I am using an ATtiny 402 to implement a timer interrupt. The internal clock I have selected is 20Mhz. Prescaler is not enabled. For timer interrupt, I am using timer 0 in normal mode. The PA6 is used as an output to see the Interrupt time period by an oscilloscope.
And for the experiment, I used the TOP value of 30000.
In the current configuration, the Timer interrupt time should be = TOP * (Pre / Clk) = 30000 * ( 1 / 20000000) s = 1.5 ms
But in the oscilloscope, the interrupt period time is: 8.8 ms
Am is miscalculating something or is there any mistake in my code.
My source code is :
#include <avr/io.h>
#include <avr/interrupt.h>
FUSES = {
.WDTCFG = 0x00, // WDTCFG {PERIOD=OFF, WINDOW=OFF}
.BODCFG = 0x00, // BODCFG {SLEEP=DIS, ACTIVE=DIS, SAMPFREQ=1KHz, LVL=BODLEVEL0}
.OSCCFG = 0x02, // OSCCFG {FREQSEL=20MHZ, OSCLOCK=CLEAR}
.TCD0CFG = 0x00, // TCD0CFG {CMPA=CLEAR, CMPB=CLEAR, CMPC=CLEAR, CMPD=CLEAR, CMPAEN=CLEAR, CMPBEN=CLEAR, CMPCEN=CLEAR, CMPDEN=CLEAR}
.SYSCFG0 = 0xC4, // SYSCFG0 {EESAVE=CLEAR, RSTPINCFG=UPDI, CRCSRC=NOCRC}
.SYSCFG1 = 0x07, // SYSCFG1 {SUT=64MS}
.APPEND = 0x00, // APPEND {APPEND=User range: 0x0 - 0xFF}
.BOOTEND = 0x00, // BOOTEND {BOOTEND=User range: 0x0 - 0xFF}
};
LOCKBITS = 0xC5; // {LB=NOLOCK}
void io_set(void){
PORTA.DIR = 0b01000000 ; // pin PA1 input others output
PORTA.PIN1CTRL = 0b0001000 ; // pullup PA1
}
void clk_conf(void){
CLKCTRL.MCLKCTRLA = 0b00000000 ; // internal clock 20 Mhz ////
CLKCTRL.MCLKCTRLB = 0b00000000 ; // Prescaler is not enabled /////
}
void timer0_init(){
TCA0.SINGLE.CTRLA = 0b00000001 ;// // Peripheral enable, clock = CLOCK_PER
TCA0.SINGLE.CTRLB = 0b00000000 ;// // Timer in normal mode
TCA0.SINGLE.PER = 30000; ////// Setting the Top value to 30000
TCA0.SINGLE.INTCTRL = 0b00000001; //
}
void en_global_int(){
SREG |= 0b10000000 ; //enable global interrupt
}
int main(void)
{
clk_conf() ;
io_set() ;
en_global_int() ;
timer0_init() ;
sei() ;
while (1){
}
}
ISR(TCA0_OVF_vect){
TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm; //clearing the flag
TCA0.SINGLE.CNT = 0 ; //counter set to zero
PORTA.OUT ^= 0b01000000 ; //toggling the output pin
}
CodePudding user response:
By default after reset, the CLOCK_MAIN is set to 20MHz and CLOCK_PER is set to 20/6=3.33333MHz with a prescaler of 6, that's exactly what you are using.
The reason your attempt of setting the main clock prescaler didn't work is because system critical I/O register settings are protected from accidental modification by Configuration Change Protection (CCP). Read section 10 of Attiny202/402 datasheet and section 8.5.7 about CCP, and then section 3.5 on how to write to CCP on Getting Started with Writing C-Code for AVR® MCUs.
CodePudding user response:
In a project (with ATTiny406) i had the same problems. I solved it with a few lines:
// CLOCK Setup
CCP = CCP_IOREG_gc;
CLKCTRL.MCLKCTRLA = CLKCTRL_CLKSEL_OSC20M_gc;
while(!(CLKCTRL.MCLKSTATUS & CLKCTRL_OSC20MS_bm));
CCP = CCP_IOREG_gc;
CLKCTRL.MCLKCTRLB = 0x00;
CLKCTRL.OSC20MCTRLA = CLKCTRL_RUNSTDBY_bm;
Maybe this helps...