The faulty sketch is based of an working example from Markus Bader at
I experimented with timer registers and interrupt vectors. A logical error must have occurred. After uploading the modified sketch, nothing works.
- All subsequent uploads will not work (processing.app.SerialException: Error opening serial port 'COM12').
- After a reset, the serial monitor still shows the result of the last correct upload.
The "bad" sketch contains the following important points:
- Line 8: Declaration of a pointer to a timer
- Line 28: Calculation of the timer address
- Line 93: Calculating the interrupt vector
Is there a way to make the Nano 33 IOT working again?
Here is the modified sketch:
/*===========================================================================
This sketch illustrates how to set a timer on an SAMD21 based Arduino boards
(Feather M0, Arduino Zero - and Nano 33 IOT - should work)
----------------------------------------------------------------------------
TC4 with CC0 = 48000 -> exactly 1 ms interrupt
============================================================================*/
Tc* TCn; // Pointer to TC3 | TC4 | TC5
#define TIMn 4 // Number of used timer from above (3|4|5)
#define LED_PIN 13 // Blinking with change at each interrupt
bool state = 0; // Actual state of the LED_PIN
char buffer[64]; // Buffer for sprintf
void setup() {
pinMode(LED_PIN,OUTPUT); // LED pin, toogled at each interrupt
Serial.begin(38400);
while(!Serial) delay(10);
Serial.println("Testing SAMD21 at Nano 33 IOT: Timer 3...5");
//---- Print the addresses of the 3 possible timer ----
sprintf(buffer,"TC3=0x%08lXU",(long)TC3);
Serial.println(buffer);
sprintf(buffer,"TC4=0x%08lXU",(long)TC3 + 0x400);
Serial.println(buffer);
sprintf(buffer,"TC5=0x%08lXU",(long)TC3 + 0x800);
Serial.println(buffer);
TCn = TC3 + (TIMn-3) * 0x400; //---- calculated pointer to used timer
sprintf(buffer,"TCn=0x%08lXU",(long)TCn);
Serial.println(buffer); // Show it at Serial Monitor
tcConfigure(); // Configure the timer
tcStartCounter(); // Starts the timer
}
void loop() {
//tcDisable(); // This function can be used, to stop/pause the timer
//tcReset(); // This function should be called if you stop the timer
}
//==== Interup service at all 3 interrupts ====
void TCx_Handler() {
if(state == true) {
digitalWrite(LED_PIN,HIGH);
} else {
digitalWrite(LED_PIN,LOW);
}
state = !state;
// END OF YOUR CODE
TCn->COUNT16.INTFLAG.bit.MC0 = 1; // Don't change this
}
//==== This function gets called by the interrupt =====
void TC3_Handler (void) {
TCx_Handler();
}
void TC4_Handler (void) {
TCx_Handler();
}
void TC5_Handler (void) {
TCx_Handler();
}
/*----------------------------------------------------------------------
TIMER SPECIFIC FUNCTIONS FOLLOW
you shouldn't change these unless you know what you're doing
----------------------------------------------------------------------*/
//===== Configures the TC to generate output events at the sample frequency.
// Configures the TC in Frequency Generation mode, with an event output once
// each time the audio sample frequency period expires.
void tcConfigure() {
// Enable GCLK for TC4 and TC5 (timer counter input clock)
GCLK->CLKCTRL.reg = (uint16_t)(GCLK_CLKCTRL_CLKEN
| GCLK_CLKCTRL_GEN_GCLK0
| GCLK_CLKCTRL_ID(GCM_TC4_TC5));
while (GCLK->STATUS.bit.SYNCBUSY);
tcReset(); //reset TCn
// Set Timer counter Mode to 16 bits
TCn->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16;
// Set TC5 mode as match frequency
TCn->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;
// Set prescaler and enable TC5
TCn->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1 | TC_CTRLA_ENABLE;
// Based off of the system clock and the user defined sample rate
TCn->COUNT16.CC[0].reg = 48000; //---- Wert für genau 1 ms ----;
while (tcIsSyncing());
//---- Configure interrupt request ----
IRQn TCx_IRQ = (IRQn)(TC3_IRQn + TIMn -3); //---- Calculate vector
Serial.print("TCx_IRQ="); Serial.println((int)TCx_IRQ); // Debug only
NVIC_DisableIRQ(TCx_IRQ);
NVIC_ClearPendingIRQ(TCx_IRQ);
NVIC_SetPriority(TCx_IRQ, 0);
NVIC_EnableIRQ(TCx_IRQ);
// Enable the TC5 interrupt request
TCn->COUNT16.INTENSET.bit.MC0 = 1;
while (tcIsSyncing()); //wait until TC5 is done syncing
}
//====Function that is used to check if TC5 is done syncing
// returns true when it is done syncing
bool tcIsSyncing() {
return TCn->COUNT16.STATUS.reg & TC_STATUS_SYNCBUSY;
}
//==== This function enables TC5 and waits for it to be ready
void tcStartCounter() {
TCn->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; //set the CTRLA register
while (tcIsSyncing()); //wait until snyc'd
}
//==== Reset TC5 =====
void tcReset() {
TCn->COUNT16.CTRLA.reg = TC_CTRLA_SWRST;
while (tcIsSyncing());
while (TCn->COUNT16.CTRLA.bit.SWRST);
}
//==== Disable TC5 =====
void tcDisable() {
TCn->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE;
while (tcIsSyncing());
}