Is there a way to pin all RTOS tasks to core 0, leaving core 1 completely free for application code?
The reason for this question is that there seems to be a change introduced in the way tasks are scheduled between the cores in ESP-IDF v4.1.
I have just done a minor code update (changed WiFi credentials) and rebuilt the code for my ESP32 LED clock, and the display now flickers horribly. Other than the minor code update, the only change I can see is that I am now using ESP-IDF V4.1 instead of v4.0.1.
Previously I believe all the RTOS code ran on core 0, leaving core 1 free for me to pin my display task to APP_CPU in a tight loop and turn off the watchdog. This worked very well, with a rock solid display. Now with the new ESP-IDF version, my display routine appears to be getting interrupted and delayed at varying rates. This changes the update rate of the LED display, which needs to have each row lit for exactly the same time for consistent brightness across the display.
Reading through the docs, it appears that SMP now allows tasks to be scheduled on either core unless pinned to one specific core. I have pinned everything I can, including tasks in MENUCONFIG, but that doesn't seem to be enough. There seems to be other RTOS tasks 'floating' between the cores creating very variable delays in scheduling of my display task.
I have tried CONFIG_FREERTOS_UNICORE, but this completely disables core 1.
I have also tried making the whole display routine critical with portENTER_CRITICAL() but then RTOS dies with a watchdog timeout, confirming that some parts of RTOS are indeed running on core 1.
[solved] SPI display flicker - related to SMP and task pinning changes in v4.1?
[solved] SPI display flicker - related to SMP and task pinning changes in v4.1?
Last edited by steveboak on Tue Feb 09, 2021 4:58 am, edited 1 time in total.
[solved] SPI display flicker - related to SMP and task pinning changes in v4.1?
Found an alternative solution - using calculated delays, I can make sure the display update starts at a precise time despite any interrupts changing the timing of the last pass, completely eliminating display flicker.
Code: Select all
// Several techniques are needed to make the display update stable.
// 1. watchdog is disabled on this task as it hard loops here.
// 2. make display task critical to stop it being interrupted
// 3. allow interrupts that were held off during display update
// 4. measure time elapsed in the actual display update
// 5. calculate balance of loop time, and wait.
portMUX_TYPE mutex = portMUX_INITIALIZER_UNLOCKED;
struct timeval tv_now;
suseconds_t time_us, wait_us;
while (1) {
gettimeofday(&tv_now, NULL);
time_us = tv_now.tv_usec;
portENTER_CRITICAL(&mutex);
LED32x16_updateDisplayTask(spi);
portEXIT_CRITICAL(&mutex);
// queued interrupts should be handled here...
// now calculate time to next display update
gettimeofday(&tv_now, NULL);
if (tv_now.tv_usec > time_us) {
wait_us = 500 - (tv_now.tv_usec-time_us);
} else {
wait_us = 500 - ((tv_now.tv_usec-time_us)+1000000);
}
ets_delay_us(wait_us);
}
Who is online
Users browsing this forum: dg9ngf and 105 guests