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

'Реверс' SDK Espressif и ROM-BIOS для создания открытого SDK.

pvvx

Активный участник сообщества
Я думаю было бы было бы интересно сочетание http://richard.burtons.org/2015/05/17/decompiling-the-esp8266-boot-loader-v1-3b3/ с OpenSDK.
Там всего загрузчик, без какой-либо операционки и включения "кеширования" flash. Т.е. из него не вызвать процедуры из flash и его задача всего загрузка других кусков, да и он при этом занимает память IRAM. Могли бы его перенести и в другую область, которая затирается далее нужным кодом. Ведь он не нужен после загрузки. Короче это очередной китай-бред, связанный с тем, что у них уже ничего не лезет в 512к flash и для их системы обновления по сети.
КОИ8 тут вряд ли поможет. Мне кажется Вы зря не хотите переходить на UTF8, сейчас это повсеместный стандарт. Да и для международного проекта самое правильное решение :)
Да я ошибся. UTF8 конечно. Не важно какая локальная кодировка - git при передаче/приеме всё равно перекодирует, но надо правильно задать эти параметры и знать какие и где... Пока не заботился и сильно не копал это дело...
 
Последнее редактирование:

anakod

Moderator
Команда форума
Там всего загрузчик, без какой-либо операционки и включения "кеширования" flash. Т.е. из него не вызвать процедуры из flash и его задача всего загрузка других кусков, да и он при этом занимает память IRAM. Могли бы его перенести и в другую область, которая затирается далее нужным кодом. Ведь он не нужен после загрузки. Короче это очередной китай-бред, связанный с тем, что у них уже ничего не лезет в 512к flash и для их системы обновления по сети.
Не думаю, во-первых это вроде энтузиастами сделано а не Espressif, а во-вторых оно как раз заточено под задачу произвольного хранения и загрузки неограниченного количества образов прошивок (в пределах мегабайта флешки). Про память - согласен, если тратит лишнее это не гуд, ее и так мало.

UPD А как сделать чтобы память использовалась повторно?
 

pvvx

Активный участник сообщества
Не думаю, во-первых это вроде энтузиастами сделано а не Espressif, а во-вторых оно как раз заточено под задачу произвольного хранения и загрузки неограниченного количества образов прошивок (в пределах мегабайта флешки).
Вот и говорю - у него совершенно другая задача и это не самостоятельная примочка, а кусок созданный исключительно для китай-SDK :)
А собираемое "творение" - это полноценная система. С ней можете странслировать и Дурино без WiFi. Такая система сделана для того, чтобы иметь максимум памяти и максимум производительности + минимум потребления и/или использовать модуль ESP8266 как обычный MCU без WiFi. Подгрузка китай-SDK c WiFi для передачи накопленных данных вписывается отдельным блоком, который запускается когда данные уже обработаны/готовы и положены в RTC_RAM или flash.
Сейчас в данной системе не хватает только правильного sleep, с засыпанием CPU и т.д. (потребление модулем на уровне 2mA). Он представлен (все функции есть) в ROM-BIOS. Время его отработки от пары ms до ... Очень необходимая фича для ожидания готовности внешних датчиков. Необходимо дописать "сервис" обращения к ней (кто и почему вызывает просыпание, сколько предел по времени и т.д.) и ввести коррекции (она кривовата). Всё остальное, кроме специфических драйверов для внешних устройств уже есть в данном "OpenSDKnoWiFi"
Этот sleep режим уже проверен и часть показана в блоке Код (C) dtm_params_init(NULL, NULL); dtm_set_params(0,3000*26/40,0,0,0); rtc_enter_sleep();
Есть ещё второй режим sleep специфичный для самого CPU, так-же с задаваемыми источниками "просыпания" и временем в тактах CPU + callback-и. Так-же уже реализован в ROM-BIOS в ets_run(), но пока используется на 1%. Он требует немного специфичной политики организации работы с прерываниями таймеров и т.д. А в текущих Дуринах и прочих ПО это не используется и игнорируется - там у писателей главное побольше набить галочек и напихать побольше "портирований" всего и вся... :)
PS: Я всегда за разнообразие, а не унификацию – “сделать всё серым”. Природа любит разнообразие и ничего лишнего и каждой фиговинке свои цели и программа… :) После "Дурин" большинство уже ничего не может сделать самостоятельно. И их много развелось - баланс нарушен :)
 
Последнее редактирование:

pvvx

Активный участник сообщества
Кто может объяснить, почему в RTOS библиотеках включены все дубли кодов из ROM-BIOS? Это сделано чтобы неиспользуемого коду во flash было во много раз больше? (Китай-програмерам платят за каждую строчку кода, даже если он не нужен? :))
https://github.com/espressif/esp_iot_rtos_sdk/tree/master/lib
 

anakod

Moderator
Команда форума
pvvx, мы же с Вами как раз сегодня про оптимизацию и дублирование разговаривали :) Вот китайцы молодцы, никогда не забывают скописатить код, даже если он их собственный :D

Касательно RTOS: насколько он отличается, что там по DHCP (и можно ли использовать обычный)? Давно подумывал на него перейти.
 

pvvx

Активный участник сообщества
pvvx, мы же с Вами как раз сегодня про оптимизацию и дублирование разговаривали :)
Дык уже проросло http://www.esp8266.com/viewtopic.php?t=3420&p=19449#p19444

Касательно RTOS: насколько он отличается, что там по DHCP (и можно ли использовать обычный)? Давно подумывал на него перейти.
Там старая версия без излишков, но с дублями от первых либ v5 для WiFi (она полностью в ROM-BIOS, а SDK использует v6)
Пример, как входят дубли в те либы:
phy_chip_v5_ana_romfunc.o
phy_chip_v6_ana.o
phy_chip_v5_cal_romfunc.o
phy_chip_v6_cal.o
В v6 изменено до десяти функций. Список измененных уже приводился Код (Text).
У измененных название начинается с "ram_...", а от v5 в ROM-BIOS = "rom_..."
Касательно RTOS: насколько он отличается, что там по DHCP (и можно ли использовать обычный)? Давно подумывал на него перейти.
Используется DHCP из LwIP. И в SDK аналогично. Для ST - собственный-китайский :) В новом SDK 1.1.0 к ним подвязаны "события" типа GOT_IP... Это единственное правильное решение в их разработке, но сделано было криво...
Open mdns адаптировать некогда. Китайцы какую-то open версию стырили и вставили.
То, что лежит тут https://github.com/espressif/esp_iot_rtos_sdk/tree/master/third_party - это просто для приколу :)
Процедуры ROM-BIOS и остальные либы SDK не могут работать с мультизадачкой. Это в них никак не предусмотрено и по этому про RTOS можно забыть, пока не напишите всё сами.

Да, ещё отличие библиотек в RTOS от SDK1.1.0 в том, что китайцам пришлось "пойти на жертвы" - они выкинули часть неиспользуемых процедур из библиотек в SDK1.1.0, т.к. это уже никуда не лезло :)
 
Последнее редактирование:

JustACat

Moderator
Команда форума
Не работает только отображение в браузере.
Не хочется вас наставлять, но, вот как раз поэтому, в основном, и переходят все постепенно на UTF. Все же кодировки вроде 1251 или KOI себя изживают. И их использование только порождает в итоге проблемы.
Взять для примера хотя б Pebble - как они лоханулись, что в свой первый пебл не внедрили сразу юникод?.. Потом допиливали, мучились, не влезало. А заложили бы сразу - и проблемы бы не было вовсе.
Какой сейчас выигрыш от старых кодировок? Только размер файла разве что?..
В общем, не мне вас, @pvvx, учить и наставлять, конечно. Но все же хотелось бы, чтобы и вы перешли на светлую сторону силы UTF ^_^"
Китай-програмерам платят за каждую строчку кода, даже если он не нужен?
А мож правда так? Это даже ведь имеет название "Индусский код".
 

pvvx

Активный участник сообщества
JustACat - вопрос в том, что надо указать в TortoiseGit 1.8.14.0, чтобы он нормально перекодировал любой формат.
А расширение текстов и прочего в несколько раз по объему меня не устраивает. Пусть это будет на github, а у себя я буду использовать то, что совместимо с используемым мной ПО, пока не напишут замену с полной поддержкой UTF. Но этого пока не видать, т.к. причина не в том, а в том что везде насаждается английский (диалект США) язык. А от языка зависит многое...
Писатели из США не утруждают себя поддержкой других языков, а я должен? :)
 

pvvx

Активный участник сообщества
Проверил sleep в ROM-BIOS, который работает в est_run() без перезагрузки и с назначением события просыпания. (est_run() - это процедура исполняется всегда и в китай-SDK, в ней цикл с ожиданием прерываний)
Код:
Test 'SDK no WiFi'
Heap size:    81848 bytes
Bss size:    40 bytes
Stack pointer:    0x3fffffb0
ets_delay_us(1000) dt=1000
ets_delay_us(10000) dt=10001
Test sleep (low power) 1000 ms, 7 cycles
go ets_run()
Test cb1, t=30907
Test cb2, t=31888, dt=981
Test cb1, t=33391
Test cb2, t=34340, dt=949
Test cb1, t=35843
Test cb2, t=36792, dt=949
Test cb1, t=38292
Test cb2, t=39239, dt=947
Test cb1, t=40744
Test cb2, t=41692, dt=948
Test cb1, t=43196
Test cb2, t=44143, dt=947
Test cb1, t=45647
Test cb2, t=46593, dt=946
Test cb1, t=48097
Test cb2, t=49043, dt=946
Т.к. sleep отключает всё, то приходится восстанавливать PLL после выхода к кварцу на 26MHz...
Придется адаптировать/переписывать для OpenSDK, т.к. там назначается на событие просыпания всегда одна нога - GPIO2 и не правильно выставляется предельное время sleep в RTC (всё из-за кварца на 26MHz вместо 40MHz).
 

anakod

Moderator
Команда форума
То что сбивается это наверно достаточно закономерно, т.к. просыпание после deep sleep это фактически старт заново (с нуля). Или я ошибаюсь?
 

pvvx

Активный участник сообщества
То что сбивается это наверно достаточно закономерно, т.к. просыпание после deep sleep это фактически старт заново (с нуля). Или я ошибаюсь?
deep sleep написан и работает (см. sys_deep_sleep()).
А sleep - это выключение CPU и его потрахов (но не всех - RTC и другие блоки работают) на ходу. CPU останавливается, а после события продолжает работу с места "останова". Но и при этом почему-то его PLL сбита. Т.е. он продолжает работу с дефолтными установками и требует их восстановления.
Режим sleep удобен тем, что просыпание более быстрое и ничего в памяти не сбито. Потребление в нем минимально (точно ещё не измерял). Время входа и выхода мало - ограничения только на время восстановления PLL и некоторых других аппаратных "опций". На просыпание, кроме ограничения ( время таймера на RTC вызывающего INT) назначается ещё любое событие - например перепад уровня на входной ножке. Он дает экономию питания при ожидании ответов с внешних устройств. Но для user-ов требуется написание простой системы назначения всего этого дела...
Т.к. часы (CLK) у RTC не на кварце, а на внутреннем RC генераторе, то он неточный (зависит от температруры и т.д) и требует калибровки (регистры калибровки описаны в xls с GPIO). Перед входом в sleep она и выполняется (требуется > 100 us). Но можно и без калибровки, если она произведена заранее или точность предельного времени нахождения в sleep не требуется. Точное ограничение ожидания события от датчика обычно не требуется, т.к. оно используется как авария = датчик умер и не хочет отвечать :)
----
Для deep_sleep (sleep через reset) есть ветка быстрого старта (возобновления) в ROM-BIOS, но её использовать сложно – требует определенного состояния выводов (как и при программировании), а так-же не хватает информации по чипу + потеря значений в памяти RTC из-за отсутствия подключенного внешнего источника питания к ноге VCC_RTC (ROM-BIOS анализирует при старте некоторые значения там и от них зависит “ветвь старта”).
 
Последнее редактирование:

pvvx

Активный участник сообщества
Обобщая о системах low_power на ESP8266:

На данном чипе мы имеем 3 системы low_power:

1) Deep_sleep – sleep до события срабатывания “будильника” в RTC, назначенного на ножку вывода и соединенного с reset. При использовании SDKnoWiFi возобновление после deep_sleep < 30 ms.

2) Sleep - sleep до события прерывания. Назначается прерывание по таймеру RTC. Всё остальное, кроме спец. прерываний по I/O вырубается. Выходом, продолжением исполнения кода CPU с места засыпания, является срабатывание прерывания или I/O или таймера RTC. При использовании SDKnoWiFi возобновление работы после sleep, с установкой PLL на 26MHz кварц < 150 us. Без, для прямого опроса датчика сразу - наносеки.

3) Спец команда CPU * ожидания прерывания (ROM:40000F65: "waiti 0"). Глушит только CPU. Потребление модулем < 2 mA. Имеет установку ограничения времени нахождения CPU в данном режиме в спец. регистре CPU и задается в тактах CPU. Стоит в цикле ets_run(), где вечно сидит процессор. В итоге любой лишний включенный timer_arm() или безграмотный user-цикл опроса чего-либо (как в "Дуринах", особо её драйверах) увеличивает потребление чипом.
Организуйте работу системы по событиям, по возможности без всяких delay( >1 ms) и длительных циклов опросов. По событию (CPU лучше включить на 180MHz), отработать и встать опять на "waiti" до следующего события. Если время ожидания и опрос позволяет использовать sleep или deep_sleep - то и использовать их. Тогда потребление будет минимальным.

*The WAITI (Wait for Interrupt) instruction, which is a part of the Interrupt Option, saves power by setting the current interrupt level, powering down the processor’s logic, and waiting for an interrupt.
 
Последнее редактирование:

pvvx

Активный участник сообщества
Протестировал потребление оптимизированного sys_delay_us() в замену est_delay_us():
TstOpenSDKnoWiFi.gif
Код:
Test 'SDK no WiFi'
Heap size:    81848 bytes
Bss size:    40 bytes
Stack pointer:    0x3fffffa0
sys_delay_us(1000000), dt=1000004
sys_delay_us(900000), dt=899999
sys_delay_us(800000), dt=800000
sys_delay_us(700000), dt=699999
sys_delay_us(600000), dt=599999
sys_delay_us(500000), dt=499999
sys_delay_us(400000), dt=399999
sys_delay_us(300000), dt=300000
sys_delay_us(200000), dt=199999
sys_delay_us(100000), dt=100000
ets_delay_us(1000000) dt=500000
Test sleep (low power) 1000 ms, 7 cycles
go ets_run()
Test cb1, t=6063443
Test cb2, t=6065320, dt=1877
Test cb1, t=6068129
Test cb2, t=6069962, dt=1833
Test cb1, t=6072766
Test cb2, t=6074593, dt=1827
Test cb1, t=6077392
Test cb2, t=6079215, dt=1823
Test cb1, t=6082023
Test cb2, t=6083857, dt=1834
Test cb1, t=6086658
Test cb2, t=6088488, dt=1830
Test cb1, t=6091300
Test cb2, t=6093129, dt=1829
Test cb1, t=6095940
Test cb2, t=6097767, dt=1827
Модуль ESP-01 с горящим светодиодом, пуск с CH_PD.
Что-то надо ещё отключить в потрохах ESP8266, но пока не нашел как и что... :)
 
Последнее редактирование:

pvvx

Активный участник сообщества
Почуть-чуть проясняется с WiFi, хотя я этим не занимаюсь, рассчитывая на других :) Мне было многократно сказано, в переписке, что кто-то разгребает WiFi процедуры... но пока что-то не видно и не слышно.
В частности код ieee80211 китайцами "скопирован" из freebsd.
Это подтверждают и тут: http://bbs.espressif.com/viewtopic.php?f=7&p=2113#p2113
В итоге особых проблем с WiFi частью быть не должно. Разве что со спецификой, связанной c аппаратными фичами чипа.
----
Ещё пустили байку-слух, что выйдет новый чип ESP с большей памятью. Наверно настолько плохи дела у NodeMCU :)
Да и пока стало "легче жить" - все "телепузики" ушли на arduino :)
 
Последнее редактирование:

anakod

Moderator
Команда форума
and finally outputting the frame via ieee80211_mgmt_output which internally calls ieee80211_raw_output which in my opinion is replaced by ppTxPkt in ESP, so maybe the signature is similar.
Если так, то мне кажется можно взять одну эту функцию бинарником/асмом либо дизассемблировать, а все остальное накатить из оригинала с полными исходниками.
 

pvvx

Активный участник сообщества
Если так, то мне кажется можно взять одну эту функцию бинарником/асмом либо дизассемблировать, а все остальное накатить из оригинала с полными исходниками.
Да, но там, в оригинале, слишком много лишнего - ~60%. А разбираться с этим лень. Оригинал писало несколько человек и одному разгребать долго.
Первым делом надо тупо отсортировать, какие функции есть в SDK либе 80211, в каждом входящем obj.
Код:
libnet80211.a:ieee80211.o
libnet80211.a:ieee80211_action.o
libnet80211.a:ieee80211_crypto.o
libnet80211.a:ieee80211_crypto_ccmp.o
libnet80211.a:ieee80211_crypto_tkip.o
libnet80211.a:ieee80211_crypto_wep.o
libnet80211.a:ieee80211_ets.o
libnet80211.a:ieee80211_hostap.o
libnet80211.a:ieee80211_ht.o
libnet80211.a:ieee80211_hwmp.o
libnet80211.a:ieee80211_input.o
libnet80211.a:ieee80211_mesh.o
libnet80211.a:ieee80211_node.o
libnet80211.a:ieee80211_output.o
libnet80211.a:ieee80211_phy.o
libnet80211.a:ieee80211_power.o
libnet80211.a:ieee80211_proto.o
libnet80211.a:ieee80211_scan.o
libnet80211.a:ieee80211_sta.o
libnet80211.a:if_eagle.o
libnet80211.a:wl_chm.o
libnet80211.a:wl_cnx.o
Например так:
https://github.com/pvvx/esp8266web/blob/master/info/libs/net80211/ieee80211_output.h
Потом надо разгрести форматы запросов и удалить лишнее.
Затем уже уточненно сравнивать с дизасм, что там китайцы накрутили своего для связи с другими частями и т.д.
Потом, проанализировав итого, загрузив всё в голову, сесть на попу и переписать исходники из оригинала. :)
 
Последнее редактирование:

pvvx

Активный участник сообщества
Вот так делается сохранение всех и каждый раз измененных параметров WiFi в SDK:
Код:
void wifi_param_save_protect_with_check(uint16 startsector, int sectorsize, void *pdata, uint16 len)
{
    uint8 * pbuf = pvPortMalloc(len);
    int i;
    if(pbuf == NULL) return;
    do {
        spi_flash_erase_sector(startsector);
        spi_flash_write(startsector*sectorsize, pdata, len);
        spi_flash_read(startsector*sectorsize, pbuf, len);
        i = ets_memcmp(pdata, pbuf, len);
        if(i) {
            os_printf("[W]sec %x error\n", startsector);
        }
    } while(i != 0);
    vPortFree(pbuf);
}
Т.е. если сектор уже помирает, то оно будет писать "пока дым не пойдет". Китай поражают своим программированием... :)
При старте модуля (питание, reset, deep_sleep) обычно последний сектор flash стирается и переписывается 2 раза. При соединении к AP тоже стирается и переписывается :mad:
И делается это (тратится 4 килобайта) для сохранения всего двух контрольных сумм предыдущих 2-х секторов, в которых тоже стираются и переписываются данные до 888 байт...
Кроме этого в SDK 1.3.0 в некоторых случаях, в процедуре инициализации SDK, стирается и сектор перед сектором с блоком в 128 байт esp_init_data_default.bin (убивает SPIFFS в Дуринах :) ).
Код:
.irom0.text:40240533                 l32r            a2, a_flashchip
.irom0.text:40240536                 l32i            a2, a2, 0 ;получить адрес структуры flashchip
.irom0.text:40240539                 l32i            a14, a2, 0xC ; flashchip->sector_size (размер сектора = 4096 байт)
.irom0.text:4024053C                 l32i            a2, a2, 4 ; flashchip->chip_size (размер flash в байтах)
.irom0.text:4024053F                 mov.n           a3, a14
.irom0.text:40240541                 l32r            a0, a___udivsi3
.irom0.text:40240544                 callx0          a0 ; a2=a2/a3 =  делить размер flash в байтах на размер сектора
.irom0.text:40240547                 mov.n           a3, a14 ; flashchip->sector_size (размер сектора = 4096 байт)
.irom0.text:40240549                 l32i.n          a4, a1, 0x14 ; адрес блока полученного по pvPortZalloc(256)+0x80 ранее. Туда сохранен блок в 128 байт всех равных 0xFF из сектора с адресом end_flash-0x5000 (=0x7B000).
.irom0.text:4024054B                 addi            a2, a2, -5 ; end flash sectors - 5 !!! (0x7B000 !)
.irom0.text:4024054E                 movi            a5, 0x80 ; 128 байт
.irom0.text:40240551                 call0           wifi_param_save_protect_with_check
:eek:
Не читайте китайские доки о разметке их Flash с использованием последних 5-ти секторов - там про это ничего не сказано! :)

Итого на сохранение 888*2+128 байт китай-SDK расходует последние 16 ... , т.е 20 килобайт Flash. :)

И ошибки во всех версиях SDK в:
Код:
bool wifi_station_set_hostname(uint8 * name)
{
    if(name == NULL) return false;
    uint32 len = ets_strlen(name);
    if(len > 32) return false;
    uint32 opmode = wifi_get_opmode();
    if(opmode == 1 || opmode == 3) {
        default_hostname = false;
        if(hostname != NULL) {
            vPortFree(hostname);
            hostname = NULL;
        }
        hostname = pvPortMalloc(len);
        if(hostname == NULL) return false;
        struct netif * nif = eagle_lwip_getif(0);
        ets_strcpy(hostname, name); // пишется на 1 байт больше, чем было выделено по vPortFree(hostname) !!!
        if(nif != NULL) {
            nif->hostname = hostname;
        }
        return true;
    }
    return false;
}
 
Последнее редактирование:

pvvx

Активный участник сообщества
При старте (инициализации SDK) отрабатывает функция phy_gpio_cfg(), которая в качестве исходных опций использует esp_init_data_default.bin байты 50,51,52,53,54,64 и в зависимости от которых она меняет функции GPIO 0,1,2,3,13,14,16 и так-же “SDIO dataoutput is at negative edges (SDIO V1.1)”или “SDIO dataoutput is at positive edges (SDIO V2.0)“ (байт 50) и лезет в неописанные регистры контроллера SDIO (0x60000A00..0x60000Aff).

Кто копался с этим и может дополнить или уточнить детали с esp_init_data_default.bin и SDIO (0x60000A00..0x60000Aff)?
 

dronvolk

New member
Похоже тема заглохла... дайте хоть ссылки на описание ассемблера этого чуда в перьях. недавно прикупил себе парочку модулей (да повелся на отношение цена-возможности), а тут sdk наикривейший и нифига описания нет нормального по чипу. придется самому ковырять этот sdk вдруг что получится :D.
 

pvvx

Активный участник сообщества
Похоже тема заглохла... дайте хоть ссылки на описание ассемблера этого чуда в перьях. недавно прикупил себе парочку модулей (да повелся на отношение цена-возможности), а тут sdk наикривейший и нифига описания нет нормального по чипу. придется самому ковырять этот sdk вдруг что получится :D.
За данное время сменилось много версий SDK и всё что было надо - сделали. Если не знаете где и как взять дизасм, то и браться не стоит :) Берите IDA и вперед.
 
Сверху Снизу