Timer Interrupt cannot Run Faster than 100Hz?

e2738729
Posts: 35
Joined: Mon Nov 05, 2018 6:22 pm

Timer Interrupt cannot Run Faster than 100Hz?

Postby e2738729 » Fri Mar 22, 2019 3:26 am

Hi everyone,

I have a program that has a timer interrupt with each tick is 1us. The timer interrupt triggers xSemphoreGiveFromISR to ADS1256_Collect task that simply toggles a GPIO (see code below)

The below is the code:

Code: Select all

#include <stddef.h>
#include "esp_intr_alloc.h"
#include "esp_attr.h"
#include "driver/timer.h" 
#include "esp_log.h"
#include "esp_err.h"
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_system.h"
#include <stdlib.h>
#include <string.h>
#include "driver/spi_master.h"
#include "soc/gpio_struct.h"
#include "rom/ets_sys.h"
#include <time.h>
#include <errno.h>

#include "driver/gpio.h"
#include "esp_log.h"
#include "freertos/semphr.h"

static bool FLAG = 0;
SemaphoreHandle_t xSemaphore = NULL;

static intr_handle_t s_timer_handle;

static void timer_isr(void* spi)
{
    // This resets the timer interrupt -- don't mess with this unless you
    // know what you're doing or want to break things
    TIMERG0.int_clr_timers.t0 = 1;
    TIMERG0.hw_timer[0].config.alarm_en = 1;
    
    xSemaphoreGiveFromISR(xSemaphore, NULL);
}


void ADS1256_Collect(spi_device_handle_t spi) {      
    uint8_t mux[6] = {0x08,0x18,0x28,0x38,0x48,0x58};
    uint8_t i =0; uint8_t reg = 0; uint8_t cmd = 0; uint8_t data = 0;

    for (;;) {
        //wait for the notification from the ISR
        if(xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
            if(FLAG == 0){
                gpio_set_level(5, 1); FLAG = 1;
            }    
            else{
                gpio_set_level(5,0); FLAG = 0;    
            }
        }
    }
}



// This is going to set up a hardware interrupt.  Again, don't mess with this
// unless you want to break things, or you know what you're doing.
void init_timer(int timer_period_us) {
    timer_config_t config = {
        .alarm_en = true,
        .counter_en = false,
        .intr_type = TIMER_INTR_LEVEL,
        .counter_dir = TIMER_COUNT_UP,
        .auto_reload = true,
        .divider = 80            /* 1 us per tic */
    };

    timer_init(TIMER_GROUP_0, TIMER_0, &config);
    timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0);
    timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, timer_period_us);
    timer_enable_intr(TIMER_GROUP_0, TIMER_0);
    timer_isr_register(TIMER_GROUP_0, TIMER_0, &timer_isr, NULL, 0, &s_timer_handle);
    
    timer_start(TIMER_GROUP_0, TIMER_0);
}

void app_main(void)
{    
    gpio_set_direction(5, GPIO_MODE_OUTPUT);
    gpio_set_level(5, 0);
    xSemaphore = xSemaphoreCreateBinary();
    xTaskCreate(ADS1256_Collect, "ADS1256_Collect", 2048, NULL, 10, NULL);
    init_timer(10000);
}
The argument inside the init_timer will set the rate of the timer interrupt. However, the toggling GPIO rate does not change at all for any value less than 10,000. The frequency stays at 100Hz. Even changing the divider from 80 to 8 doesn't do anything.

Why is this happening and how can I speed up the timer interrupt trigger? Maybe 200Hz.

Thank you

ESP_igrr
Posts: 2067
Joined: Tue Dec 01, 2015 8:37 am

Re: Timer Interrupt cannot Run Faster than 100Hz?

Postby ESP_igrr » Fri Mar 22, 2019 4:54 am

xSemaphoreGiveFromISR can take the 2nd argument, which will return a flag you can check and trigger portYIELD_FROM_ISR(); This will tell FreeRTOS that a higher priority task might have been unblocked as a result of the xSemaphoreGiveFromISR call, and that you want to switch to it without waiting for the next tick. Without that, the task will only run at the next tick (hence you see 100Hz frequency).

See https://docs.espressif.com/projects/esp ... iveFromISR and the code snippet therein (note the usage of xHigherPriorityTaskWoken).

e2738729
Posts: 35
Joined: Mon Nov 05, 2018 6:22 pm

Re: Timer Interrupt cannot Run Faster than 100Hz?

Postby e2738729 » Mon Mar 25, 2019 8:23 pm

Thanks,

It did help me achieve 200Hz.

e2738729
Posts: 35
Joined: Mon Nov 05, 2018 6:22 pm

Re: Timer Interrupt cannot Run Faster than 100Hz?

Postby e2738729 » Sat Mar 30, 2019 4:30 am

Hi,

So it seems the interrupt-triggered task is able to run 200Hz when there are no other lower priority tasks running alongside. Since I have 2 other tasks run along with the interrupt-triggered task, sometimes the interrupt-triggered task was not able to run at the precise timing due to being placed in ready mode until the running (active) task finished.

Is there away I can synchronize other tasks such that their execution time won't interfere with the interrupt-triggered task? The 200Hz requirement is absolute for my application.

Thanks

ESP_Sprite
Posts: 9043
Joined: Thu Nov 26, 2015 4:08 am

Re: Timer Interrupt cannot Run Faster than 100Hz?

Postby ESP_Sprite » Sat Mar 30, 2019 7:19 am

You should be able to do that by raising the priority of your task to be above that of the other tasks: as FreeRTOS is pre-emptive, it will immedately give control to the task blocking on the semaphore you give in the interrupt, given that the priority of the task waiting on it has a higher priority than the currently running task.

(Note that there's one exception here, which is flash writes. As the ESP32 runs the majority of it's program 'directly' off flash, a flash write will stop effectively all tasks.)

e2738729
Posts: 35
Joined: Mon Nov 05, 2018 6:22 pm

Re: Timer Interrupt cannot Run Faster than 100Hz?

Postby e2738729 » Sat Mar 30, 2019 2:43 pm

Thanks for your help.

You mentioned flash write in the last reply, and I wonder what this really mean.

Is there a task that runs flash write in the background? How do I know how often this task (if exists) runs? Is there away that I can maintain 200Hz task precisely?

I really appreciate if you could direct me to more readings/info regarding this.

ESP_Sprite
Posts: 9043
Joined: Thu Nov 26, 2015 4:08 am

Re: Timer Interrupt cannot Run Faster than 100Hz?

Postby ESP_Sprite » Sun Mar 31, 2019 5:33 am

No, flash is only done when needed. NVS writes to flash (when you save a variable, sometimes WiFi also does this on connect), SPIFFS writes write to flash, fatfs writes can write to flash.

Who is online

Users browsing this forum: No registered users and 61 guests