How to get 8MHz on a GPIO of a Nano Every

Hi folks!

With an Arduino Nano it is possible to get a 8 MHz clock signal on pin 9:

void setup ()
  {
  // set up 8 MHz timer on pin 9 (OC1A)
  pinMode (9, OUTPUT); 
  // set up Timer 1
  TCCR1A = bit (COM1A0);  // toggle OC1A on Compare Match
  TCCR1B = bit (WGM12) | bit (CS10);   // CTC, no prescaling
  OCR1A =  0;       // output every cycle
  }  // end of setup

void loop ()
  {
  // whatever 
  }  // end of loop

I am trying to achieve the same thing on a Nano Every. I have adjusted the PWM example in “getting started with TCB” and so far, I have succeeded in getting 4 MHz (see code below). I am quite proud since I am a beginner and I have just started to learn about timers, registers, ports, prescalers, etc.

Is using TCB in PWM mode the way to go or is there a better way? Is it possible to get a higher frequency out of it? I don’t want to mess with the millis() function, I think I should use TCB1 or TCB0?

#include <avr/io.h>
#define TCB_CMP_EXAMPLE_VALUE (0x0101)        // I adjusted this value to get the highest possible PWM frequency     

void CLOCK_init (void);
void PORT_init (void);
void TCB3_init (void);

void CLOCK_init (void)  {
  CPU_CCP = CCP_IOREG_gc;                                    /* Enable writing to protected register */
  CLKCTRL.MCLKCTRLB = CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm;           // I used 2X prescaler in stead of 64
  CPU_CCP = CCP_IOREG_gc;                                    /* Enable writing to protected register */
  CLKCTRL.MCLKCTRLA = CLKCTRL_CLKSEL_OSC20M_gc;                      // I Selected OSC20M in stead of OSCULP32K 
  while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm)               /* Wait for system oscillator changing to finish */
  { ; }
}

void PORT_init (void)  {
 PORTB_DIR |= PIN5_bm;
 PORTB_OUT |= PIN5_bm;
}

void TCB3_init (void)  {
  TCB3.CCMP = TCB_CMP_EXAMPLE_VALUE;       /* Load CCMP register with the period and duty cycle of the PWM */
  TCB3.CTRLA |= TCB_ENABLE_bm;             /* Enable TCB3 and Divide CLK_PER by 2 */
//  TCB3.CTRLA |= TCB_CLKSEL_CLKDIV2_gc;       // I removed this line as it slows things down

  TCB3.CTRLB |= TCB_CCMPEN_bm;             /* Enable Pin Output and configure TCB in 8-bit PWM mode */
  TCB3.CTRLB |= TCB_CNTMODE_PWM8_gc;
}

int main(void)  {
  CLOCK_init();
  PORT_init();
  TCB3_init();

 while(1) {}
}

Thanks for any tips.

Hi,

with the ATmega4809 TCB is actually not the right timer for something like this. You can use the 8Bit PWM or maybe the TimeOut mode. Furthermore every TCBn has a specific WO pin. You can’t just mix them. For that you need the manual.
The Nano Every Board has the following pinout.

/*
  Arduino Nano Every PinOut (ATmega4809)
                  _
               __|_|__    
              |       |  
  (D13)  PE2  +       +  PE1  (D12)  
        3.3V  +       +  PE0  (D11)  
  (AREF) PD7  +       +  PB1  (D10)(~)(TCA0 Channel 1)
  (D14)  PD3  +       +  PB0  (D 9)(~)(TCA0 Channel 0)
  (D15)  PD2  +       +  PE3  (D 8)
  (D16)  PD1  +       +  PA1  (D 7) 
  (D17)  PD0  +       +  PF4  (D 6)(~)(TCB0)
  (D18)  PF2  +       +  PB2  (D 5)(~)(TCA0 Channel 2)
  (D19)  PF3  +       +  PC6  (D 4)  
  (D20)  PD4  +       +  PF5  (D 3)(~)(TCB1)  
  (D21)  PD5  +       +  PA0  (D 2) 
        5.0V  +       +  GND
       RESET  +       +  RESET
         GND  +       +  PC5  (D 0) RX1
         VIN  +       +  PC4  (D 1) TX1      
              |_______|  
*/

TCB3 would have as WO pin PB5 or PC1. Both are not led out on the Nano Every board.
TCB2 would have pin PC0 or PB4 as WO. Both are not led out on the Nano Every Board.
TCB1 has pin PA3 or PF5 as WO. PF5 is led out on the Nano Every Board.
TCB0 has pin PA2 or PF4 as WO. PF4 is led out on the Nano Every Board.

We take TCB0 with WO PF4. This is Arduino pin 6. The WO portmux is not affected by the timer registers. That is done in another register. The 16 bit compare register splits into MSB and LSB 8bit.
MSB is the pulse width.
LSB is the frequency.
The setting 1 + 1 → 0x0101 produces the highest possible frequency with Duty Cycle 50% with 8MHz.

For me it looks like this.

/*
  Doc_Arduino - german Arduino Forum
  Arduino IDE v1.8.13
  Arduino Nano Every
  13.04.2021
  TCBn as 8 Bit PWM
  License: GNU GPLv3
*/

#include <NanoEveryPin.h>
#include <megaAVR0TCBn.h>

OutputPin <6> pinPWM; // PF4
TCB <0> timerTCB0;

void setup (void)
{                     
  initPins();
  initTCB0();
}

void loop (void)
{
  
}

void initPins (void)
{ 
  pinPWM.init();
}

void initTCB0 (void)
{
  timerTCB0.reset();
  timerTCB0.setCLKDIV1();
  timerTCB0.setModePWM8();
  timerTCB0.enableCCMPEN();
  timerTCB0.setCompare(0x0101); // MSB Duty Cycle / LSB Periode
  timerTCB0.enable();
}

libraries.zip (115,7 KB)

1 Like

Hi Doc_Arduino,

Thank you for your reply. I was not able to login to the new forum because something was wrong with my account. It is finally solved now.

I took a look at your libraries, they look quite impressive. However, I can not find any C-files so I could not see exactly how you do it. In the mean time I found some code to get a 8 MHz clock signal on pin D3 using TCB1 and PWM:

  PORTMUX.TCBROUTEA |= PORTMUX_TCB1_bm;
  TCB1.CCMPL = 1;   /* PWM Period*/
  TCB1.CCMPH = 1;   /* PWM Compare*/

  TCB1.CTRLB = 0 << TCB_ASYNC_bp        /* Asynchronous Enable: disabled */
               | 1 << TCB_CCMPEN_bp     /* Pin Output Enable: enabled */
               | TCB_CNTMODE_PWM8_gc;   /* 8-bit PWM */
 
  TCB1.CTRLA = TCB_CLKSEL_CLKDIV1_gc;   /* CLK_PER (No Prescaling)      */ 
  TCB1.CTRLA |= TCB_ENABLE_bm;

Thanks again.

Hi,

my lib is header only because of the class template. There is no .c file because of that. If something would be missing you could not compile the sketch. The bit definitions are the standard definitions from Microchip. They are always present for the controller. Search on your computer for a file named iom4809.h

The pinout as shown in #2 is Arduino standard. As long as you don't change anything in the portmux register it will stay like this. However, if you are programming bare metal, then you need to set it.

The same result would have been as follows. Everything remains basically as it is. Only the timer number at initialization changes from 0 to 1. The names are adjusted additionally. And of course change the output pin from D6 to D3.

#include <NanoEveryPin.h>
#include <megaAVR0TCBn.h>

OutputPin <3> pinPWM; // PF5
TCB <1> timerTCB1;

void setup (void)
{                     
  initPins();
  initTCB1();
}

void loop (void)
{
  
}

void initPins (void)
{ 
  pinPWM.init();
}

void initTCB1 (void)
{
  timerTCB1.reset();
  timerTCB1.setCLKDIV1();
  timerTCB1.setModePWM8();
  timerTCB1.enableCCMPEN();
  timerTCB1.setCompare(0x0101); // MSB Duty Cycle / LSB Periode
  timerTCB1.enable();
}

You don't have to take my lib if you can do better without. There is no compulsion. :stuck_out_tongue_winking_eye:

Here is how to get 8MHz on pin A5 without using any timer counters at all! Instead you use the Configurable Custom Logic feature of the ATmega4809 microcontroller. CCL allows some simple gated registers to be generated on chip. In this case we create a type D flip-flop, ~Q connected to D and clocked by the system (16MHz clock).

void setup() {
  // LUT0 is the D input, which is connected to the flipflop output
  CCL.LUT0CTRLB = CCL_INSEL0_FEEDBACK_gc; // Input from sequencer
  CCL.TRUTH0 = 1; // Invert the input
  CCL.SEQCTRL0 = CCL_SEQSEL0_DFF_gc; // D flipflop
  // The following line configures using the system clock, OUTEN, and ENABLE
  CCL.LUT0CTRLA = CCL_OUTEN_bm | CCL_ENABLE_bm;
  // LUT1 is the D flipflop G input, which is always high
  CCL.TRUTH1 = 0xff; 
  CCL.LUT1CTRLA = CCL_ENABLE_bm; // Turn on LUT1
  CCL.CTRLA = 1; // Enable the CCL
}

void loop() {
}
2 Likes

Hi,

That's how it works, of course. He should simply work through the app notes.
Getting Started is very helpful for the beginning.

ATmega4809 Manuals >> Documents ...

@Doc_Arduino: I had been staring for quite some time over those "getting started" files, but for a beginner it is not that simple. Your link works, but many of the links on your link don't. For instance, the CCL link does not work...

@almytom: Thanks, that is good to know. But for my current project, I need my 8MHz pulse to be on pin D3. I assume that it is not possible to get it on D3 with that CCL method?

Sorry, the CCL would put it on A5 or A0. The Event System would allow routing the CCL output to A4, D5, A1, or D13. That's six pins, but unfortunately D3 is not among them. Why must D3 be used?

Hi,

I can imagine that it slays you with all the information at first. But the Getting Started Manuals help, because they focus only on one specific feature.
All links work for me.
You go to the documents tab on the Microship page. Here you can see the many .pdf manuals. Then you click on the first app note "... with CCL". Land on the next page, move your mouse to the right and click on the .pdf icon next to Size. Either that opens in the browser or you download it.

If the links really don't work for you, for whatever reason, you can go directly to Github if necessary. GitHub App Notes

Revised table for faster overview. The formatting is not 100% correct.

  Prepared to the best of our knowledge and belief.  :-)
  Without warranty.
  Doc_Arduino - in the german section of the forum

  Arduino Nano Every PinOut (ATmega4809)
                      _
                   __|_|__    
                  |       |  
      (D13)  PE2  +       +  PE1  (D12)  
            3.3V  +       +  PE0  (D11)  
      (AREF) PD7  +       +  PB1  (D10)(~)(TCA0 Channel 1)
  (A0)(D14)  PD3  +       +  PB0  (D 9)(~)(TCA0 Channel 0)
  (A1)(D15)  PD2  +       +  PE3  (D 8)
  (A2)(D16)  PD1  +       +  PA1  (D 7) 
  (A3)(D17)  PD0  +       +  PF4  (D 6)(~)(TCB0)
  (A4)(D18)  PF2  +       +  PB2  (D 5)(~)(TCA0 Channel 2)
  (A5)(D19)  PF3  +       +  PC6  (D 4)  
  (A6)(D20)  PD4  +       +  PF5  (D 3)(~)(TCB1)  
  (A7)(D21)  PD5  +       +  PA0  (D 2) 
            5.0V  +       +  GND
           RESET  +       +  RESET
             GND  +       +  PC5  (D 0) RX1
             VIN  +       +  PC4  (D 1) TX1      
                  |_______|  

//----------------------------------------------------------------------------------------------------------------------------------------------

 With 'default' in the table the view from the µC is meant. Not the one of the Arduino framework. 
 If you don't change anything at the portmux registers, the setting according to the board label above is valid.

 Ardu      |    Event       |      CCL-LUTn     |       TCA0        |       TCBn        |
  Pin Port | Port | Channel | default | PortMux | default | PortMux | default | PortMux |
   0  PC5  |  0     2 or 3  |   ---       ---   |   ---      0-WO5  |   ---       ---   |
   1  PC4  |  0     2 or 3  |   ---       ---   |   ---      0-WO4  |   ---       ---   |
   2  PA0  |  0     0 or 1  |  0-IN0      ---   |  0-WO0      ---   |   ---       ---   |
   3  PF5  |  1     4 or 5  |   ---       ---   |   ---      0-WO5  |   ---      1-WO   |
   4  PC6  |  0     2 or 3  |   ---      1-OUT  |   ---       ---   |   ---       ---   |
   5  PB2  |  1     0 or 1  |   ---       ---   |   ---      0-WO2  |   ---       ---   |
   6  PF4  |  1     4 or 5  |   ---       ---   |   ---      0-WO4  |   ---      0-WO   |
   7  PA1  |  0     0 or 1  |  0-IN1      ---   |  0-WO1      ---   |   ---       ---   |
   8  PE3  |  0     4 or 5  |   ---       ---   |   ---      0-WO3  |   ---       ---   |
   9  PB0  |  1     0 or 1  |   ---       ---   |   ---      0-WO0  |   ---       ---   |
  10  PB1  |  1     0 or 1  |   ---       ---   |   ---      0-WO1  |   ---       ---   |
  11  PE0  |  0     4 or 5  |   ---       ---   |   ---      0-WO0  |   ---       ---   |
  12  PE1  |  0     4 or 5  |   ---       ---   |   ---      0-WO1  |   ---       ---   |
  13  PE2  |  0     4 or 5  |   ---       ---   |   ---      0-WO2  |   ---       ---   |
  14  PD3  |  1     2 or 3  |  2-OUT      ---   |   ---      0-WO3  |   ---       ---   |
  15  PD2  |  1     2 or 3  |  2-IN2      ---   |   ---      0-WO2  |   ---       ---   |
  16  PD1  |  1     2 or 3  |  2-IN1      ---   |   ---      0-WO1  |   ---       ---   |
  17  PD0  |  1     2 or 3  |  2-IN0      ---   |   ---      0-WO0  |   ---       ---   | 
  18  PF2  |  1     4 or 5  |  3-IN2      ---   |   ---      0-WO2  |   ---       ---   |  board internal double assignment with PA2 observe !!!
  19  PF3  |  1     4 or 5  |  3-OUT      ---   |   ---      0-WO3  |   ---       ---   |  board internal double assignment with PA3 observe !!!
  20  PD4  |  1     2 or 3  |   ---       ---   |   ---      0-WO4  |   ---       ---   |
  21  PD5  |  1     2 or 3  |   ---       ---   |   ---      0-WO5  |   ---       ---   |

//----------------------------------------------------------------------------------------------------------------------------------------------

 On the board to the outside are not wired:
 !!! double occupancy Arduino pin 18 and 19 observe !!!

           |    Event       |      CCL-LUTn     |
  Pin Port | Port | Channel | default | PortMux |
  18  PA2  |                |  0-IN2      ---	  |  PF2 !!! 
  19  PA3  |                |  0-OUT      ---	  |  PF3 !!!		
      PA4  |                |   ---       ---	  | 
      PA5  |                |   ---       ---	  |  
      PA6  |                |   ---      0-OUT  | 
      PA7  |                |   ---       ---	  |  
      PB3  |                |   ---       ---	  |  
      PC0  |                |  1-IN0      ---	  |
      PC1  |                |  1-IN1      ---	  |  
      PC2  |                |  1-IN2      ---	  |  
      PC3  |                |  1-OUT      ---	  |  
      PC7  |                |   ---       ---	  |  
      PD6  |                |   ---      2-OUT  |    
      PF0  |                |  3-IN0      ---	  |    
      PF1  |                |  3-IN1      ---	  |    


  

Pinout-Tabelle extended.txt.h (4,7 KB)
rename to .txt

@Doc_Arduino OK, from the documents tab, the links work.

@almytom I need it on D3 because the hardware is largely finished. I started this project on an Arduino Nano v3, but my program is becoming too big (too many global variables) so I want to change to a Nano Every which has more SRAM.

But like I said, I managed to get a 8MHz pulse on D3, so my problem is solved.

Thanks again,

Willem