-
Notifications
You must be signed in to change notification settings - Fork 158
Description
Hello there. I am trying to port some code from an Attiny45 over to an Attiny412.
The code on the Attiny45 made use of an "Output Compare Match Interrupt" with TCNT0 registers and that's quite well documented on how it works and how to use it.
I haven't found such a clear documentation for such a use on the new Attiny series unfortunately, so I am asking for some help here.
In order to better understand these "new" registers I am trying to build a very basic example:
An ISR function is toggling an LED between On/Off periodically. I want to be able to determine and manipulate its rate (period, timing).
Right now, after looking at various documentation and places I laded onto the following code:
#define TCB_TIMEOUT_VALUE 0xffff
void CLOCK_init (void){
//Mandatory unlock prescaler protection
CCP = CCP_IOREG_gc;
//Setting TCB Clock Prescaler
CLKCTRL_MCLKCTRLB = CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm;
CLKCTRL_MCLKCTRLA = CLKCTRL_CLKSEL_OSCULP32K_gc;
/* Wait for system oscillator changing to finish */
while (CLKCTRL_MCLKSTATUS & CLKCTRL_SOSC_bm)
{
;
}
}
void PORT_init (void){
// Setting PIN6 as Output and initializing it HIGH
PORTA_DIR = 0b01000000;
PORTA_OUT = 0b01000000;
}
void TCB0_init (void){
/* Load the Compare or Capture register with the timeout value*/
TCB0_CCMP = TCB_TIMEOUT_VALUE;
/* Enable TCB and set CLK_PER divider to 1 (No Prescaling) */
TCB0_CTRLA = TCB_CLKSEL_CLKDIV2_gc | TCB_ENABLE_bm;
/* Enable Capture or Timeout interrupt */
TCB0_INTCTRL = TCB_CAPT_bm;
}
ISR(TCB0_INT_vect)
{
TCB0_INTFLAGS = TCB_CAPT_bm; /* Clear the interrupt flag */
PORTA_OUT ^= (1 << PIN6_bp); //XOR (exclusive OR) to toggle the LED state
}
int main(void)
{
CLOCK_init();
PORT_init();
TCB0_init();
//Enable Global Interrupts
sei();
while (1)
{
;
}
}
With the above code I get an LED rate which seems to be around 400ms. Although I'm not getting why! I would like to understand how to manipulate these registers to get precisely to a desired timing (for example, 10ms).
A few things I noticed:
• Decreasing the TCB_TIMEOUT_VALUE obviously decreases the time interval at which the ISR gets called;
• Assigning a smaller Prescaler at CLKCTRL_MCLKCTRLB = CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm decreases the time interval;
• The following instruction seems to do nothing: CLKCTRL_MCLKCTRLA = CLKCTRL_CLKSEL_OSCULP32K_gc;
• Using an advised datasheet assignation to get into Periodic Timeout Mode makes the code not work at all anymore: TCB0_CTRLB = TCB_CNTMODE_TIMEOUT_gc;
• Flashing with a lower clock speed (20Mhz is the Default one, I tried decreasing to any sort of value to slow the rate of the LED) doesn't affect the LED timing at all!
• With this instruction I have three clock options, but I don't understand what they really do.
TCB0_CTRLA = TCB_CLKSEL_CLKDIV1_gc | TCB_ENABLE_bm; --> Seems to give no extra CLK "division"
TCB0_CTRLA = TCB_CLKSEL_CLKDIV2_gc | TCB_ENABLE_bm; --> Seems to halve the CLK, so slows it down by a factor of 2
TCB0_CTRLA = TCB_CLKSEL_CLKTCA | TCB_ENABLE_bm; ---> Should get the CLK from the TCA Timer, but I am not able to make this work in any sort of way.
- Important side note*
I would like to understand what is the criteria to preserve correctly the millis(), micros() and delay() functions if I am changing the Timers.
Thank you guys in advance!