Timer Questions

Hello,

can someone explain to me how the Arduino Core uses the timers?

I think I have found out that the timers are used as follows.
analogWrite:
TCA0 Pin 5 PB2
TCA0 Pin 9 PB0
TCA0 Pin 10 PB1
TCB0 Pin 6 PF4
TCB1 Pin 3 PF5

TCA0 clocks at 250kHz with Prescaler 64.
TBCn clocks synchronously to TCA0.

Is this correct so far?

millis uses the next free TCBn, which is quite confusing.
If I now use all 5 analog pins, millis should use TCB2. Is that correct?
According to this TCB3 should be free.
Why does millis not use TCB2 permanently?

Now comes my problem.
I can change the prescaler from TCB3 to 1 or TCA0.
Everything still works.
But if I change the TCB3 prescaler to 2, the loop stops.
With TCB2 the same problem.
Why does the loop stop?

If I set the prescaler from TCB0 to 2, pin 6 stops analogously. Why is that?
Shouldn’t only its frequency change here?

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

#include <util/atomic.h>
#include <avr/interrupt.h>

volatile unsigned int countTCB3;
bool state {false};

void setup(void)
{
  Serial.begin(115200);
  Serial.println("\nSTART");
  pinMode(LED_BUILTIN, OUTPUT);
  analogWrite(3, 127);
  analogWrite(5, 127);
  analogWrite(6, 127);
  analogWrite(9, 127);
  analogWrite(10, 127);
  
  configTCB3();
}

void loop(void)
{
  state = !state;
  digitalWrite(LED_BUILTIN, state);
  delay(50);
  ATOMIC_BLOCK (ATOMIC_RESTORESTATE) {
    countTCB3 = TCB3.CNT;
  }
  Serial.println(countTCB3);
}

void configTCB3 (void)
{
  //TCB3.CTRLA = TCB3.CTRLA | TCB_CLKSEL_CLKDIV1_gc;     
    TCB3.CTRLA = TCB3.CTRLA | TCB_CLKSEL_CLKDIV2_gc;    // loop is stopped    
  //TCB3.CTRLA = TCB3.CTRLA | TCB_CLKSEL_CLKTCA_gc;    
}

Everything you said down to "correct so far" is correct. However the core always uses TCB3 for time tracking functions like millis(). The Arduino Servo Library uses TCB2 if used, otherwise it is free but initialized. The reason why changing the prescaler for TCB3 to 1 "works" but 2 "stops" is actually a coding error in your example. Originally the value of the CLKSEL field is 2, which uses TCA0 prescaler. When you OR TCB_CLKSEL_CLKDIV1_gc, that's a value of 0 so does nothing. However TCB_CLKSEL_CLKDIV2_gc is a value of 1, so ORing sets the field to a value of 3, which is invalid.

The same thing happens assuming you are just ORing into TCB0.CTRLA as well. All the TCBx.CTRLA are initialized to use the TCA0 prescaler.

Hello,

Coding error, correct. :o
I had completely overlooked that.
Thanks a lot.

works fine :slight_smile:

void configTCB2 (void)
{
  TCB2.CTRLA = TCB2.CTRLA & ~(0x03 << 1);  // delete CLKSEL Bits   

  //TCB2.CTRLA = TCB2.CTRLA | TCB_CLKSEL_CLKDIV1_gc;     
  TCB2.CTRLA = TCB2.CTRLA | TCB_CLKSEL_CLKDIV2_gc;  
  //TCB2.CTRLA = TCB2.CTRLA | TCB_CLKSEL_CLKTCA_gc;    
}