Arduino Nano 33 IoT ESP32-S3 Timer Interrupts

Not with AVR specific code though. That PORTD line will just be an error on a SAM or ESP platform. Again, the AVR code you have is a red herring. It's adding confusion to what should be simple.

Thank you for the heads up! I am used to set and read pins using registers but forgot they are hardware specific. I'll just use digitalWrite. Or maybe since the SAMD chip is made by Microchip it uses some similar registers as the PIC family which I already know how to use. I should try.

Why guess? Just look at the datasheet and save yourself the time.

1 Like

program using two SAMD21 timers to generate square wave 5KHz on pin 6 and 10KHz on pin 7

// MKRFOX 1200 (SAMS21) timer test - generate square wave 5KHz  on pin 6 and 10KHz on pin 7
//   NOTE: square waves are not syncronised

// from g https://github.com/khoih-prog/SAMD_TimerInterrupt

#if !(defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRWIFI1010) \
      || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_SAMD_MKRFox1200) || defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310) \
      || defined(ARDUINO_SAMD_MKRGSM1400) || defined(ARDUINO_SAMD_MKRNB1500) || defined(ARDUINO_SAMD_MKRVIDOR4000) \
      || defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(__SAMD51__) || defined(__SAMD51J20A__) \
      || defined(__SAMD51J19A__) || defined(__SAMD51G19A__) || defined(__SAMD51P19A__) \
      || defined(__SAMD21E15A__) || defined(__SAMD21E16A__) || defined(__SAMD21E17A__) || defined(__SAMD21E18A__) \
      || defined(__SAMD21G15A__) || defined(__SAMD21G16A__) || defined(__SAMD21G17A__) || defined(__SAMD21G18A__) \
      || defined(__SAMD21J15A__) || defined(__SAMD21J16A__) || defined(__SAMD21J17A__) || defined(__SAMD21J18A__))
#error This code is designed to run on SAMD21/SAMD51 platform! Please check your Tools->Board setting.
#endif

/////////////////////////////////////////////////////////////////

// These define's must be placed at the beginning before #include "SAMDTimerInterrupt.h"
// _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
// Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
// Don't define TIMER_INTERRUPT_DEBUG > 2. Only for special ISR debugging only. Can hang the system.
#define TIMER_INTERRUPT_DEBUG 0
#define _TIMERINTERRUPT_LOGLEVEL_ 0

// Select only one to be true for SAMD21. Must must be placed at the beginning before #include "SAMDTimerInterrupt.h"
#define USING_TIMER_TC3 true  // Only TC3 can be used for SAMD51
#define USING_TIMER_TC4 true  // Not to use with Servo library

#include "SAMDTimerInterrupt.h"

#define SQUARE_WAVE_PIN3 6  // pin to output square wave
#define SQUARE_WAVE_PIN4 7  // pin to output square wave

#define TIMER_INTERVAL_US 50  // timer interval in uSec

// Depending on the board, you can select SAMD21 Hardware Timer from TC3, TC4, TC5, TCC, TCC1 or TCC2
// SAMD51 Hardware Timer only TC3

SAMDTimer ITimer3(TIMER_TC3);
SAMDTimer ITimer4(TIMER_TC4);

// timer interrupt routine
volatile int counter3;
void TimerHandler_TIMER_TC3() {
  counter3++;
  //timer interrupt toggles pin SQUARE_WAVE_PIN
  digitalWrite(SQUARE_WAVE_PIN3, !digitalRead(SQUARE_WAVE_PIN3));
}
// timer interrupt routine
volatile int counter4;
void TimerHandler_TIMER_TC4() {
  counter4++;
  //timer interrupt toggles pin SQUARE_WAVE_PIN
  digitalWrite(SQUARE_WAVE_PIN4, !digitalRead(SQUARE_WAVE_PIN4));
}

void setup() {
  pinMode(SQUARE_WAVE_PIN3, OUTPUT);
  pinMode(SQUARE_WAVE_PIN4, OUTPUT);
  Serial.begin(115200);
  while (!Serial && millis() < 5000)
    ;
  delay(100);
  Serial.print(F("\nStarting TimerInterruptTest on "));
  Serial.println(BOARD_NAME);
  Serial.println(SAMD_TIMER_INTERRUPT_VERSION);
  Serial.print(F("CPU Frequency = "));
  Serial.print(F_CPU / 1000000);
  Serial.println(F(" MHz"));

  // Interval in microseconds
  if (ITimer3.attachInterruptInterval(TIMER_INTERVAL_US * 5, TimerHandler_TIMER_TC3)) {
  } else
    Serial.println(F("Can't set ITimer3. Select another freq. or timer"));
  if (ITimer4.attachInterruptInterval(TIMER_INTERVAL_US, TimerHandler_TIMER_TC4)) {
  } else
    Serial.println(F("Can't set ITimer4. Select another freq. or timer"));
}

void loop() {
  // ecery second print interupt counter
  static long timer = millis();
  if (millis() - timer > 1000) {
    timer = millis();
    Serial.print("counter3 ");
    Serial.print(counter3);
    Serial.print(" counter4 ");
    Serial.println(counter4);
    counter3 = counter4 = 0;
  }
}

serial monitor output

Starting TimerInterruptTest on __SAMD21G18A__
SAMDTimerInterrupt v1.10.1
CPU Frequency = 48 MHz
counter3 4003 counter4 20018
counter3 4003 counter4 20021
counter3 4003 counter4 20016
counter3 4003 counter4 20018
counter3 4003 counter4 20018
counter3 4003 counter4 20017
counter3 4003 counter4 20016
counter3 4003 counter4 20019
counter3 4003 counter4 20019

oscilloscope output
image

NOTE: square waves are not syncronised only appear so on scope because I have stopped the run
to synchronise generate the 2KHz from the 10KHz interrupt, e.g. every fifth interrupt invert the 2KHz output

1 Like

Nice. How could I temporary stop the interrupt from being executed like this?

noInterrupts(); // Stop ISR
  // Do something
interrupts(); // Restart executing the ISR

SAMDTimerInterrupt has the following methods

    void detachInterrupt();
    void disableTimer();
    void reattachInterrupt();
   void enableTimer();

probably disableTimer() and enableTimer() would do what you require

EDIT: example with 10KHz and 2KHz square waves - timer disabled/enabled on a keyboard hit

// MKRFOX 1200 (SAMS21) timer test - generate square wave 2KHz  on pin 6 and 10KHz on pin 7
//   - timer disabled/enabled on a keyboard hit

// from g https://github.com/khoih-prog/SAMD_TimerInterrupt

#if !(defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRWIFI1010) \
      || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_SAMD_MKRFox1200) || defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310) \
      || defined(ARDUINO_SAMD_MKRGSM1400) || defined(ARDUINO_SAMD_MKRNB1500) || defined(ARDUINO_SAMD_MKRVIDOR4000) \
      || defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(__SAMD51__) || defined(__SAMD51J20A__) \
      || defined(__SAMD51J19A__) || defined(__SAMD51G19A__) || defined(__SAMD51P19A__) \
      || defined(__SAMD21E15A__) || defined(__SAMD21E16A__) || defined(__SAMD21E17A__) || defined(__SAMD21E18A__) \
      || defined(__SAMD21G15A__) || defined(__SAMD21G16A__) || defined(__SAMD21G17A__) || defined(__SAMD21G18A__) \
      || defined(__SAMD21J15A__) || defined(__SAMD21J16A__) || defined(__SAMD21J17A__) || defined(__SAMD21J18A__))
#error This code is designed to run on SAMD21/SAMD51 platform! Please check your Tools->Board setting.
#endif

/////////////////////////////////////////////////////////////////

// These define's must be placed at the beginning before #include "SAMDTimerInterrupt.h"
// _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
// Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
// Don't define TIMER_INTERRUPT_DEBUG > 2. Only for special ISR debugging only. Can hang the system.
#define TIMER_INTERRUPT_DEBUG 0
#define _TIMERINTERRUPT_LOGLEVEL_ 0

// Select only one to be true for SAMD21. Must must be placed at the beginning before #include "SAMDTimerInterrupt.h"
#define USING_TIMER_TC3 true  // Only TC3 can be used for SAMD51

#include "SAMDTimerInterrupt.h"

#define SQUARE_WAVE_PIN3 6  // pin to output square wave
#define SQUARE_WAVE_PIN4 7  // pin to output square wave

#define TIMER_INTERVAL_US 50  // timer interval in uSec

// Depending on the board, you can select SAMD21 Hardware Timer from TC3, TC4, TC5, TCC, TCC1 or TCC2
// SAMD51 Hardware Timer only TC3

SAMDTimer ITimer3(TIMER_TC3);

// timer interrupt routine
volatile int counter3, counter4;
void TimerHandler_TIMER_TC3() {
  static int counter_2KHz = 5;
  counter3++;
  //timer interrupt toggles pin SQUARE_WAVE_PIN
  digitalWrite(SQUARE_WAVE_PIN3, !digitalRead(SQUARE_WAVE_PIN3));
  if (--counter_2KHz == 0) {
    counter_2KHz = 5;
    counter4++;
    //timer interrupt toggles pin SQUARE_WAVE_PIN
    digitalWrite(SQUARE_WAVE_PIN4, !digitalRead(SQUARE_WAVE_PIN4));
  }
}


void setup() {
  pinMode(SQUARE_WAVE_PIN3, OUTPUT);
  pinMode(SQUARE_WAVE_PIN4, OUTPUT);
  Serial.begin(115200);
  while (!Serial && millis() < 5000)
    ;
  delay(100);
  Serial.print(F("\nStarting TimerInterruptTest on "));
  Serial.println(BOARD_NAME);
  Serial.println(SAMD_TIMER_INTERRUPT_VERSION);
  Serial.print(F("CPU Frequency = "));
  Serial.print(F_CPU / 1000000);
  Serial.println(F(" MHz"));

  // Interval in microseconds
  if (ITimer3.attachInterruptInterval(TIMER_INTERVAL_US, TimerHandler_TIMER_TC3)) {
  } else
    Serial.println(F("Can't set ITimer3. Select another freq. or timer"));
}

void loop() {
  // ecery second print interupt counter
  static long timer = millis();
  if (millis() - timer > 1000) {
    timer = millis();
    Serial.print("counter3 ");
    Serial.print(counter3);
    Serial.print(" counter4 ");
    Serial.println(counter4);
    counter3 = counter4 = 0;

    // keyboard hit disable/enable timer
    if (Serial.available()) {
      static bool enabled = true;
      Serial.read();
      if (enabled) {
        ITimer3.disableTimer();
        Serial.println("keyboard hit disabled timer");
      } else {
        ITimer3.enableTimer();
        Serial.println("keyboard hit enabled timer");
      }
      enabled = !enabled;
    }
  }
}

serial monitor output - counter goto 0 when timer is disabled

Starting TimerInterruptTest on __SAMD21G18A__
SAMDTimerInterrupt v1.10.1
CPU Frequency = 48 MHz
counter3 20015 counter4 4003
counter3 20016 counter4 4003
counter3 20015 counter4 4003
counter3 20017 counter4 4004
counter3 20015 counter4 4003
keyboard hit disabled timer
counter3 0 counter4 0
counter3 0 counter4 0
counter3 0 counter4 0
counter3 0 counter4 0
keyboard hit enabled timer
counter3 20014 counter4 4003
counter3 20015 counter4 4003
counter3 20015 counter4 4003
counter3 20016 counter4 4003
keyboard hit disabled timer
counter3 1 counter4 0
counter3 0 counter4 0
counter3 0 counter4 0
counter3 0 counter4 0
keyboard hit enabled timer
counter3 20014 counter4 4003
counter3 20016 counter4 4003

Edit: maybe worth updating the post title to reflect that it is a SAMD21 that is using timer interrupts

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.