Page 1 of 1

Getting Guru Meditation Exception while using Hardware Timer

Posted: Thu Jun 29, 2017 1:17 pm
by Ritesh
Hi All,

As we are developing one application on ESP32 and we have used ESP32 2.0 Official Release for SDK base, We are getting Guru Meditation Exception randomly in application while using Hardware Timer.

We have used Hardware Timer based on example provided with some our modifications.

Please find below Hardware Timer code which we are right now using in our application.

Code: Select all

#define ONE_SEC_TIMER_INTERVAL  4999993

/*
 * @brief timer group0 hardware timer0 init
 */
void tg0_timer0_init()
{
    // int timer_group = TIMER_GROUP_0;
    int timer_idx = TIMER_0;
    timer_config_t config;
    config.alarm_en = 1;
    config.auto_reload = 1;
    config.counter_dir = TIMER_COUNT_UP;
    config.divider = TIMER_DIVIDER;
    config.intr_type = TIMER_INTR_SEL;
    config.counter_en = TIMER_PAUSE;
	
	timer_interval = ONE_SEC_TIMER_INTERVAL;
	
	
    /*Configure timer*/
    timer_init(timer_group, timer_idx, &config);
    /*Stop timer counter*/
    timer_pause(timer_group, timer_idx);
    /*Load counter value */
    timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL);
    /*Set alarm value*/
    timer_set_alarm_value(timer_group, timer_idx, timer_interval);
    /*Enable timer interrupt*/
    timer_enable_intr(timer_group, timer_idx);
    /*Set ISR handler*/
    timer_isr_register(timer_group, timer_idx, low_freq_isr, (void*) timer_idx, ESP_INTR_FLAG_IRAM, NULL);
    /*Start timer counter*/
    timer_start(timer_group, timer_idx);
}

void tg0_timer1_init()
{
    // int timer_group = TIMER_GROUP_0;
    int timer_idx = TIMER_1;
    timer_config_t config;
    config.alarm_en = 1;
    config.auto_reload = 1;
    config.counter_dir = TIMER_COUNT_UP;
    config.divider = TIMER_DIVIDER;
    config.intr_type = TIMER_INTR_SEL;
    config.counter_en = TIMER_PAUSE;
	
	timer_interval = ONE_SEC_TIMER_INTERVAL;
	
    /*Configure timer*/
    timer_init(timer_group, timer_idx, &config);
    /*Stop timer counter*/
    timer_pause(timer_group, timer_idx);
    /*Load counter value */
    timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL);
    /*Set alarm value*/
    timer_set_alarm_value(timer_group, timer_idx, timer_interval);
    /*Enable timer interrupt*/
    timer_enable_intr(timer_group, timer_idx);
    /*Set ISR handler*/
    timer_isr_register(timer_group, timer_idx, high_freq_isr, (void*) timer_idx, ESP_INTR_FLAG_IRAM, NULL);
    /*Start timer counter*/
    timer_start(timer_group, timer_idx);
}

/*
 * @brief timer group0 ISR handler
   NOTE : must use IRAM_ATTR in isr function defineation,
 */
void IRAM_ATTR high_freq_isr(void *para)
{
	static char high_freq = 0;
    int timer_idx = (int) para;
    // uint32_t intr_status = TIMERG0.int_st_timers.val;
    // timer_event_t evt;

	if(high_freq == 0)
	{
		if(CHECK_LED_STATUS(WifiLed) == LEDFREQSTAT_HIGH_FRQ)
		{
			// printf("led off for 500 ms in high isr\r\n");
			gpio_set_level(WIFI_LED, 1);
		}
		if(CHECK_LED_STATUS(BLled) == LEDFREQSTAT_HIGH_FRQ)
		{
			// printf("led off for 500 ms in high isr\r\n");
			gpio_set_level(WIFI_LED, 1);
		}
		high_freq = 1;
		timer_high_frq_modified = ONE_SEC_TIMER_INTERVAL/2;
	}
	else if(high_freq == 1)
	{
		if(CHECK_LED_STATUS(WifiLed) == LEDFREQSTAT_HIGH_FRQ)
		{
			// printf("led on for 100 ms in high isr\r\n");
			gpio_set_level(WIFI_LED, 0);
		}
		if(CHECK_LED_STATUS(BLled) == LEDFREQSTAT_HIGH_FRQ)
		{
			// printf("led on for 100 ms in high isr\r\n");
			gpio_set_level(WIFI_LED, 0);
		}
		timer_high_frq_modified = ONE_SEC_TIMER_INTERVAL/10;
		high_freq = 0;
	}

	if (timer_idx==1) {
        TIMERG0.int_clr_timers.t1 = 1;
		timer_set_alarm_value(timer_group, timer_idx, timer_high_frq_modified);
        TIMERG0.hw_timer[1].update=1;
        TIMERG0.hw_timer[1].config.alarm_en = 1;
    }
}

/*
 * @brief timer group0 ISR handler
   NOTE : must use IRAM_ATTR in isr function defineation,
 */
void IRAM_ATTR low_freq_isr(void *para)
{
	static char low_freq = 0;
    int timer_idx = (int) para;
    // uint32_t intr_status = TIMERG0.int_st_timers.val;
    // timer_event_t evt;
	// timer_interval_modified = ONE_SEC_TIMER_INTERVAL/2;
	if(low_freq == 0)
	{
		if(CHECK_LED_STATUS(WifiLed) == LEDFREQSTAT_LOW_FRQ)
		{
			// printf("led off for 2000 ms in low isr\r\n");
			gpio_set_level(WIFI_LED, 1);
		}
		if(CHECK_LED_STATUS(BLled) == LEDFREQSTAT_LOW_FRQ)
		{
			// printf("led off for 2000 ms in low isr\r\n");
			gpio_set_level(WIFI_LED, 1);
		}
		low_freq = 1;
		timer_low_frq_modified = ONE_SEC_TIMER_INTERVAL*2;
	}
	else if(low_freq == 1)
	{
		if(CHECK_LED_STATUS(WifiLed) == LEDFREQSTAT_LOW_FRQ)
		{
			// printf("led on for 100 ms in low isr\r\n");
			gpio_set_level(WIFI_LED, 0);
		}
		if(CHECK_LED_STATUS(BLled) == LEDFREQSTAT_LOW_FRQ)
		{
			// printf("led on for 100 ms in low isr\r\n");
			gpio_set_level(WIFI_LED, 0);
		}
		timer_low_frq_modified = ONE_SEC_TIMER_INTERVAL/10;
		low_freq = 0;
	}

	if (timer_idx==0) {
        TIMERG0.int_clr_timers.t0 = 1;
		timer_set_alarm_value(timer_group, timer_idx, timer_low_frq_modified);
        TIMERG0.hw_timer[0].update=1;
        TIMERG0.hw_timer[0].config.alarm_en = 1;
    }
}
So, We have checked exceptions and found that we are getting last back-trace call as timer_set_alarm_value.
xtensa-esp32-elf-addr2line.exe -pfia -e /e/build/app-template.elf 0x4011271e:0x3ffb05e0 0x400814e0:0x3ffb0600
0x4011271e: timer_set_alarm_value at E:/esp-idf-v2.0/components/driver/timer.c:264
0x400814e0: _xt_lowint1 at xtensa_vectors.o:?
After that we have replaced Hardware Timer with Software Timer using xTimerCreate and it works fine without any issue. So, It seems like issue might be Hardware Timer Component which we are using in our application code for Timer feature.

Please let me know if anyone has faced this type of issue or any clue/info to solve this issue without using Hardware Timer.

Re: Getting Guru Meditation Exception while using Hardware Timer

Posted: Thu Jun 29, 2017 6:40 pm
by WiFive
timer_set_alarm_value is not IRAM_ATTR function. Check methods inside ISR in example


https://github.com/espressif/esp-idf/bl ... ple_main.c

Re: Getting Guru Meditation Exception while using Hardware Timer

Posted: Thu Jun 29, 2017 11:14 pm
by Ritesh
WiFive wrote:timer_set_alarm_value is not IRAM_ATTR function. Check methods inside ISR in example


https://github.com/espressif/esp-idf/bl ... ple_main.c
Hi,

I didn't get your point. We have followed Hardware Timer concept based on example provided with some ISR related modifications.

So that timer_set_alarm_value has been called from timer init API.

Please explain in details why Exception has been generated while using Hardware Timer.

Re: Getting Guru Meditation Exception while using Hardware Timer

Posted: Fri Jun 30, 2017 12:12 am
by WiFive
Check inside your 2 ISR for timer_set_alarm_value

Re: Getting Guru Meditation Exception while using Hardware Timer

Posted: Fri Jun 30, 2017 1:29 am
by Ritesh
WiFive wrote:Check inside your 2 ISR for timer_set_alarm_value
So, How can I set alarm value in my both ISR calls?

Re: Getting Guru Meditation Exception while using Hardware Timer

Posted: Fri Jun 30, 2017 5:27 am
by WiFive
Do it the way the example does in the ISR by setting timer struct members directly. Which is what I said the first time.

Re: Getting Guru Meditation Exception while using Hardware Timer

Posted: Fri Jun 30, 2017 5:52 am
by ESP_igrr
Alternatively, replace ESP_INTR_FLAG_IRAM with ESP_INTR_FLAG_DEFAULT when you are registering the interrupt. Then the interrupt will be automatically disabled at times when cache is disabled. You will be able to call non-IRAM functions from ISR in this case.

Re: Getting Guru Meditation Exception while using Hardware Timer

Posted: Fri Jun 30, 2017 7:17 am
by Ritesh
WiFive wrote:Do it the way the example does in the ISR by setting timer struct members directly. Which is what I said the first time.
Hi,

Thanks for quick reply. I will check and let you know result for that.

Re: Getting Guru Meditation Exception while using Hardware Timer

Posted: Fri Jun 30, 2017 7:17 am
by Ritesh
ESP_igrr wrote:Alternatively, replace ESP_INTR_FLAG_IRAM with ESP_INTR_FLAG_DEFAULT when you are registering the interrupt. Then the interrupt will be automatically disabled at times when cache is disabled. You will be able to call non-IRAM functions from ISR in this case.
Hi,

Thanks for quick reply. I will check and let you know result for that.