Чтение содержимого ESP8266 Flash изнутри скетча
Я знаю, что есть способ создать дамп флэш-памяти с помощью esptool, но есть ли способ прочитать содержимое памяти скетча (только скетча, а не полной флэш-памяти или SPIFFS) через скетч сам? Например, есть ли программа на ESP8266, способная читать собственный машинный код из флэш-памяти и что-то с ней делать? Мне не нужен доступ на запись, только доступ на чтение.
Я хотел бы иметь возможность создать резервную копию текущего скетча в SPIFFS, чтобы можно было вернуть плохой скетч, пока не сломан триггер возврата. (Например, если более поздняя часть процесса загрузки испорчена или если функция работает немного неправильно, можно удерживать кнопку, и она будет восстановлена из сохраненного образа. Процесс восстановления — это то, что я выяснил из моего предыдущего вопроса, но мне хотелось бы найти способ написать скетч в SPIFFS, который не требует отдельной ручной загрузки или оболочки вокруг процесса OTA.)
[править:] Спасибо за комментарии.
Я создал этот код, который ДОЛЖЕН скопировать скетч в SPIFFS. Однако, похоже, это было сделано неправильно (поскольку результат не имеет тех же контрольных сумм, что и исходный файл, и попытки его записи приводят к неработоспособному устройству). Могу ли я попросить кого-нибудь просмотреть это и посмотреть, смогут ли они понять, почему?
unsigned long addr = 0;
unsigned long rem = ESP.getSketchSize();
uint32_t *data = new uint32_t[SPI_FLASH_SEC_SIZE];
File f = SPIFFS.open("/fw.bin", "w");
while (rem > 0) {
ESP.flashRead(addr, data, SPI_FLASH_SEC_SIZE);
int sz = SPI_FLASH_SEC_SIZE * sizeof(uint32_t);
if (rem < sz)
sz = rem;
f.write(reinterpret_cast<uint8_t *>(&data[addr]), sz);
addr += SPI_FLASH_SEC_SIZE;
rem -= sz;
yield();
Serial.println(rem);
}
f.flush();
f.close();
@, 👍1
Обсуждение1 ответ
Лучший ответ:
Я думаю, что вы читаете Flash немного неправильно
хотя ESP.flashRead
принимает указатель unit32_t для выходных данных, аргумент чтения «count» находится в байтах — если посмотреть на код Updater.cpp, он делает это
uint8_t buff[128];
for(int i = 0; i < binSize; i += sizeof(buff)) {
ESP.flashRead(_startAddress + i, (uint32_t *)buff, sizeof(buff));
.....
}
Итак, адрес и количество указаны в байтах - учитывая, что SPI_FLASH_SEC_SIZE равен 0x1000 или 4096, ваш код выполняет следующее
- чтение 4096 байт в буфер 16384
- запись 16384 байт (поэтому последние 12288 байт нулевые или случайные, не уверен)
- добавление 4096 к адресу
- вычитая 16384 из размера.
- повторять, пока все не будет прочитано.
Итак, написанный размер будет правильным, но данные будут неправильными на три четверти :p
Поэтому ваш код должен быть
unsigned long addr = 0;
unsigned long rem = ESP.getSketchSize();
uint8_t *data = new uint8_t[SPI_FLASH_SEC_SIZE];
int sz = SPI_FLASH_SEC_SIZE;
File f = SPIFFS.open("/fw.bin", "w");
while (rem > 0) {
ESP.flashRead(addr, (uint32_t *)data, SPI_FLASH_SEC_SIZE);
if (rem < sz)
sz = rem;
f.write(data, sz);
addr += SPI_FLASH_SEC_SIZE;
rem -= sz;
yield();
Serial.println(rem);
}
f.flush();
f.close();
Кажется, это сработало очень хорошо. Спасибо. Отмечу, что как написано, это вызывает ошибку компиляции, так как f.write не принимает uint32_t. Я по-прежнему использовал данные для чтения флэш-памяти, но вместо этого определил «данные» как uint8_t., @RDragonrydr
Упс, я пропустил unt32, @Jaromanda X
- ESP8266 завис в режиме прошивки?
- Как настроить схему секционирования Wemos D1 mini pro?
- Как читать и записывать EEPROM в ESP8266
- Как исправить: Invalid conversion from 'const char*' to 'char*' [-fpermissive]
- ошибка: espcomm_upload_mem failed при загрузке скетча
- Как определить размер Flash?
- Несколько клиентских серверов через Wi-Fi
- Передача функции-члена класса в качестве аргумента
Я начал изучать это после вашего предыдущего вопроса (потому что, я думаю, это тоже будет полезно для меня) - если вы посмотрите, как устроена EEPROM, вы увидите, что она использует
spi_flash_read
- который определен вtools/ sdk/include/spi_flash.h
— теперь я **думаю**, что прошивка будет загружаться, начиная с адреса0
— и, возможно, [этот код Python](https://microcontrollerelectronics.com/decoding-an-esp8266- прошивка-image/) (очевидно, преобразованная в C++) может помочь определить точный размер загруженной прошивки., @Jaromanda Xна самом деле... есть
ESP.getSketchSize()
для получения размера скетча :p - так что теоретически это просто вопрос использованияspi_flash_read
для чтения скетча (очевидно, частями, поскольку скетч больше, чем ОЗУ) и запишите его в SPIFFS, @Jaromanda XКажется, я не могу заставить это работать. Я разместил код, который написал в вопросе сейчас, но что-то не работает. Я получаю файл с другим содержимым, хотя он ИСТИННОГО размера., @RDragonrydr
было бы неплохо, если бы вы могли прочитать это и посмотреть, что там - для начала unit32_t выглядит неправильно, ваши
данные
будут 4 x SPI_FLASH_SEC_SIZE, @Jaromanda XЯ понимаю, что чтение флэш-памяти может выполняться с 32 битами за раз, но не уверен, что адрес обрабатывается правильно... возможно,
addr += SPI_FLASH_SEC_SIZE * 4;
?, @Jaromanda XЯ также думаю, что вы получаете только байты
SPI_FLASH_SEC_SIZE
, а не dword (32 бита)... так что вы будете писать изрядное количество мусора - опять же, не уверен, документация в лучшем случае расплывчата., @Jaromanda X