• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Как передать управление фоновым задачам SDK?

gerkimuyda

New member
Столкнулся с проблемкой, что при сильной загрузке проца (например некоторые расчеты в цикле), не обрабатываются фоновые задачи SDK (например, поддержка соединения wifi, таймер wdt). Вся прога построена на прерываниях, но есть моменты, в которых нужна немного длительная обработка.
system_soft_wdt_feed() сбрасывает wdt, но вот фоновые процессы sdk не получают управления и wifi начинает отваливаться по таймауту (extensive data lost).

Пробовал найти команды для отдачи тиков процессора фоновым задачам (передачи управления для их исполнения с возвратом и продолжением текущего кода). Ничего не смог найти. Вроде что-то est_run() должна делать, но она не возвращает управление назад.

Код:
40000e04 <ets_run>:
40000e04:    12c1f0            addi    a1, a1, -16    ; stack
40000e07:    21feff        l32r    a2, 40000e00    ; ( 3fffc6fc )
40000e0a:    026100            s32i    a0, a1, 0    ; save return
40000e0d:    02a000            movi    a0, 0        ; a0 = 0
40000e10:    024200            s8i    a0, a2, 0    ; 0 byte --> 3fffc6fc
40000e13:    85feff            call0    40000dfc <sub_0dfc>    (stub)
40000e16:    450b00            call0    40000ecc <sub_0ecc>
40000e19:    022100            l32i    a0, a1, 0    ; restore return
40000e1c:    12c110            addi    a1, a1, 16    ; stack
40000e1f:    0df0          ret.n
А что делает <sub_0ecc> ?
Еще читал в доке, что есть таски с маленькими приоритетами, ниже чем пользовательские, и они в такой ситуации могут не получать управление совсем (до них не доходит очередь).

Среда разработки: Unofficial Development Kit

Есть ли более простой способ, чем создавать отдельную функцию "продолжения" и вешать ее на таймер (типа аля callback после фоновых процессов )?
 

pvvx

Активный участник сообщества
Есть ли более простой способ, чем создавать отдельную функцию "продолжения" и вешать ее на таймер (типа аля callback после фоновых процессов )?
Более простого способа нет.
Софт таймер так-же вызывается из ets_run() и если не завершить его выход, то все другие процессы встанут, пофиг приоритеты. Там ещё большие сложности, т.к. после вызова таймеров и тасков из ets_run(), она ставит флаги и не установка их приведет к потере распределения у неё очередности вызова процессов...
Есть "сложное" :) решение в виде вставки своей my_ets_run() и указания компилятору замены вызова из SDK ets_run() на новый my_ets_run().
Код исходного ets_run() из ROM давно реверсирован в "СИ" и использовал для коррекции кривой NodeMCU Lua года два или более назад... Так-же была дана рекомендация как одной малой процедурой в NON_OS_SDK сделать два независимых процесса - пользовательский и WiFi для Arduino, но оно было не воспринято и фрики сделали кривизну с не поддерживаемым:
void Loop() {
while(1);
}
Теперь ESP8266 Ardino IDE имеет несовместимость с концептом Arduino :)

Для Lua и совместимости с их кривым кодом (чтобы его не переписывать, а просто разбавить ужасно тупой и медлительный SPIFFS вызовами run_sdk_tasks()) была сделана и такая EspLua/ets_run.c at master · pvvx/EspLua · GitHub для вызова run_sdk_tasks() (в EspLua/delay.c at master · pvvx/EspLua · GitHub) (в *.ld отключено объявление ets_run() в ROM)
Но это не решает всех проблем, а частый случай для совместимости имеющегося кода в NodeMCU Lua на ESP8266...
Данную функцию нельзя вешать на callback-и Lwip - возможна повторность вхождения (вызова новых callback-ов из Lwip в callback-е Lwip) :) Это исправляется другими методами - нормальной заменой ets_run() с переключением в ней задач по таймеру и флагам активности (недо-RTOS с всего двумя задачами и общим стеком)...

Сама ets_run() в ROM, если нет активных тасков и таймеров, выполняет ets_idle_cb(ets_idle_arg), если он назначен (if(ets_idle_cb != NULL)). Затем ставит CPU в low power на ожидание прерываний: [inline]asm volatile ("waiti 0;"); // Wait for Interrupt[/inline] и по кругу...
В приведенном примере просто вставлен выход из этого цикла ets_run() по введенному флагу ets_run_ret - это всё отличие от оригинальной ets_run().
Т.е. вся система работает по событиям и ваш подход с линейным программированием "аля` Arduino для детей" тут не катит.
 
Последнее редактирование:

nikolz

Well-known member
Столкнулся с проблемкой, что при сильной загрузке проца (например некоторые расчеты в цикле), не обрабатываются фоновые задачи SDK (например, поддержка соединения wifi, таймер wdt). Вся прога построена на прерываниях, но есть моменты, в которых нужна немного длительная обработка.
system_soft_wdt_feed() сбрасывает wdt, но вот фоновые процессы sdk не получают управления и wifi начинает отваливаться по таймауту (extensive data lost).

Пробовал найти команды для отдачи тиков процессора фоновым задачам (передачи управления для их исполнения с возвратом и продолжением текущего кода). Ничего не смог найти. Вроде что-то est_run() должна делать, но она не возвращает управление назад.

Код:
40000e04 <ets_run>:
40000e04:    12c1f0            addi    a1, a1, -16    ; stack
40000e07:    21feff        l32r    a2, 40000e00    ; ( 3fffc6fc )
40000e0a:    026100            s32i    a0, a1, 0    ; save return
40000e0d:    02a000            movi    a0, 0        ; a0 = 0
40000e10:    024200            s8i    a0, a2, 0    ; 0 byte --> 3fffc6fc
40000e13:    85feff            call0    40000dfc <sub_0dfc>    (stub)
40000e16:    450b00            call0    40000ecc <sub_0ecc>
40000e19:    022100            l32i    a0, a1, 0    ; restore return
40000e1c:    12c110            addi    a1, a1, 16    ; stack
40000e1f:    0df0          ret.n
А что делает <sub_0ecc> ?
Еще читал в доке, что есть таски с маленькими приоритетами, ниже чем пользовательские, и они в такой ситуации могут не получать управление совсем (до них не доходит очередь).

Среда разработки: Unofficial Development Kit

Есть ли более простой способ, чем создавать отдельную функцию "продолжения" и вешать ее на таймер (типа аля callback после фоновых процессов )?
Попробуйте остановить WDT на время Ваших вычислений.
 

gerkimuyda

New member
Проблема не в WDT, который можно сбрасывать или вообще отключить. Проблема в WiFi, которое не получает управление для поддержания связи.
Уже думал, может как-то обмануть ets_run, предварительно запихнув в стек свой адрес возврата... или расковырять (если получиться) что он делает и эмулировать его работу... Но это временный костыль до первого обновления SDK (и других адресов).
Сейчас отдыхаю и другим занят, а чуть позже углублюсь в материалы, которые дал @pvvx и в опции компилятора по подмене функции (с этим еще не сталкивался).
 

nikolz

Well-known member
Проблема не в WDT, который можно сбрасывать или вообще отключить. Проблема в WiFi, которое не получает управление для поддержания связи.
Уже думал, может как-то обмануть ets_run, предварительно запихнув в стек свой адрес возврата... или расковырять (если получиться) что он делает и эмулировать его работу... Но это временный костыль до первого обновления SDK (и других адресов).
Сейчас отдыхаю и другим занят, а чуть позже углублюсь в материалы, которые дал @pvvx и в опции компилятора по подмене функции (с этим еще не сталкивался).
Отключите WIFI на время вычислений.
https://esp8266.ru/forum/threads/ehnergopotreblenie-esp-novoe.2591/page-5
 

pvvx

Активный участник сообщества
в опции компилятора по подмене функции (с этим еще не сталкивался).
См. GCC wrap
К примеру опция -Wl,--wrap=os_printf_plus заменит вызовы на вашу, описанную как:
int ICACHE_FLASH_ATTR __wrap_os_printf_plus(const char *format, ...)
 
Сверху Снизу