Topics

► Games

► Sound & Music

► Watches & Clocks

► GPS

► Power Supplies

► Computers

► Graphics

► Thermometers

► Tools

► Tutorials

► PCB-Based Projects

By processor

AVR ATtiny

► ATtiny10

► ATtiny2313

► ATtiny84

► ATtiny841

► ATtiny85

► ATtiny861

► ATtiny88

AVR ATmega

► ATmega328

► ATmega1284

AVR 0-series and 1-series

► ATtiny3216

► ATtiny402

► ATtiny414

► ATmega4809

AVR DA/DB-series

► AVR128DA28

► AVR128DA48

► AVR128DB28

ARM

► ATSAMD21

About me

  • About me

Feeds

RSS feed

Frequency Divider Using CCL

3rd March 2021

This article describes how to use the Configurable Custom Logic (CCL) in the latest AVR microcontrollers to create a two-stage frequency divider. A test circuit based on an AVR128DA28 uses Timer/Counter TCA0 to flash an LED at 1Hz, and then uses the two-stage frequency divider to flash two more LEDs at a half and a quarter of this frequency:

FrequencyDivider.jpg

A two-stage frequency divider built from the Configurable Custom Logic on an AVR128DA28.

The frequency divider is independent of the microcontroller, so it's like having a pair of external divide-by-two logic blocks. As in this test circuit, you could use them to divide the output from a timer/counter to generate additional signals at half and a quarter of the timer/counter frequency. Alternatively you could connect them as a divide-by-four prescaler at the external clock input to one of the timer/counters, such as TCB0.

The CCL frequency divider works at frequencies up to about 90MHz, well above the 24MHz clock frequency of the AVR128DA28.

Introduction

While reading about the Configurable Custom Logic in a Microchip datasheet I began thinking that it might be possible to use the flip-flops in the CCL as a frequency divider, to prescale the frequency before connecting it to a timer/counter peripheral. Each pair of LUTs in the CCL includes one flip-flop, and two would be needed to construct a divide-by-two circuit. The parts with four LUTs would be able to provide a two-stage divide by 4 prescaler, and the parts with six LUTs would be able to provide three stages, or divide by 8.

The following table shows the number of LUTs available in all the AVR microcontrollers that include CCL, and the number of stages of prescaler you could in theory create:

Part LUTs Stages Divisor
ATtiny 0-series 2 1 2
ATtiny 1-series 2 1 2
ATmega 0-series 4 2 4
AVR DA-series 28/32 pin 4 2 4
AVR DA-series 48/64 pin 6 3 8
AVR DB-series 28/32 pin 4 2 4
AVR DB-series 48/64 pin 6 3 8

To test out the idea I decided to use an AV128DA28 because it would allow me to construct two dividers, and it's available in a PDIP package so it would be easy to prototype on a breadboard.

Here's the configuration of the Configurable Custom Logic in the AV128DA28:

FrequencyDivider.gif

The two dividers are independent, but you can connect them together to make a two stage divider by linking PA3 and PD2 externally.

Each stage is the same:

  • The sequencer is configured as a D-type flip/flop (DFF).
  • The even-numbered LUT, 0 or 2, is configured as an inverter which feeds the Q output of the D-type flip/flop, inverted, back to the D input. Its truth table is 0b01010101.
  • The input signal is connected to IN2 which clocks the D-type flip/flop.
  • The odd-numbered LUT, 1 or 3, is configured to output a constant '1' to keep the G input high. Its truth table is 0b11111111.

It turned out to work perfectly, and I was able to clock the dividers at up to 90MHz, well above the 24MHz maximum clock frequency of the AVR128DA28.

Thanks to the AVRFreaks members who discussed this idea with me when I proposed it on the forum, and in particular CmdrZin who suggested the solution.

The circuit

Here's the circuit to demonstrate the frequency divider:

CCLFrequencyDivider.gif

Circuit to demonstrate the two-stage frequency divider built from Configurable Custom Logic on an AVR128DA28.

The demo program toggles the output PA0 once a second. This is then connected to the input PA2 of the first of the dividers. The output of this divider PA3 is connected to the input of the second divider, PD2, and the final output is at PD3. The three outputs PA0, PA3, and PD3 are connected to LEDs so you can see the effect of the dividers.

The program

Here's the program to set up the CCL to create the two dividers:

void CCLSetup () {
  // Set up Configurable Custom Logic LUT0 and LUT1
  CCL.LUT0CTRLA = CCL_CLKSRC_IN2_gc;                 // Flip-Flop clocked by IN2
  CCL.LUT0CTRLB = CCL_INSEL0_FEEDBACK_gc;            // Feed Flip-Flop output to IN0
  CCL.LUT0CTRLC = CCL_INSEL2_IN2_gc;                 // Input IN2 from pin PA2

  // Sequential logic 0
  CCL.SEQCTRL0 = CCL_SEQSEL_DFF_gc;                  // Use D-type Flip-Flop
  
  // Truth tables
  CCL.TRUTH0 = 0b01010101;                           // Truth table for LUT0
  CCL.TRUTH1 = 0b11111111;                           // Truth table for LUT1

  // Exactly the same for LUT2 and LUT3
  CCL.LUT2CTRLA = CCL_CLKSRC_IN2_gc;                 // Flip-Flop clocked by IN2
  CCL.LUT2CTRLB = CCL_INSEL2_FEEDBACK_gc;            // Feed Flip-Flop output to IN0
  CCL.LUT2CTRLC = CCL_INSEL2_IN2_gc;                 // Input IN2 from pin PA2

  // Sequential logic 1
  CCL.SEQCTRL1 = CCL_SEQSEL_DFF_gc;                  // Use D-type Flip-Flop

  // Truth tables
  CCL.TRUTH2 = 0b01010101;                           // Truth table for LUT2
  CCL.TRUTH3 = 0b11111111;                           // Truth table for LUT3

  // Now enable everything
  CCL.LUT0CTRLA |= CCL_ENABLE_bm | CCL_OUTEN_bm;     // LUT0 and output to PA3
  CCL.LUT1CTRLA |= CCL_ENABLE_bm;                    // LUT1 enabled

  CCL.LUT2CTRLA |= CCL_ENABLE_bm | CCL_OUTEN_bm;     // LUT2 and output to PD3
  CCL.LUT3CTRLA |= CCL_ENABLE_bm;                    // LUT3 enabled

  CCL.CTRLA = CCL_ENABLE_bm;                         // Enable CCL
}

For the demonstration program I configured the 16-bit Timer/Counter TCA0 to toggle the output WO0, which is pin PA0. The 16MHz clock frequency is divided by 1024, and then the counter counts up until there is a compare match with 15624 in the compare match register CMP0. This toggles the output once a second.

void TCA0Setup () {
  PORTMUX.TCAROUTEA = PORTMUX_TCA0_PORTA_gc;         // WO outputs on PORTA
  PORTA.DIRSET = PIN0_bm;                            // Make WO0 an output
  TCA0.SINGLE.CTRLD = 0;                             // Single mode
  // Set Frequency mode:
  TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_WGMODE_FRQ_gc;     
  TCA0.SINGLE.CMP0 = 15624;                          // Set period 0.5 Hz
  // Prescale 1024 and enable:
  TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1024_gc | TCA_SINGLE_ENABLE_bm; 
}

Compiling the program

Compile the programs using Spence Konde's Dx Core on GitHub. Choose the AVR DA-series (no bootloader) option under the DxCore heading on the Board menu. Check that the subsequent options are set as follows (ignore any other options):

Chip: "AVR128DA28"
Clock Speed: "16 MHz internal"

Then upload the program to the AVR128DA28 using a UPDI programmer. The DxCore now supports the following two options:

  • Make a UPDI programmer from an Arduino Uno, or other ATmega328P-based board, as described in Make UPDI Programmer, and set the Programmer option to "jtag2updi".
  • Use a USB to Serial board, such as the SparkFun FTDI Basic board [1], connect TX to the UPDI pin via a 4.7kΩ resistor, connect RX directly to the UPDI pin, and set the Programmer option to "Serial port and 4.7k (pyupdi style)".

You can ignore the error "Cannot locate flash and boot memories in description".

You can also run the program on an AVR128DB28 by changing the two occurrences of CCL_SEQSEL_DFF_gc to CCL_SEQSEL1_DFF_gc (don't ask me why!).

Here's the whole CCL Frequency Divider program: Frequency Divider Program.


  1. ^ SparkFun FTDI Basic Breakout - 5V on Sparkfun.

blog comments powered by Disqus