• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе 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, ...)
 
Сверху Снизу