Page 1 of 1

Generate signal with timer

Posted: Fri Apr 12, 2024 8:12 am
by espmajds
I'm trying to generate a 100 kHz signal with ESP32 timers.
I tried to do this with the gptimer but the ESP32 keeps resetting!
Which timer can I use for this? How?

Re: Generate signal with timer

Posted: Fri Apr 12, 2024 10:13 am
by MicroController
saeidi_majid wrote:
Fri Apr 12, 2024 8:12 am
I'm trying to generate a 100 kHz signal with ESP32 timers.
That's not going to happen.
Which timer can I use for this? How?
Look into generating PWM in hardware, e.g. via the LEDC peripheral.

Re: Generate signal with timer

Posted: Fri Apr 12, 2024 10:42 am
by espmajds
I tested it with LEDC and it works properly, but I want to know how to do it with GPTimer functions.
I've set the timer resolution to 1MHz, so each tick equals 1 microsecond. Therefore, if I set the alarm count value to 10, an interrupt occurs every 10 microseconds, during which I can toggle a port get my frequency
Now, when I do this, the ESP32 resets.
  1. #include <stdio.h>
  2. #include "freertos/FreeRTOS.h"
  3. #include "freertos/task.h"
  4. #include "freertos/queue.h"
  5. #include "driver/gptimer.h"
  6. #include "driver/gpio.h"
  7.  
  8. #define FREQ_OUT_PIN     GPIO_NUM_5
  9.  
  10. static QueueHandle_t timer_alarm_queue = NULL;
  11.  
  12. gptimer_handle_t gptimer = NULL;
  13.  
  14. typedef struct {
  15.     uint64_t event_count;
  16.     uint64_t event_alarm;
  17. }queue_element_t;
  18.  
  19. //************************************************************************************************************
  20. static bool IRAM_ATTR timrt_alarm_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
  21. {
  22.     BaseType_t high_task_awoken = pdFALSE;
  23.  
  24.     queue_element_t queue_data = {
  25.             .event_count = edata->count_value,
  26.             .event_alarm = edata->alarm_value,
  27.     };
  28.  
  29.     xQueueSendFromISR(timer_alarm_queue, &queue_data, &high_task_awoken);
  30.    
  31.     return (high_task_awoken == pdTRUE);
  32. }
  33.  
  34. //************************************************************************************************************
  35. static void timer_alarm_task(void* arg)
  36. {
  37.     int isOn = 0;
  38.     queue_element_t data;
  39.  
  40.     while (true)
  41.     {
  42.         if(xQueueReceive(timer_alarm_queue, &data, portMAX_DELAY))
  43.         {
  44.             isOn =! isOn;
  45.             gpio_set_level(LED_GPIO, isOn);
  46.         }
  47.     }
  48. }
  49.  
  50. //************************************************************************************************************
  51. void app_main(void)
  52. {
  53.     gpio_set_direction(LED_GPIO, GPIO_MODE_OUTPUT);
  54.  
  55.     gptimer_config_t timer_config = {
  56.             .clk_src = GPTIMER_CLK_SRC_APB,
  57.             .direction = GPTIMER_COUNT_UP,
  58.             .resolution_hz = 1000000,
  59.             .intr_priority = 0,
  60.             .flags.intr_shared = false,
  61.     };
  62.  
  63.     gptimer_new_timer(&timer_config, &gptimer);
  64.  
  65.     gptimer_event_callbacks_t timerCallback = {
  66.             .on_alarm = timrt_alarm_callback,
  67.     };
  68.  
  69.     gptimer_register_event_callbacks(gptimer, &timerCallback, NULL);
  70.  
  71.     gptimer_alarm_config_t alarm_config = {
  72.             .alarm_count = 5000,
  73.             .reload_count = 0,
  74.             .flags.auto_reload_on_alarm = true,
  75.     };
  76.  
  77.     gptimer_set_alarm_action(gptimer, &alarm_config);
  78.  
  79.     timer_alarm_queue = xQueueCreate(1, sizeof(uint32_t));
  80.  
  81.     xTaskCreate(timer_alarm_task, "timer_alarm_task", 2048, NULL, 5, NULL);
  82.  
  83.     gptimer_enable(gptimer);
  84.  
  85.     gptimer_start(gptimer);
  86.  
  87.  
  88.     while(1)
  89.     {
  90.         vTaskDelay(1000 / portTICK_PERIOD_MS);
  91.     }
  92. }

Re: Generate signal with timer

Posted: Fri Apr 12, 2024 1:18 pm
by MicroController
an interrupt occurs every 10 microseconds
This is the actual problem. When accounting for the overhead of entering and exiting an ISR plus the xQueueSendFromISR(...), plus the context switch to the timer_alarm_task, 10us won't leave much time, if any, for anything else on that CPU core. I don't know if that's actually what causes the resets in your case (e.g. by angering the watchdog timer), but 100kHz is still likely too much for an ISR; and if it doesn't crash the system, the jitter in signal timing you'd get is probably inacceptable.
However, you can try to do the GPIO toggling directly from the ISR instead of communicating to a task to significantly reduce the overhead.

Re: Generate signal with timer

Posted: Fri Apr 12, 2024 1:50 pm
by espmajds
I directly changed the GPIO from the ISR, but it resets again.
The ESP32 has a high operating frequency, which is why it surprises me why this is happening!
What is your suggestion for generating 100 kilohertz frequency other than LEDC?
Do you have any sample code
Thanks

Re: Generate signal with timer

Posted: Fri Apr 12, 2024 2:41 pm
by ESP_Sprite
Do you have an issue specific with the LEDC? If so, you can also use the MCPWM or the RMT, or even hack stuff up using e.g. I2s, to generate such a signal. If you specifically want to generate a signal using a software interrupt, it would really help if you would tell us why exactly. (And the answer might be: 'you can't'. The features that make the ESP32 core very fast, also make it a bit sluggish when it comes to interrupt handling and context switching. That is why they have so many flexible peripherals on board, like the LEDC.)

Re: Generate signal with timer

Posted: Fri Apr 12, 2024 3:35 pm
by espmajds
I don't have any issues with LEDC. in fact, I wanted to set up an ultrasonic SR-04 module, which actually worked fine with LEDC. However, as I'm currently learning ESP-IDF and reading the GPTimer documentation, I tried to generate 100 kHz frequency for the SR-04 using GPTimer to get familiar with different methods and applications of GPTimer.

I have another question about GPTimer.
Since the ESP32 has two Timer groups, each containing 2 timers, how can I configure a different setup and a separate ISR for each?

Thanks.

Re: Generate signal with timer

Posted: Sat Apr 13, 2024 7:57 am
by espmajds
I don't understand! What's the relationship between GPTimer and Timer Group?
If a timer group includes 4 timers, then which one does GPTimer work with?
And do I need to use multiple gptimer_handle_t with different configurations to create multiple timers with GPTimer?

Re: Generate signal with timer

Posted: Sun Apr 14, 2024 1:16 am
by ESP_Sprite
Not sure where you get that a timer group contains 4 timers. From the TRM: 'The ESP32 contains two timer modules, each containing two timers. '. In general, the gptimer driver abstracts away over this: if you ask it for a timer, it'll give you the first one that is free.