Page 1 of 2

binary semaphore doesn't work if created in task that uses it ?

Posted: Mon Jan 15, 2018 5:21 am
by pataga
I am using a binary semaphore given from an isr that notifies a task to read new data from a device. The device generates data ready interrupts at approximately 400Hz, so the task should be also getting notifications from the semaphore at the same rate.

If i create the global semaphore in the task that uses it, then the task gets notifications at roughly the FreeRTOS tick rate ( in this case, 500Hz ) with some gaps.

If i create the semaphore in app_main before creating the task that uses it, everything works as expected, the notifications are processed at the data ready interrupt rate (~400Hz) without missing any.

Not sure if this is correct behavior, in any case, it would be nice to have an explanation.

Code: Select all

volatile SemaphoreHandle_t imuSemaphore;
	

void drdyHandler(void) {
	xSemaphoreGiveFromISR(imuSemaphore, NULL);
	}
	
static void imu_task() {

        // does not work if created here !
	//imuSemaphore = xSemaphoreCreateBinary();
	//attachInterrupt(pinDRDYINT, drdyHandler, RISING);

	// initialize device to generate data and data  ready interrupts ...

	while (1) {		
		if (xSemaphoreTake(imuSemaphore, portMAX_DELAY)) {
			LED_ON();
			// read the data from device
			LED_OFF();
			}
		}  
	}	


void app_main() {
	// init stuff ...
	
	// works if semaphore created here
	imuSemaphore = xSemaphoreCreateBinary();
	attachInterrupt(pinDRDYINT, drdyHandler, RISING);
	
	xTaskCreatePinnedToCore(&imu_task, "imutask", 2048, NULL, 20, NULL, 1);
	
	while(1) {
	        // do some stuff			
		delayMs(30);
		}		
	}
	
	
sem_good.png
sem_good.png (10.91 KiB) Viewed 15529 times
sem_bad.png
sem_bad.png (15.8 KiB) Viewed 15529 times

Re: binary semaphore doesn't work if created in task that uses it ?

Posted: Mon Jan 15, 2018 8:03 am
by ESP_Sprite
Do you get the same weird behaviour if you pin the task to CPU 0 instead of 1?

Re: binary semaphore doesn't work if created in task that uses it ?

Posted: Mon Jan 15, 2018 11:16 am
by pataga
Do you get the same weird behaviour if you pin the task to CPU 0 instead of 1?
OK, this is even stranger. If I pin the task to cpu 0, then the notification doesn't work correctly whether I create the semaphore and register the handler in app_main or in the task initialization code.

In both cases, I get the notifications at 500Hz with some skips every 3 or 4 notifications.

Went back to original configuration with task pinned to core 1 and semaphore/isr registration in app_main, and it works fine.
So at least my working configuration is repeatable :-D

Am using esp-idf downloaded on Jan 11.

Re: binary semaphore doesn't work if created in task that uses it ?

Posted: Mon Jan 15, 2018 12:44 pm
by ESP_igrr
Please don't forget to pass 2nd BOOL* argument to xSemaphoreGiveFromISR and call portYIELD_FROM_ISR if it gets set to pdTRUE.
If you don't do that, preemption will only happen on the next FreeRTOS tick.

Re: binary semaphore doesn't work if created in task that uses it ?

Posted: Mon Jan 15, 2018 1:55 pm
by pataga
Please don't forget to pass 2nd BOOL* argument to xSemaphoreGiveFromISR and call portYIELD_FROM_ISR if it gets set to pdTRUE.
If you don't do that, preemption will only happen on the next FreeRTOS tick.
Ah ... so i was using it wrong all this time ! I found a correct example of semaphore usage, and fixed the ISR

Code: Select all

void drdyHandler(void) {
	static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	xSemaphoreGiveFromISR(imuSemaphore, &xHigherPriorityTaskWoken);
    if( xHigherPriorityTaskWoken == pdTRUE) {
        portYIELD_FROM_ISR(); // this wakes up imu_task immediately instead of on next FreeRTOS tick
		}
	}
	
and now it works fine. Thanks much ...

Re: binary semaphore doesn't work if created in task that uses it ?

Posted: Mon Jan 15, 2018 3:52 pm
by ESP_igrr
Good to know. The variable does not need to be static, by the way.

Re: binary semaphore doesn't work if created in task that uses it ?

Posted: Wed Jan 30, 2019 8:50 pm
by JPMJPM
I have the same problem with an interrupt every 125 uS from a HW timer.

Any help ?.

Regards.

Code: Select all

SemaphoreHandle_t I2CSemaphore = NULL;

void IRAM_ATTR timer_group0_isr(void *para) {
	int timer_idx = (int) para;
  	uint32_t intr_status = TIMERG0.int_st_timers.val;
    	if((intr_status & BIT(timer_idx)) && timer_idx == TIMER_0) {
      		TIMERG0.hw_timer[timer_idx].update = 1;
		TIMERG0.int_clr_timers.t0 = 1;
      		TIMERG0.hw_timer[timer_idx].config.alarm_en = 1;
			
      		//gpio_set_level(test_pin, temp);
      		//temp = !temp;

		BaseType_t xHigherPriorityTaskWoken = pdFALSE;
		xSemaphoreGiveFromISR(I2CSemaphore, &xHigherPriorityTaskWoken);
    		if( xHigherPriorityTaskWoken == pdTRUE) {
        		portYIELD_FROM_ISR();
		}

		//xSemaphoreGiveFromISR(I2CSemaphore, NULL);
	}
}

static void IRAM_ATTR I2Chandler(void *pvParameter) {
	while (1) {
    		if (xSemaphoreTake(I2CSemaphore, portMAX_DELAY) == pdTRUE) {
			gpio_set_level(test_pin, temp);
      			temp = !temp;
    		}
  	}
}

void app_main() {

	I2CSemaphore = xSemaphoreCreateBinary();

	xTaskCreatePinnedToCore(&I2Chandler, "I2Chandler", 2048, NULL, 10, NULL, 1);

	example_tg0_timer0_init();
}
ok.png
gpio_set_level() only inside timer_group0_isr()
ok.png (4.74 KiB) Viewed 14348 times
error.png
gpio_set_level() only inside I2Chandler()
error.png (7.11 KiB) Viewed 14348 times

Re: binary semaphore doesn't work if created in task that uses it ?

Posted: Thu Jan 31, 2019 7:30 am
by ESP_Sprite
If anything, this is not the same problem, as if it were I'd expect the toggle rate to be the FreeRTOS tick frequency (depends on your configuration, but max 1KHz.) Do you happen to do stuff that writes to the flash? Because that will disable your interrupt and task temporarily.

Re: binary semaphore doesn't work if created in task that uses it ?

Posted: Thu Jan 31, 2019 11:50 am
by JPMJPM
There is not stuff that writes to the flash.

Anyway I changed FreeRTOS tick frequency from 100 Hz to 1 KHz in menuconfig
but the problem persists.

Re: binary semaphore doesn't work if created in task that uses it ?

Posted: Fri Feb 01, 2019 3:02 am
by ESP_Sprite
Can you try initializing the timer on CPU 1? (Put example_tg0_timer0_init(); within the task that you created, instead of in main.)