Hi everyone,
I'm trying to develop an interrupt that occurs every second using Arduino nano 33 IoT timer overflow. I sketched this code that is not working; infact the time of the interrupt is not the one that I want and if I change the prescaler or the countings nothing is changing. Can you help me in finding the error?
thank you
Is there a particular reason you want to use TC3 instead of, say, the RTC?
Or an overflow interrupt instead of one of the compare channels?
You probably don't want to manipulate GCLK0, since it's probably already been set up by the Arduino core.
Here's some example code that configures the TC3 timer to call the TC3_Handler() every second. In this instance it toggles the board's built-in LED every second:
// Set timer TC3 to call the TC3_Handler at 1Hz (1 second period)
void setup() {
pinMode(LED_BUILTIN, OUTPUT); // Set the built-in LED pin to an output
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Set GCLK0 (48MHz) as clock source for timer TC3
GCLK_CLKCTRL_GEN_GCLK0 |
GCLK_CLKCTRL_ID_TCC2_TC3;
TC3->COUNT16.CTRLA.reg = TC_CTRLA_WAVEGEN_MFRQ | // Put the timer TC3 into match frequency (MFRQ) mode
TC_CTRLA_PRESCALER_DIV1024 | // Divide the clock by 1024
TC_CTRLA_PRESCSYNC_PRESC; // Reset timer on the next prescaler pulse (not GCLK)
TC3->COUNT16.CC[0].reg = 46874; // Set the TC3 period to 1Hz: 48MHz / (1024 * 1Hz) - 1 = 46874
while (TC3->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization
NVIC_SetPriority(TC3_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC3 to 0 (highest)
NVIC_EnableIRQ(TC3_IRQn); // Connect TC3 to Nested Vector Interrupt Controller (NVIC)
TC3->COUNT16.INTENSET.reg = TC_INTENSET_OVF; // Enable TC3 overflow interrupts
TC3->COUNT16.CTRLA.bit.ENABLE = 1; // Enable TC3
while (TC3->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization
}
void loop() {}
void TC3_Handler() // Interrupt Service Routine (ISR) for timer TC3
{
static bool toggle = true; // Define the toggle variable
if (TC3->COUNT16.INTFLAG.bit.OVF) // Check for overflow (OVF) interrupt
{
TC3->COUNT16.INTFLAG.bit.OVF = 1; // Clear the OVF interrupt flag
// Put your timer overflow (OVF) code here...
digitalWrite(LED_BUILTIN, toggle); // Toggle the built-in LED
toggle = !toggle; // Switch the toggle
}
}
I have another questions: Do you know if it is possible to read both data from analog input and data from the embedded accelerometer using the interrupt developped above? because if I try, Arduino stops working
@virginiaciveriati The issue is that the Wire library that's used for I2C communications uses interrupts itself, therefore it's not possible to access the accelerometer from within another interrupt service routine (ISR).
In any case, it's good practice to run as little code as possible within the interrupt handler function. The easiest way is to simply set a boolean flag variable in the ISR then test and clear the flag in the loop():
volatile bool dataReady = false; // Define the data ready flag
void interruptHandler() // Interrupt handler function
{
dataReady = true; // Set the dataReady flag
}
void loop()
{
if (dataReady) // Check if data is ready
{
// Handle code here...
dataReady = false; // Clear the dataReady flag
}
// ...continue with rest of loop....
Thank you for the response! unfortunately though the code it's still not working even if I try something simpler than reading the acceleration like reading an analog input with the function AnalogRead(). Do you have an explanation for that? I also tried to use the compare interrupt instead of the overflow one but i wasn't able to make it work.
Thank you for your help so far!
Virginia
The analogRead() function should work. I just tested it in the TC3 timer code above and it functioned just fine.
If you require the analog pin and the accerometer to be read every second, have you considered using the millis() function in the loop()? This avoids the use of interrupts entirely:
#define INTERVAL 1000 // Set the time interval to 1000ms (1 second)
uint32_t previousMillis; // Define the millis variables
void setup() {}
void loop()
{
uint32_t currentMillis = millis(); // Get the current time
if (currentMillis - previousMillis >= INTERVAL) // If the elapsed time since the previous access exceeds the interval
{
previousMillis = currentMillis; // Update previousMillis with the current time
// Add code to be run every second here...
}
}