Arduino Nano 33 IoT ESP32-S3 Timer Interrupts

Hello! First time posting on the forum!
I am trying to rebuild a self stabilizing two-wheeled robot I saw here.

I am currently looking at the software and I am having some trouble with the timer interrupts since I choose to use an Arduino Nano IoT that's based on ESP32-S3 . Can somebody please help me understanding the registers I need to use for it to work?

Here is an extract of the code that can't work on my micro:

// TIMER 1: controlling motor 1
ISR(TIMER1_COMPA_vect){
  TCNT1 = 0;  
  if (directionMotor1 == 0)
    return;
    
  PORTD |= (1<<PORTD4); //set bit       // same as digitalWrite(STEPPER_STEP_1, HIGH); 
  delay_05us();
  PORTD &= ~(1<<PORTD4); //clear bit    // same as digitalWrite(STEPPER_STEP_1, LOW);
}

// TIMER 3: controlling motor 2
ISR(TIMER3_COMPA_vect){
  TCNT3 = 0;  
  if (directionMotor2 == 0)
    return;
    
  PORTD |= (1<<PORTD7); //set bit       // same as digitalWrite(STEPPER_STEP_2, HIGH); 
  delay_05us();
  PORTD &= ~(1<<PORTD7); //clear bit    // same as digitalWrite(STEPPER_STEP_2, LOW);
}

void setMotorSpeed(int16_t tspeed, int motorID)
{
  long timer_period;
  int16_t motorspeed = tspeed;

  noInterrupts();
  
  if (motorID == 1) {
    if (motorspeed > 0) {
      timer_period = 2000000 / motorspeed; // 2Mhz timer
      directionMotor1 = 1;
      digitalWrite(STEPPER_DIR_1, LOW);
    } else if (motorspeed < 0) {
      timer_period = 2000000 / -motorspeed;
      directionMotor1 = -1;
      digitalWrite(STEPPER_DIR_1, HIGH);
    } else {
      timer_period = 65535;
      directionMotor1 = 0;
    }

    if (timer_period > 65535)   // Check for maximun period without overflow
      timer_period = 65535;
    /* ERROR
    OCR1A = timer_period;  
    if (TCNT1 > OCR1A)    // Check  if we need to reset the timer...
      TCNT1 = 0; 
    */
  } else if (motorID == 2){
    if (motorspeed > 0) {
      timer_period = 2000000 / motorspeed; // 2Mhz timer
      directionMotor2 = 1;
      digitalWrite(STEPPER_DIR_2, HIGH);
    } else if (motorspeed < 0) {
      timer_period = 2000000 / -motorspeed;
      directionMotor2 = -1;
      digitalWrite(STEPPER_DIR_2, LOW);
    } else {
      timer_period = 65535;
      directionMotor2 = 0;
    }

    if (timer_period > 65535)   // Check for maximun period without overflow
      timer_period = 65535;
    /* ERROR
    OCR3A = timer_period;  
    if (TCNT3 > OCR3A)    // Check  if we need to reset the timer...
      TCNT3 = 0;
    */
  }   
  interrupts();
}

I found this example that works but I'd like to understand more because I read somewhere that TC3 isn't the most reliable one:

int count=0;
void setup() {
  Serial.begin(9600);
  REG_GCLK_GENDIV = ( GCLK_GENDIV_ID(0));
  REG_GCLK_GENCTRL = (GCLK_GENCTRL_ID(0)| GCLK_GENCTRL_GENEN );
  REG_GCLK_CLKCTRL = (GCLK_CLKCTRL_ID_TCC2_TC3 |GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_CLKEN);   
  REG_PM_APBCMASK =  PM_APBCMASK_TC3;  
  REG_TC3_CTRLA = (TC_CTRLA_ENABLE |TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_NFRQ | TC_CTRLA_PRESCALER_DIV1024 | TC_CTRLA_PRESCSYNC_PRESC);
  REG_TC3_INTENSET =  TC_INTENSET_OVF ;
  REG_TC3_INTFLAG = TC_INTFLAG_OVF;
  REG_TC3_COUNT16_COUNT = 0x48E4;
  NVIC_EnableIRQ(TC3_IRQn);
}


void TC3_Handler()
{
  REG_TC3_COUNT16_COUNT = 0x48E4;
  REG_TC3_INTFLAG = TC_INTFLAG_OVF;
  count ++;
  Serial.println(count);
}

void loop() {

}

Is there any sort of documentation on how to set up timer registers?
Thank you in advance for your help.

This code also works. But I can't figure out how could I tweak it to match my needs and implement it in my project.

Something like this would be awesome but I am afraid there are no specific libraries for the code to look this clean...

#define LED 21
 
hw_timer_t *Timer0_Cfg = NULL;
 
void IRAM_ATTR Timer0_ISR()
{
    digitalWrite(LED, !digitalRead(LED));
}
void setup()
{
    pinMode(LED, OUTPUT);
    Timer0_Cfg = timerBegin(0, 80, true);
    timerAttachInterrupt(Timer0_Cfg, &Timer0_ISR, true);
    timerAlarmWrite(Timer0_Cfg, 1000, true);
    timerAlarmEnable(Timer0_Cfg);
}
void loop()
{
    
}

Converting that code from AVR to ESP is not going to be straight forward. They are completely different architectures. You'd be better off to just throw this out an completely rewrite it. Or try to understand how it works and rewrite it.

If that's something that is beyond your abilities, then I would recommend getting the board that is compatible with the code you want to use or finding a project that is compatible with the board you want to use. Trying to port this from one architecture to the other is NOT a trivial task and would surely be more work than simply rewriting code for a balancer from scratch.

Thanks for the suggestion, I don't think it's impossible, it's just I can't find any documentation about the registers I need to work with. On the Arduino's official datasheet there's not a single mention.
I'll look more into it, at the moment i found this and I'll test it soon. Thank you again.

Oh, it's certainly not impossible. But it will be harder than writing from scratch. There are not going to be one-to-one replacements for those registers.

Right, Arduino is meant to abstract that stuff away. You shouldn't have to go to that level with most Arduino projects. It's not the intended audience.

If you want to find information on the registers in the ESP then check the datasheets from Espressif. For the AVR chips get the AVR datasheets from Microchip (formerly Atmel).

I don't understand what you mean by rewriting from scratch, I of course need the rest of the code and the concept behind the AVR timers (when they are called, what's the frequency, when they are resetted, what interrupts are they triggering, what are interrupts doing and so on) so it's basically rewriting the entire timer section from scratch, I am aware I can't just do AVR_TIMER --> ESP_TIMER and expect everything to work. But thanks anyway, I'll follow your suggestions an maybe try using an Arduino UNO that hopefully shares the same or similar AVR timer registers. :slightly_smiling_face:

I am sorry about the crosspost, I didn't intend wasting people's time. I deleted it.

That's what I mean. You'd have to know what this code is trying to do with those timers, and then figure out how to do the same sort of thing with a different set of timers. But how to balance a self-balancer is not something that you can only learn from this code. There are tons of examples on how a balancing robot works. I think it would be easier to decide what needs to be done (measure roll at certain intervals, run PID calculation at certain intervals, provide output to the motors as appropriate) and then write code for an ESP to do that. Taking apart how its done on an AVR won't be any more informative and will require twice as much study.

Basically you'll end up rewriting the code at the end of the day either way. The question is how do you want to learn what to do in the code you write? Do you want to struggle to understand how it works on an AVR, and then from there try to understand what's needed, and then from there try to understand how to do that on an ESP? Or do you think it makes more sense to cut that first step out and just go straight to learning what needs to be done and then how to do it on the chip you have.

Alright, it makes sense. I didn't think about it in this way. Thank you very much for the mind opening, I was really stuck. But is arduino nano esp32 really based only on esp? Will any program that work on esp word on arduino esp? Because I tried including some libraries for esp and didn't work.

I found what I was looking for, this full pinout diagram shows all the timer registers and in combination with the Microchip datasheet (I didn't know I was using ARM timers instead of ESP) I can interact with them. Now I just have to figure out how to trigger an ISR at the right time.

Low-Power, 32-bit Cortex-M0+ MCU with Advanced Analog and PWM (microchip.com)

This code example shows how to use timers to generate a 33 kHz PWM on PINs D2 and D6 by using the TCC0 registers.

void setup() {

//************************************** Clcok Setting ********************************************************//
  // Feed GCLK0 at 48MHz to TCC0 and TCC1
  REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN |         // Enable GCLK0 as a clock source (1 << 14) (imposta il bit 14 a 1 per abilitarlo)
                      GCLK_CLKCTRL_GEN_GCLK0 |     // Select GCLK0 at 48MHz (0 << 8) (GCLK_CLKCTRL_GEN_GCLK1, GCLK_CLKCTRL_GEN_GCLK2, ...)
                      GCLK_CLKCTRL_ID_TCC0_TCC1;   // Route GCLK0 to TCC0 and TCC1 (0x1A << 0)

//************************************** Clcok Setting ********************************************************//

//************************************** PORT Enabling ********************************************************//
  // Enable the port multiplexer for pins D6
  PORT->Group[g_APinDescription[6].ulPort].PINCFG[g_APinDescription[6].ulPin].bit.PMUXEN = 1;

  // D6 is on EVEN port pin PA04 and TCC0/WO[0] channel 0 is on peripheral E
  PORT->Group[g_APinDescription[6].ulPort].PMUX[g_APinDescription[6].ulPin >> 1].reg |= PORT_PMUX_PMUXE_E;

  // Enable the port multiplexer for pins D2
  PORT->Group[g_APinDescription[2].ulPort].PINCFG[g_APinDescription[2].ulPin].bit.PMUXEN = 1;

  // D2 is on EVEN port pin PB10 and TCC0/WO[4] channel 0 is on peripheral F
  PORT->Group[g_APinDescription[2].ulPort].PMUX[g_APinDescription[2].ulPin >> 1].reg |= PORT_PMUX_PMUXE_F;
//************************************** PORT Enabling ********************************************************//

//************************************** TIMER Setting ********************************************************//
  // Normal (single slope) PWM operation: timer countinuously counts up to PER register value and then is reset to 0
  REG_TCC0_WAVE = TCC_WAVE_WAVEGEN_NPWM;          // Setup single slope PWM on TCC0  (2 << 0)
  while (TCC1->SYNCBUSY.bit.WAVE);                 // Wait for synchronization

  REG_TCC0_CTRLA |= TCC_CTRLA_PRESCALER_DIV1 ;      // Set prescaler to 1, 48MHz/1 (0 << 8)

  REG_TCC0_PER = 1453;                            // Set the frequency of the PWM on TCC0 to 33kHz: 48MHz / (1 * 1453 + 1) = 33kHz
  while (TCC0->SYNCBUSY.bit.PER);                  // Wait for synchronization

  REG_TCC0_CC0 = 726;                           // TCC1 CC0 - 50% duty cycle
  while (TCC0->SYNCBUSY.bit.CC0);                 // Wait for synchronization

  // dead time generation (edit the value to adjust the dead time on Low side (bit: 16) and High side (bit:24))
  REG_TCC0_WEXCTRL |= (50 << 16) | (50 << 24) | (1 << 8) | (2 << 0);  // (1 << 8): implement dead time at output WO[0] and WO[4]
  // (2 << 0): output matrix (all output use CC0

  TCC0->CTRLA.bit.ENABLE = 1;                     // Enable the TCC0 counter
  while (TCC0->SYNCBUSY.bit.ENABLE);              // Wait for synchronization
  //************************************** TIMER Setting ********************************************************//
}

void loop() {
}

why not use the ESP32TimerInterrupt Library
e.g. generating a 10KHz square wave on GPIO4 using a ESP32-S3-DevKitC-1 Timer0 interrupts

// esp32 interrupt every 50uSec generate 20KHz square wave on GPIO4

// original code from https://github.com/khoih-prog/ESP32TimerInterrupt

#if !defined(ESP32)
#error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting.
#endif

// These define's must be placed at the beginning before #include "ESP32_New_TimerInterrupt.h"
// _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
#define _TIMERINTERRUPT_LOGLEVEL_ 4

// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error
#include "ESP32TimerInterrupt.h"

// Don't use PIN_D1 in core v2.0.0 and v2.0.1. Check https://github.com/espressif/arduino-esp32/issues/5868
// Don't use PIN_D2 with ESP32_C3 (crash)
#define PIN_GPIO4 4  // Pin GPIO19 signal output

// With core v2.0.0+, you can't use Serial.print/println in ISR or crash.
// and you can't use float calculation inside ISR  Only OK in core v1.0.6-
volatile int counter = 0;  // counting timer interrupts
bool IRAM_ATTR TimerHandler0(void* timerNo) {
  static bool toggle0 = false;
  counter++;
  digitalWrite(PIN_GPIO4, toggle0);
  toggle0 = !toggle0;  //timer interrupt toggles pin PIN_GPIO4
  return true;
}

#define TIMER0_INTERVAL_US 50  // timer interrupts in uSec

// Init ESP32 timer 0 and 1
ESP32Timer ITimer0(0);

void setup() {
  pinMode(PIN_GPIO4, OUTPUT);
  Serial.begin(115200);
  while (!Serial && millis() < 5000)
    ;
  delay(500);
  // setup timer 0 interrupts
  Serial.print(F("\nStarting TimerInterruptTest on "));
  Serial.println(ARDUINO_BOARD);
  Serial.println(ESP32_TIMER_INTERRUPT_VERSION);
  Serial.print(F("CPU Frequency = "));
  Serial.print(F_CPU / 1000000);
  Serial.println(F(" MHz"));

  // Using ESP32  => 80 / 160 / 240MHz CPU clock ,
  // For 64-bit timer counter
  // For 16-bit timer prescaler up to 1024

  // Interval in microsecs
  if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_US, TimerHandler0)) {
    Serial.print(F("Starting  ITimer0 OK"));
  } else
    Serial.println(F("Can't set ITimer0. Select another freq. or timer"));
  Serial.flush();
}

void loop() {
  // display interrupt counter every second
  static long timer = millis();
  if (millis() - timer >= 1000) {
    timer = millis();
    Serial.println(counter);
    counter = 0;
  }
}

oscilloscope output
image

serial monitor output

Starting TimerInterruptTest on ESP32S3_DEV
ESP32TimerInterrupt v2.3.0
CPU Frequency = 240 MHz
[TISR] ESP32_S3_TimerInterrupt: _timerNo = 0 , _fre = 1000000
[TISR] TIMER_BASE_CLK = 80000000 , TIMER_DIVIDER = 80
[TISR] _timerIndex = 0 , _timerGroup = 0
[TISR] _count = 0 - 50
[TISR] timer_set_alarm_value = 50.00
Starting  ITimer0 OK20155
20000
20000
20000
20000

Thank you for your partecipation to this topic!
I tried it but thanks to @Delta_G I found out I am not really programming on the ESP32 chip but instead my code runs on the Atmel SAMD21 wich works in combination with the ESP.
In fact this specific line of code stops me from successefully compiling my code:

 #if !defined( ESP32 ) 
 	#error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting. 
 #endif 

In the board manager I have to use Arduino Nano 33 IoT, if I use the ESP32S3 Dev Module I can't compile it right. It should work if I knew how to put the code directly onto the ESP without using the other chip.

I'm now working on the SAMD21 registers which are explained in the datasheet linked in my previous update.
This is the closest example I found that almost fully matches my needs, I just have to tweak it a little bit:

void setupTimerISR()
{
  // Set up the generic clock (GCLK4) used to clock timers
  REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) |          // Divide the 48MHz clock source by divisor 1: 48MHz/1=48MHz
                    GCLK_GENDIV_ID(4);            // Select Generic Clock (GCLK) 4
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC |           // Set the duty cycle to 50/50 HIGH/LOW
                     GCLK_GENCTRL_GENEN |         // Enable GCLK4
                     GCLK_GENCTRL_SRC_DFLL48M |   // Set the 48MHz clock source
                     GCLK_GENCTRL_ID(4);          // Select GCLK4
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  // Feed GCLK4 to TC4 and TC5
  REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TC4 and TC5
                     GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                     GCLK_CLKCTRL_ID_TC4_TC5;     // Feed the GCLK4 to TC4 and TC5
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  // TC4 at 46.875 kHz for step period
  REG_TC4_COUNT16_CC0 = 0;                      // Set the TC4 CC0 register as the TOP value in match frequency mode
  while (TC4->COUNT16.STATUS.bit.SYNCBUSY);       // Wait for synchronization

  // TC5 at 1000 Hz for acceleration
  REG_TC5_COUNT16_CC0 = CC0;                        // Set the TC5 CC0 register as the TOP value in match frequency mode
  while (TC5->COUNT16.STATUS.bit.SYNCBUSY);       // Wait for synchronization

  NVIC_SetPriority(TC4_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority for TC4 to 0 (highest)
  NVIC_EnableIRQ(TC4_IRQn);         // Connect TC4 to Nested Vector Interrupt Controller (NVIC)

  NVIC_SetPriority(TC5_IRQn, 1);    // Set the Nested Vector Interrupt Controller (NVIC) priority for TC5 to 1
  NVIC_EnableIRQ(TC5_IRQn);         // Connect TC5 to Nested Vector Interrupt Controller (NVIC)

  REG_TC4_INTFLAG |= TC_INTFLAG_OVF;              // Clear the interrupt flags
  REG_TC4_INTENSET = TC_INTENSET_OVF;             // Enable TC4 interrupts

  REG_TC5_INTFLAG |= TC_INTFLAG_OVF;              // Clear the interrupt flags
  REG_TC5_INTENSET = TC_INTENSET_OVF;             // Enable TC5 interrupts
 
  REG_TC4_CTRLA |= TC_CTRLA_PRESCALER_DIV1024 |   // Set prescaler to 1024, 48MHz/1024 = 46.875kHz
                   TC_CTRLA_WAVEGEN_MFRQ |        // Put the timer TC4 into match frequency (MFRQ) mode
                   TC_CTRLA_ENABLE;               // Enable TC4
  while (TC4->COUNT16.STATUS.bit.SYNCBUSY);       // Wait for synchronization

  REG_TC5_CTRLA |= TC_CTRLA_PRESCALER_DIV1024 |   // Set prescaler to 1024, 48MHz/1024 = 46.875kHz
                   TC_CTRLA_WAVEGEN_MFRQ |        // Put the timer TC5 into match frequency (MFRQ) mode
                   TC_CTRLA_ENABLE;               // Enable TC5
  while (TC5->COUNT16.STATUS.bit.SYNCBUSY);       // Wait for synchronization
}

Thanks again for your suggestion I'll look if it fits better using only the onboard ESP.

generating 100KHz square wave on a MKRFOX 1200 (SAMD21 processor)

// MKRFOX 1200 (SAMS21) timer test - generate 100KHz square wave on pin 6

// 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 false  // Not to use with Servo library
#define USING_TIMER_TC5 false
#define USING_TIMER_TCC false
#define USING_TIMER_TCC1 false
#define USING_TIMER_TCC2 false  // Don't use this, can crash on some boards

#include "SAMDTimerInterrupt.h"

#define SQUARE_WAVE_PIN 6  // pin to output square wave

#define TIMER_INTERVAL_US 5  // timer interval in uSec

#if (TIMER_INTERRUPT_USING_SAMD21)

#if USING_TIMER_TC3
#define SELECTED_TIMER TIMER_TC3
#elif USING_TIMER_TC4
#define SELECTED_TIMER TIMER_TC4
#elif USING_TIMER_TC5
#define SELECTED_TIMER TIMER_TC5
#elif USING_TIMER_TCC
#define SELECTED_TIMER TIMER_TCC
#elif USING_TIMER_TCC1
#define SELECTED_TIMER TIMER_TCC1
#elif USING_TIMER_TCC2
#define SELECTED_TIMER TIMER_TCC
#else
#error You have to select 1 Timer
#endif

#else

#if !(USING_TIMER_TC3)
#error You must select TC3 for SAMD51
#endif

#define SELECTED_TIMER TIMER_TC3

#endif

// Init selected SAMD timer
SAMDTimer ITimer(SELECTED_TIMER);

// timer interrupt routine
volatile int counter;
void TimerHandler() {
  counter++;
  //timer interrupt toggles pin SQUARE_WAVE_PIN
  digitalWrite(SQUARE_WAVE_PIN, !digitalRead(SQUARE_WAVE_PIN));
}

void setup() {
  pinMode(SQUARE_WAVE_PIN, 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 (ITimer.attachInterruptInterval(TIMER_INTERVAL_US, TimerHandler)) {
  } else
    Serial.println(F("Can't set ITimer. Select another freq. or timer"));
}

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

serial output

tarting TimerInterruptTest on __SAMD21G18A__
SAMDTimerInterrupt v1.10.1
CPU Frequency = 48 MHz
199164
199149
199145
199149
199134
199148
199148
199146
199136

oscilloscope output
image

1 Like

Wow! This is very useful! I'm gonna mark this answer as the solution as soon as I tested and confirmed it.

I hope this is going help someone else one day.

Thank you very much for the time you spent helping me! I really appreciated the oscilloscope image.

But what if I need to operate two separate timers?

I tried the examples on the GitHub page of the library with no success. I even tried to manually include the other header files such as #include <SAMD_ISR_Timer.h> also with "".

error: 'ISR_Timer' does not name a type; did you mean 'ITimer'?
 ISR_Timer SAMD_ISR_Timer;
 ^~~~~~~~~
 ITimer

And then many other consequent errors and one in particular i found interesting. What I forgot? I just copypasted the code from github (yes, the two separate code blocks merged).

error: 'lastMillis' was not declared in this scope
     lastMillis = millis();
     ^~~~~~~~~~

explain how you want the two timers to operate

I'd like to have two different TimerHandler() functions. That operate at the same frequency and everything, the only difference is the content. Or I could simply put the code inside the same since it doesn't change the frequency.

if both operate at the same frequency (what is the frequency) one interrupt should do

if the tasks are very complex (should not be - keep interrupt routines short) run interrupts at twice the frequency and alternate the tasks??

edit: there is a File>Examples>SAMD_timerinterrupt>SAMD21_MultiTimers.ino
trying to figure out how it works!!

1 Like

Yep, that's right. I will use the interrupt to send a step signal to a stepper motor like this:

if (directionMotor1 == 0)
    return;
    
  PORTD |= (1<<PORTD4); //set bit       // same as digitalWrite(STEPPER_STEP_1, HIGH); 
  delay_05us();
  PORTD &= ~(1<<PORTD4); //clear bit    // same as digitalWrite(STEPPER_STEP_1, LOW);

There is a second motor that could use a second interrupt but i don't see any problem putting the code together. The only thing I'd have to edit is the return because I should check both before exiting. But it might work! Atm I don't have the robot with me. I'll write a sketch and tomorrow I'll test it as soon as I can and post an update.

Thank you again for all your support!