How to guard time critical sections from RTOS interrupts?

btomic
Posts: 5
Joined: Thu May 04, 2017 7:01 pm

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)?

cranphin
Posts: 8
Joined: Sun May 22, 2016 7:52 am

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

cranphin
Posts: 8
Joined: Sun May 22, 2016 7:52 am

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

cranphin
Posts: 8
Joined: Sun May 22, 2016 7:52 am

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:

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;
}

cranphin
Posts: 8
Joined: Sun May 22, 2016 7:52 am

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