Using esp_timer to create another one-shot from the call back of another one-shot

chadpham75
Posts: 48
Joined: Thu Sep 12, 2019 11:39 am

Using esp_timer to create another one-shot from the call back of another one-shot

Postby chadpham75 » Thu Sep 12, 2019 11:57 am

I am using esp_timer one-shot timer, and I am looking for a solution to create/start another one-shot timer from a call back of another one-shot.
The use case is:
I have 3 RGB LED, each of them can blink at different rate, and I am using LEDC/PWM to control the intensity for these 3 LEDs.
The requirement is these 3 LEDs can be independently turn on and turn off base on the input of the LED_Set() custom function.

Below is my code starting from the esp-idf/examples/system/esp_timer/main/esp_timer_example_main.c example

Code: Select all

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "esp_timer.h"
#include "esp_log.h"
#include "esp_sleep.h"
#include "sdkconfig.h"

typedef struct
{
	bool bOnOff;
	uint64_t tOn;
	uint64_t tOff;
	esp_timer_handle_t savedHandle;
} CONTEXT;

CONTEXT gLED;

static void oneshot_timer_callback(void* arg);

static const char* TAG = "example";

void app_main()
{
	gLED.bOnOff = true;
	gLED.tOn    = 5000000;
	gLED.tOff   = 1000000;

	esp_timer_handle_t oneshot_timer;
	gLED.savedHandle  = oneshot_timer;

	const esp_timer_create_args_t oneshot_timer_args = {
			.callback = &oneshot_timer_callback,
			.arg      = (void *)&gLED,
			.name = "one shot"
	};

	ESP_ERROR_CHECK(esp_timer_create(&oneshot_timer_args, &oneshot_timer));

	/* Start the timers */
	ESP_ERROR_CHECK(esp_timer_start_once(oneshot_timer, gLED.tOn));
	ESP_LOGI(TAG, "Started timers, time since boot: %lld us", esp_timer_get_time());


	/* Print debugging information about timers to console every 2 seconds */
	for (int i = 0; i < 20; ++i) {
		ESP_ERROR_CHECK(esp_timer_dump(stdout));
		usleep(2000000);
	}

}

static void oneshot_timer_callback(void* arg)
{
    int64_t time_since_boot = esp_timer_get_time();
    ESP_LOGI(TAG, "One-shot timer called, time since boot: %lld us", time_since_boot);

    CONTEXT* pst = (CONTEXT *)arg;
    esp_timer_handle_t current = pst->savedHandle;

    uint64_t timeonoff;

    if(pst->bOnOff) {
    	pst->bOnOff = false;
    	timeonoff = pst->tOff;
    	ESP_LOGI(TAG, "Turn off LED for %lld us", timeonoff);
    }
    else {
    	pst->bOnOff = true;
    	timeonoff = pst->tOn;
    	ESP_LOGI(TAG, "Turn on LED for %lld us", timeonoff);
    }

    ESP_ERROR_CHECK(esp_timer_delete(current));

    esp_timer_handle_t new_oneshot_timer;
    pst->savedHandle  = new_oneshot_timer;

    const esp_timer_create_args_t oneshot_timer_args = {
    	.callback = &oneshot_timer_callback,
    	.arg      = (void *)pst,
    	.name = "new one shot"
    };

    ESP_ERROR_CHECK(esp_timer_create(&oneshot_timer_args, &new_oneshot_timer));

    /* Start the timers */
    ESP_ERROR_CHECK(esp_timer_start_once(new_oneshot_timer, timeonoff));
    ESP_LOGI(TAG, "Started new one shot timer, time since boot: %lld us", esp_timer_get_time());
}
However, when I ran this code the code is crashed and rebooting
I (235) cpu_start: Starting scheduler on PRO CPU.
I (236) example: Started timers, time since boot: 1621 us
one shot 0 5001612 1 0 0
one shot 0 5001612 1 0 0
one shot 0 5001612 1 0 0
I (5236) example: One-shot timer called, time since boot: 5001656 us
I (5236) example: Turn off LED for 1000000 us
Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x40080f2b PS : 0x00060630 A0 : 0x800d0b54 A1 : 0x3ffaf9a0
0x40080f2b: timer_armed at C:/Users/paviliondv7/Desktop/esp-idf/components/esp32/esp_timer.c:427

A2 : 0x80083bcc A3 : 0x3ffafb60 A4 : 0x3ffaf9a0 A5 : 0x0000000c
A6 : 0x00000000 A7 : 0x00060023 A8 : 0x800e1e4c A9 : 0x3ffaf650
A10 : 0x00000039 A11 : 0x3ffae910 A12 : 0x00000001 A13 : 0x3ffaf660
A14 : 0x3ffaf660 A15 : 0x00000003 SAR : 0x00000004 EXCCAUSE: 0x0000001c
EXCVADDR: 0x80083bcc LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xfffffffd

Backtrace: 0x40080f2b:0x3ffaf9a0 0x400d0b51:0x3ffaf9c0 0x400d1db7:0x3ffaf9e0 0x400d0a1c:0x3ffafa30 0x400d0abb:0x3ffafa50 0x40083bc9:0x3ffafa70
0x40080f2b: timer_armed at C:/Users/paviliondv7/Desktop/esp-idf/components/esp32/esp_timer.c:427

0x400d0b51: esp_timer_delete at C:/Users/paviliondv7/Desktop/esp-idf/components/esp32/esp_timer.c:427

0x400d1db7: oneshot_timer_callback at C:\Users\paviliondv7\Desktop\esp-idf\esp_timer\build/../main/esp_timer_example_main.c:83

0x400d0a1c: timer_process_alarm at C:/Users/paviliondv7/Desktop/esp-idf/components/esp32/esp_timer.c:427

0x400d0abb: timer_task at C:/Users/paviliondv7/Desktop/esp-idf/components/esp32/esp_timer.c:427

0x40083bc9: vPortTaskWrapper at C:/Users/paviliondv7/Desktop/esp-idf/components/freertos/port.c:403


Rebooting...
ets Jun 8 2016 00:22:57
Please help.

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

Re: Using esp_timer to create another one-shot from the call back of another one-shot

Postby ESP_Sprite » Sat Sep 14, 2019 7:59 am

Code: Select all

    esp_timer_handle_t new_oneshot_timer;
    pst->savedHandle  = new_oneshot_timer;
    ESP_ERROR_CHECK(esp_timer_create(&oneshot_timer_args, &new_oneshot_timer));
new_oneshot_timer is on the stack. You then assign the value of the (uninitialized) handle to savedHandle, which is pretty useless. The timer is created with new_oneshot as an arg, saving the timer handle into new_oneshot_timer. That variable disappears at the end of the function.

chadpham75
Posts: 48
Joined: Thu Sep 12, 2019 11:39 am

Re: Using esp_timer to create another one-shot from the call back of another one-shot

Postby chadpham75 » Tue Sep 17, 2019 6:12 am

Thank you.
I should have done
esp_timer_handle_t new_oneshot_timer;
ESP_ERROR_CHECK(esp_timer_create(&oneshot_timer_args, &new_oneshot_timer));
pst->savedHandle = new_oneshot_timer; //store the handle

chadpham75
Posts: 48
Joined: Thu Sep 12, 2019 11:39 am

Re: Using esp_timer to create another one-shot from the call back of another one-shot

Postby chadpham75 » Tue Sep 24, 2019 10:36 am

Hi ESP_Sprite,
I also to the system crashes everytime I try to delete the one-shot timer handle.
Could you please help to point it out for me what I may miss?

When I created one-shot timer
{
esp_timer_handle_t buzzer_oneshot_timer;
const esp_timer_create_args_t oneshot_timer_args =
{
.callback = &OneShot_Timer_CB,
.arg = (void* )(pTimerHandle),
.name = "one-shot-buzzer"
};

//Create one-shot timer
ESP_ERROR_CHECK(esp_timer_create(&oneshot_timer_args, &buzzer_oneshot_timer));
pTimerHandle = buzzer_oneshot_timer;
ESP_ERROR_CHECK(esp_timer_start_once(buzzer_oneshot_timer, wtOn));
}

Just to clean up the handle
static void OneShot_Timer_CB(void *arg)
{
esp_timer_handle_t pst = (esp_timer_handle_t)arg;
//handle the call back
if(ESP_OK == esp_timer_stop(pst)) {
ESP_ERROR_CHECK(esp_timer_delete(pst));
}
}

Without the esp_timer_delete, my code didn't get crashed. I wonder my method of passing the handle back to CB function is correct?
Thank you so much for your time.

Who is online

Users browsing this forum: asargent, Bing [Bot] and 108 guests