Hello , I was able to run timer interrupts on Every board, but the results are strange. The interrupt seems little lumpy. I guess I have mistake somewhere, please help.
Both timers TCA0 and TCB2 behave the same way. The period must be around 1ms and a1000 of them gives 1 second. I print millis() for comparison, here are the results:
```cpp
// timer options
// The 4809 has one A timer (TCA) and four B timers (TCB).
// TCA and TCB3 are used by the arduino core to generate the clock used by millis() and micros().
// TCB0 generates the PWM timing for pin D6, TCB1 for pin D3.
// https://github.com/Kees-van-der-Oord/Arduino-Nano-Every-Timer-Controller-B/blob/master/EveryTimerB/EveryTimerB.h
//
//#include <avr/interrupt.h>
unsigned int tickA = 0;
unsigned int tickB = 0;
unsigned long lastTime;
//******************************************************************************
ISR(TCA0_OVF_vect){
TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm;
tickA++;
}
//******************************************************************************
ISR(TCB2_INT_vect){
TCB2.INTFLAGS = TCB_CAPT_bm;
tickA++;
}
//******************************************************************************
void setup_timer_A(){
//from Microchip AN TB3217
//It looks that ATMega4809 runs at 16MHz without Main Clock Prescaller and defauld is TCA_SINGLE_CLKSEL_DIV64_gc
TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm;
TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_NORMAL_gc;
TCA0.SINGLE.EVCTRL &= ~(TCA_SINGLE_CNTEI_bm);
TCA0.SINGLE.PER = 0xF9; //?ms
//TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV256_gc | TCA_SINGLE_ENABLE_bm;
TCA0.SINGLE.CTRLA |= TCA_SINGLE_ENABLE_bm;
}
//******************************************************************************
void setup_timer_B(){
// compilation from diff sources
TCB2.CCMP = 0x1F3F; // 1ms ?
TCB2.CTRLB = 0; // interrupt mode
TCB2.CTRLA = TCB_CLKSEL_CLKDIV2_gc | TCB_ENABLE_bm;
//TCB2.CTRLA = TCB_CLKSEL_CLKTCA_gc | TCB_ENABLE_bm; // use TCA 250kHz clock, but this clock is not quite periodic!!
TCB2.INTCTRL = TCB_CAPT_bm;
}
//******************************************************************************
//******************************************************************************
//******************************************************************************
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
//pinMode(LED_BUILTIN, OUTPUT);
PORTE.DIR |= PIN2_bm;
//setup_timer_A();
setup_timer_B();
//sei();
}
void loop() {
// put your main code here, to run repeatedly:
if (tickA >= 1000){
tickA = 1;
PORTE.OUTTGL = PIN2_bm;
//digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
Serial.println(millis()-lastTime);
lastTime = millis();
}
}
The tick counts are integers with high and low bytes, and you are reading changing registers. If you disable the interrupt before reading, the count is stabilized at 1000. Because tickA count is changed in the interrupt, it should be declared as volatile. While the code below gives a stable count, I would prefer to put the test for the count in the ISR and set a flag when met.
// timer options
// The 4809 has one A timer (TCA) and four B timers (TCB).
// TCA and TCB3 are used by the arduino core to generate the clock used by millis() and micros().
// TCB0 generates the PWM timing for pin D6, TCB1 for pin D3.
// https://github.com/Kees-van-der-Oord/Arduino-Nano-Every-Timer-Controller-B/blob/master/EveryTimerB/EveryTimerB.h
//
//#include <avr/interrupt.h>
volatile unsigned int tickA = 0;
volatile unsigned int tickB = 0;
unsigned long lastTime;
//******************************************************************************
ISR(TCA0_OVF_vect){
TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm;
tickA++;
}
//******************************************************************************
ISR(TCB2_INT_vect){
TCB2.INTFLAGS = TCB_CAPT_bm;
tickA++;
}
//******************************************************************************
void setup_timer_A(){
//from Microchip AN TB3217
//It looks that ATMega4809 runs at 16MHz without Main Clock Prescaller and defauld is TCA_SINGLE_CLKSEL_DIV64_gc
TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm;
TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_NORMAL_gc;
TCA0.SINGLE.EVCTRL &= ~(TCA_SINGLE_CNTEI_bm);
TCA0.SINGLE.PER = 0xF9; //?ms
//TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV256_gc | TCA_SINGLE_ENABLE_bm;
TCA0.SINGLE.CTRLA |= TCA_SINGLE_ENABLE_bm;
}
//******************************************************************************
void setup_timer_B(){
// compilation from diff sources
TCB2.CCMP = 0x1F3F; // 1ms ?
TCB2.CTRLB = 0; // interrupt mode
TCB2.CTRLA = TCB_CLKSEL_CLKDIV2_gc | TCB_ENABLE_bm;
//TCB2.CTRLA = TCB_CLKSEL_CLKTCA_gc | TCB_ENABLE_bm; // use TCA 250kHz clock, but this clock is not quite periodic!!
TCB2.INTCTRL = TCB_CAPT_bm;
}
//******************************************************************************
//******************************************************************************
//******************************************************************************
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
//pinMode(LED_BUILTIN, OUTPUT);
PORTE.DIR |= PIN2_bm;
//setup_timer_A();
setup_timer_B();
//sei();
}
void loop() {
// put your main code here, to run repeatedly:
TCB2.INTCTRL &= !TCB_CAPT_bm; //stop interrupt
if (tickA >= 1000){
tickA = 1;
PORTE.OUTTGL = PIN2_bm;
//digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
Serial.println(millis()-lastTime);
lastTime = millis();
}
TCB2.INTCTRL = TCB_CAPT_bm; //enable interrupt
}
Thank you cattledog, the devil is in the details. I changed the period to 5ms and using byte as a counter it works. I have used this approach many times with PIC's having 5-6 counters for different purposes including filters. But never with Arduino.
// timer options
// The 4809 has one A timer (TCA) and four B timers (TCB).
// TCA and TCB3 are used by the arduino core to generate the clock used by millis() and micros().
// TCB0 generates the PWM timing for pin D6, TCB1 for pin D3.
// https://github.com/Kees-van-der-Oord/Arduino-Nano-Every-Timer-Controller-B/blob/master/EveryTimerB/EveryTimerB.h
//
//#include <avr/interrupt.h>
volatile byte tickA = 0;
volatile unsigned int tickB = 0;
unsigned long lastTime;
//******************************************************************************
ISR(TCA0_OVF_vect){
TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm;
tickA++;
}
//******************************************************************************
ISR(TCB2_INT_vect){
TCB2.INTFLAGS = TCB_CAPT_bm;
tickA++;
}
//******************************************************************************
void setup_timer_A(){
//from Microchip AN TB3217
//It looks that ATMega4809 runs at 16MHz without Main Clock Prescaller and defauld is TCA_SINGLE_CLKSEL_DIV64_gc
TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm;
TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_NORMAL_gc;
TCA0.SINGLE.EVCTRL &= ~(TCA_SINGLE_CNTEI_bm);
TCA0.SINGLE.PER = 0xF9; //?ms
//TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV256_gc | TCA_SINGLE_ENABLE_bm;
TCA0.SINGLE.CTRLA |= TCA_SINGLE_ENABLE_bm;
}
//******************************************************************************
void setup_timer_B(){
// compilation from diff sources
TCB2.CCMP = 0x9C3F; // 5ms, 0x1F3F; // 1ms
TCB2.CTRLB = 0; // interrupt mode
TCB2.CTRLA = TCB_CLKSEL_CLKDIV2_gc | TCB_ENABLE_bm;
//TCB2.CTRLA = TCB_CLKSEL_CLKTCA_gc | TCB_ENABLE_bm; // use TCA 250kHz clock
TCB2.INTCTRL = TCB_CAPT_bm;
}
//******************************************************************************
//******************************************************************************
//******************************************************************************
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
//pinMode(LED_BUILTIN, OUTPUT);
PORTE.DIR |= PIN2_bm;
//setup_timer_A();
setup_timer_B();
//sei();
}
void loop() {
// put your main code here, to run repeatedly:
// It works if tick is byte.
//TCB2.INTCTRL &= !TCB_CAPT_bm; //stop interrupt
if (tickA > 200){
//Serial.println(tickA);
tickA = 1;
Serial.println(millis()-lastTime);
//digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
lastTime = millis();
PORTE.OUTTGL = PIN2_bm;
}
//TCB2.INTCTRL = TCB_CAPT_bm; //start interrupt
}
Better code using loop synchronisation with the timer. Tick counters can be any size:
// Arduino Every timer TCB as system 1 ms clock.
// If the loop is asyncrhonius it works if tick counter in the ISR is a byte.
// If the loop is synchronized with the timer, the counter of any size is in the loop.
volatile unsigned int tickB = 0;
volatile byte tickA = 0; // unsigned char
volatile byte flag = 0;
unsigned long lastTime;
//******************************************************************************
ISR(TCB2_INT_vect){
TCB2.INTFLAGS = TCB_CAPT_bm;
flag = 1;
tickA++;
//tickB++;
}
//******************************************************************************
void setup_timer_B(){
// compilation from diff sources
//TCB2.CCMP = 0x9C3; // 10ms with TCB_CLKSEL_CLKTCA_gc
//TCB2.CCMP = 0x9C3F; // 5ms with TCB_CLKSEL_CLKDIV2_gc
TCB2.CCMP = 0x1F3F; // 1ms with TCB_CLKSEL_CLKDIV2_gc
TCB2.CTRLB = 0; // interrupt mode
TCB2.CTRLA = TCB_CLKSEL_CLKDIV2_gc | TCB_ENABLE_bm;
//TCB2.CTRLA = TCB_CLKSEL_CLKTCA_gc | TCB_ENABLE_bm; // use TCA 250kHz clock
TCB2.INTCTRL = TCB_CAPT_bm;
}
//******************************************************************************
//******************************************************************************
//******************************************************************************
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
//pinMode(LED_BUILTIN, OUTPUT);
PORTE.DIR |= PIN2_bm; // better go HW
setup_timer_B();
//sei();
}
void loop() {
// put your main code here, to run repeatedly:
while(flag == 0){
// synchronize the loop with the timer
}
flag = 0; // run once
tickB++; // many as we want counters here
if (tickB > 1000){
tickB = 1;
Serial.println(millis()-lastTime);
//digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
lastTime = millis();
PORTE.OUTTGL = PIN2_bm;
}
}