How to guard time critical sections from RTOS interrupts?
How to guard time critical sections from RTOS interrupts?
Postby btomic » Thu Apr 05, 2018 6:15 am
I'm using ESP8266_RTOS_SDK and the 1-Wire bus to connect with DS18B20 temperature sensors. When the wifi is in STATION_MODE there are occasional CRC errors when reading the temperature value from the sensors. When the wifi is turned off (i.e. in NULL_MODE) there are no errors at all.
The 1-wire bus is timing sensitive and some operations must not be interrupted. All sensitive portions of the code (which last for about 60 us) are guarded by the taskENTER_CRITICAL/taskEXIT_CRITICAL pair but the problem still occurs. It looks like that wifi interrupts are still interrupting critical sections and affecting critical timing on the 1-Wire bus.
I tried instead to guard critical sections with taskDISABLE_INTERRUPTS/taskENABLE_INTERRUPTS pair but the problem is still there. In this case the scheduler can still interrupt the critical sections. An attempt to both disable interrupts and use taskENTER_CRITICAL does not work at all.
Is there any way in ESP8266_RTOS_SDK to absolutely protect critical sections from high priority wifi interrupts (and still using the wifi)?
The 1-wire bus is timing sensitive and some operations must not be interrupted. All sensitive portions of the code (which last for about 60 us) are guarded by the taskENTER_CRITICAL/taskEXIT_CRITICAL pair but the problem still occurs. It looks like that wifi interrupts are still interrupting critical sections and affecting critical timing on the 1-Wire bus.
I tried instead to guard critical sections with taskDISABLE_INTERRUPTS/taskENABLE_INTERRUPTS pair but the problem is still there. In this case the scheduler can still interrupt the critical sections. An attempt to both disable interrupts and use taskENTER_CRITICAL does not work at all.
Is there any way in ESP8266_RTOS_SDK to absolutely protect critical sections from high priority wifi interrupts (and still using the wifi)?
Re: How to guard time critical sections from RTOS interrupts?
Postby cranphin » Tue Jul 23, 2019 5:54 am
I'm having similar issues. What did work for me is setting the task at the highest priority (Above wifi task), in my case 15.
But this is not recommended :)
See also (for system task prio's): https://docs.espressif.com/projects/esp ... tasks.html
But this is not recommended :)
See also (for system task prio's): https://docs.espressif.com/projects/esp ... tasks.html
Re: How to guard time critical sections from RTOS interrupts?
Postby cranphin » Sun Aug 11, 2019 10:21 pm
Small update, that still doesn't work so well if you start transmitting data over wifi :)
What does seem to work is including <xtensa/xtruntime.h>, and replacing taskENTER_CRITICAL/taskEXIT_CRITICAL with:
uint32_t savedLevel = XTOS_DISABLE_ALL_INTERRUPTS;
XTOS_RESTORE_INTLEVEL(savedLevel);
It does mostly the same (feel free to look at the source code, it's all in the SDK), except it disables all interrupt levels.
Of course this is probably very dangerous :)
It would be great if we could get a suggestion from Espressif on what the best approach would be here. I'm really not sure exactly what I'm doing here, and things like interrupts and their levels and what they do for WiFi are hardly well documented :)
I'm sure the official statement would be esp8266 is meant for WIFI, not accurate timing.
But what made the esp8266 so interesting for hobby projects is being able to do stuff like bit banging 1-wire temperature sensors, it would be nice if we could do that in the RTOS SDK too, since it seems to be getting the most love from Espressif at the moment :)
Ofcourse if someone there could get away with writing a good onewire driver as sample in the SDK, that would be even better ;)
Nice summer project? :D
What does seem to work is including <xtensa/xtruntime.h>, and replacing taskENTER_CRITICAL/taskEXIT_CRITICAL with:
uint32_t savedLevel = XTOS_DISABLE_ALL_INTERRUPTS;
XTOS_RESTORE_INTLEVEL(savedLevel);
It does mostly the same (feel free to look at the source code, it's all in the SDK), except it disables all interrupt levels.
Of course this is probably very dangerous :)
It would be great if we could get a suggestion from Espressif on what the best approach would be here. I'm really not sure exactly what I'm doing here, and things like interrupts and their levels and what they do for WiFi are hardly well documented :)
I'm sure the official statement would be esp8266 is meant for WIFI, not accurate timing.
But what made the esp8266 so interesting for hobby projects is being able to do stuff like bit banging 1-wire temperature sensors, it would be nice if we could do that in the RTOS SDK too, since it seems to be getting the most love from Espressif at the moment :)
Ofcourse if someone there could get away with writing a good onewire driver as sample in the SDK, that would be even better ;)
Nice summer project? :D
Re: How to guard time critical sections from RTOS interrupts?
Postby cranphin » Wed Aug 14, 2019 5:02 am
Still a small update, I'm using the code below now, and -still- I get small 10us delays in my time critical section :)
(At the same time, MQTT WiFi sends are running)
Task which runs the code:
Includes/defines
The method with the critical section
(At the same time, MQTT WiFi sends are running)
Task which runs the code:
Code: Select all
const BaseType_t ret = xTaskCreate(ds_task,
"ds_task",
2048,
NULL,
// See https://docs.espressif.com/projects/esp8266-rtos-sdk/en/latest/api-guides/system-tasks.html for prio's
15, // Can't go higher, who cares about stable WiFi.
&ds_task_handle);
Includes/defines
Code: Select all
#include <xtensa/xtruntime.h>
#include "esp8266/gpio_struct.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// At microsecond speeds, the functions from gpio.h are too heavy
#define GPIO_FAST_SET_1(gpio_num) GPIO.out_w1ts |= (0x1 << gpio_num)
#define GPIO_FAST_SET_0(gpio_num) GPIO.out_w1tc |= (0x1 << gpio_num)
#define GPIO_FAST_OUTPUT_ENABLE(gpio_num) GPIO.enable_w1ts |= (0x1 << gpio_num)
#define GPIO_FAST_OUTPUT_DISABLE(gpio_num) GPIO.enable_w1tc |= (0x1 << gpio_num)
#define GPIO_FAST_GET_LEVEL(gpio_num) ((GPIO.in >> gpio_num) & 0x1)
The method with the critical section
Code: Select all
uint32_t IRAM_ATTR onewire_read_bit(void) {
uint32_t r;
uint32_t savedLevel = XTOS_DISABLE_ALL_INTERRUPTS;
GPIO_FAST_OUTPUT_ENABLE(ONEWIRE_PIN);
GPIO_FAST_SET_0(ONEWIRE_PIN);
ets_delay_us(3);
GPIO_FAST_OUTPUT_DISABLE(ONEWIRE_PIN);
ets_delay_us(10); // Somewhere near here, sometimes we still get 10us extra delay
r = GPIO_FAST_GET_LEVEL(ONEWIRE_PIN);
XTOS_RESTORE_INTLEVEL(savedLevel);
usleep(53);
return r;
}
Re: How to guard time critical sections from RTOS interrupts?
Postby cranphin » Wed Aug 21, 2019 1:46 am
Looks like we've pretty much got a solution, see issue: https://github.com/espressif/ESP8266_RT ... issues/680 :)
Who is online
Users browsing this forum: No registered users and 180 guests
Login
Newbies Start Here
Are you new to ESP8266?
Unsure what to do?
Dunno where to start?
Start right here!
Latest SDK
Documentation
Complete listing of the official ESP8266 related documentation release by ESPRESSIF!
Must read here!
- All times are UTC+08:00
- Top
- Delete all board cookies
About Us
Espressif Systems is a fabless semiconductor company providing cutting-edge low power WiFi SoCs and wireless solutions for wireless communications and Internet of Things applications. We are the manufacturer of ESP8266EX.