Timer Interrupt minimum tick time

Dear All,

I need to make an interrupt (Timer/PWM) which can generate interrupts every 1us or higher. I found an example for using Timer in

https://deepbluembedded.com/esp32-timers-timer-interrupt-tutorial-arduino-ide/#google_vignette

I modified the code to obtain timer alarm interrupt every 1 us. However, when measuring through oscilloscope. The frequency of the output(an indication of interrupt) does not go higher than a certain value of 173kHz and also there is jitter. The code is as shown.

/*

 
#define LED 22
hw_timer_t *Timer0_Cfg = NULL;

 
void IRAM_ATTR Timer0_ISR()
{
    digitalWrite(LED, !digitalRead(LED));
}
void setup()
{
    pinMode(LED, OUTPUT);
    Timer0_Cfg = timerBegin(0, 8, true);
    timerAttachInterrupt(Timer0_Cfg, &Timer0_ISR, true);
    timerAlarmWrite(Timer0_Cfg, 10, true);
    timerAlarmEnable(Timer0_Cfg);
}
void loop()
{
    // Do Nothing!
}

What is the reason for jitter. Are there any better approaches for getting interrupt every 1us.

Each interrupt takes some time with housekeeping, e.g. saving and restoring registers. This limits the maximum possible interrupt rate.

Use a controller with a higher clock frequency.

The digitalRead and digitalWrite in the interrupt handler probably take more.

1 Like

Is there a method to use MCPWM interrupt. To overcome timer limitations.

The millis( ) function will cause jitter as it runs every millisecond.

The 2nd argument of the above function indicates the time interval in microseconds after which an interrupt signal will be triggered; so, it should be 1 and NOT 10.

The 2nd argument in the above function is clock prescaler. Why is it 8? Do you know the frequency of the driving clock of Timer 0? Or when you put it 8 and set the timeout period as 1 us, the driving clock rate is automatically set at the correct value?

1 Like

At least do not use digitalRead() and digiatlWrite() in IRq handler. Use a direct register access functions

1 Like

Hi b707,

Can you give reference for directly writing (REGISTER WRITING) 'High' to GPIO 22 (as an example).

I have seen in forums that code line

GPIO.out_w1ts = (1 << 22);

is used. But still can take much higher time.

1us is far too fast an interrupt frequency. Even on a 120MHz processor like a SAMD51 or RP2040, that's only 100 instruction cycles, and the overhead that @DrDiettrich mentioned will amount to more than 25 cycles. (You can get CPUs that are faster than 120MHz, of course, but the overhead tends to go up due to the more complex architectures.)

You need a different approach to solving your (unspecified) problem. Timers frequently have complex feature sets for dealing with things on short time scales, and then there are additional features like rp2040's PIO or SAM's "CCL" and "Event" subsystems (not directly supported by Arduino, so ... complex.)

Is there any method to using method to using MCPWM interrupt . Because I have been able to generate MCPWM with 100kHz and higher PWM. There is no example given in documentation regarding using MCPWM interrupt (or I am not able to find as yet). What can be done in this regard.

I have made a test code for ISR

#include "driver/mcpwm.h"
//MCPWM TRY 2

// REF:https://forum.arduino.cc/t/esp32-mcpwm/608899


                       
#define MOSFET1 22          //pin to trigger the MOSFET (Output) pin22
#define MOSFET2 23          //pin to trigger the MOSFET (Output) pin22
uint32_t counter;

void IRAM_ATTR isr_handler(void *arg)
{
counter++;
}


void setup() {
  // put your setup code here, to run once:
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, MOSFET1);
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, MOSFET2); 

  mcpwm_config_t pwm_config;
    pwm_config.frequency = 120000;    //above 100kHz there is error of more than 5 %
    pwm_config.cmpr_a = 50;       //duty cycle of PWMxA = 60.0%
    pwm_config.cmpr_a = 50;
    pwm_config.counter_mode = MCPWM_UP_COUNTER;
    pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
    mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config);   //Configure PWM0A & PWM0B with above settings
  
  mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, MCPWM_DUTY_MODE_0);
  mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A,50);
  mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B, MCPWM_DUTY_MODE_1);
  mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B,50);
  mcpwm_deadtime_enable(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, 1, 1); 
  mcpwm_isr_register(MCPWM_UNIT_0, isr_handler, NULL, ESP_INTR_FLAG_IRAM, NULL); //Set ISR Handler
}

void loop() {

  Serial.println(counter);
  delay(10);

}

For testing MCPWM interrupt, i am trying to check interrupt function by seeing increment of counter in serial monitor.
Please let me know how to reset the interrupt flag.

Hi @sacd

The command depends on which interrupt flag that requires clearing.

For example, the ESP32 MCPWM0's TEA channel 0 (compare match) flag:

MCPWM0.int_clr.op0_tea_int_clr = 1;               // Clear the interrupt flag

... while the TEZ (overflow) flag:

MCPWM0.int_clr.timer0_tez_int_clr = 1;           // Clear the interrupt flag

Timing gets worse if you read the counter properly in a critical section. Proper coding also requires marking counter as volatile.

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