MeshCore Web Flash - analiza działania (nRF52)

Baza wiedzy dotycząca projektu MeshCore
kera
Posty: 1
Rejestracja: pt mar 20, 2026 7:30 pm

MeshCore Web Flash - analiza działania (nRF52)

Post autor: kera »

Witajcie,
MeshCore Web Flasher (https://flasher.meshcore.co.uk/) to chyba najpopularniejszy sposób programowania aplikacji Meshcore. Postanowiłem dowiedzieć się więcej o jego działaniu a przy okazji - o programowaniu urządzeń opartych na kontrolerach nrf52x. Poniższe eksperymenty przeprowadzałem na posiadanym przeze mnie Elecrow ThinkNode M1 opartym na mikrokontrolerze nrf52840 (s140). Część z zamieszczonych informacji może mieć również zastosowanie dla esp32, chociaż szczegóły (jak mapa pamięci) mogą być rożne nawet dla innych modeli z rodziny nrf52x. Do linii komend używam powershella z windows 11.

Poniższe wiadomości zamieszczam wyłącznie w celach edukacyjnych. Jeżeli popełniłem gdzieś błędy lub przeinaczenia - proszę o sprostowanie.

Jaki mam bootloader?
Wersję bootloadera M1 można sprawdzić wprowadzając go w tak zwany tryb ‘uf2’. UF2 jest właściwie nazwą formatu obrazów oprogramowania zdefiniowanym przez Microsoft (https://github.com/microsoft/uf2), ale popularnie używa się 'uf2' również w odniesieniu do jednego z trybów programowania kontrolerów. W skrócie działa to tak, że po podłączeniu do komputera bootloader kontrolera zgłasza się jako wirtualny dysk USB. Wystarczy wtedy przeciągnąć na niego nowe oprogramowanie w formie uf2. Po zakończeniu kopiowania pliku bootloader rozpocznie własciwe programowanie.

Dygresja...
Dokładniej chodzi tu o tzw. bootloader drugiego stopnia (second stage bootloader). Pierwszy booloader (first stage bootloader) znajduje się w ROM (Read Only Memory). Wypalany jest na etapie produkcji układu, nie da rady go zmienić. Inicjalizuje sam układ.


Dla M1 (i wielu nrf52x) możecie uruchomić tryb uf2:
  • Podłączcie M1 do komputera kablem USB,
  • Szybko wciśnijcie reset dwa razy (potrzeba coś cienkiego, jak spinacz, otworek jest na spodzie obudowy koło portu USB),
  • bootloader wchodzi w tryb uf2 i na Waszym komputerze pojawia się nowy napęd.
W otwartym katalogu otwórzcie plik INFO_UF2.TXT; u mnie było:

UF2 Bootloader 0.9.2-dirty lib/nrfx (v2.0.0) lib/tinyusb (0.12.0-145-g9775e7691) lib/uf2 (remotes/origin/configupdate-9-gadbb8c7)
Model: ELECROW nRF52840
Board-ID: ELECROW nRF52840-pca10056-v1
Date: Dec 12 2024
SoftDevice: S140 6.1.1


Znalazłem, że UF2 Bootloader 0.9.2-dirty to najprawdopodobniej wersja bootloadera Adafruit, stąd: https://github.com/adafruit/Adafruit_nR ... r/releases. ‘-dirty’ oznacza, że nie jest to oficjalna kompilacja, być może po pewnych zmianach. Stąd niestety flashowanie oficjalnego bootloadera adafruit… może mieć nieprzewidywalne konsekwencje.

Dygresja...
Softdevice zawiera implementację stosów komunikacji bezprzewodowej - jak Bluetooth Low Energy - BLE (ale nie tylko). Softdevice pochodzi z sdk (software development kit) Nordica. Softdevice jest dostarczany przez Nordica a jego kod nie jest otwarty.


Web flasher
Sam web flasher napisano w javascript. ‘Programująca’ część skryptu wykonuje się po stronie klienta (czyli Waszego komputera) z użyciem biblioteki do komunikacji po porcie szeregowym. Kod web flashera znajdziecie tutaj: https://github.com/meshcore-dev/flasher.meshcore.dev. Ciekawy jest config.json, który zawiera listę plików przeznaczonych do:
  • wymazywania flasha kontrolera, dla m1: ThinkNode_M1_QSPIFlash_Format-v1.2.zip – pod przyciskiem ‘Erase flash’
  • programowania przez DFU (plik spod file/flash - *.zip) – po wciśnięciu przycisku ‘Flash!’
  • programowania przez uf2, plik o rozszerzeniu spod file/download – uf2.
Wszystkie te pliki można pobrać pod przyciskiem ‘Download’.

Przycisk: Enter DFU mode
DFU (device firmware update) oznacza programowania kontrolera przez komunikację po USB. Procedura wprowadzania urządzenia w tryb DFU (a właściwie bootloadera) jest zazwyczaj różna dla różnych rodzin kontrolerów. Na przykład dla esp32 (jednym z dostępnych sposobów) jest spięcie pinu G0 do masy i wciśnięcie resetu. Ale można też inaczej, bez konieczności ‘fizycznego’ kontaktu z kontrolerem. Web flasher dla nrf52 używa tzw. „1200bps touch”. Procedura jest następująca:
  • komputer (skrypt flashera) łączy się z portem szeregowym wystawianym przez kontroler (USB CDC – wirtualny port szeregowy, widziany w komputerze jako COMx) z szybkością 1200 bps,
  • skrypt oczekuje chwilę połączony, tu 100ms,
  • skrypt zamka port.
To krótkie połączenie z szybkością 1200bps uruchomi procedurę resetu do trybu dfu bootloadera. „1200bps touch” wspierany jest przez wiele bootloaderów, jak te z Nordica, Arduino, niektóre STM.

Dygresja...
Zauważcie, że port COM zmienia się po resecie. Po prostu – teraz Wasz komputer nie rozmawia z portem szeregowym dla aplikacji – ale tym stworzonym przez bootloader do programowania. Zmieniają się identyfikatory urządzenia USB (PID/VID), zmienia się przeznaczenie.


Teraz kontroler jest gotowy do wymazywania pamięci lub programowania właściwej aplikacji MeshCore.

Przycisk: Erase flash
Flash to ta pamięć stała, w której zapisywane są programy (RAM to pamięć, gdzie programy się wykonują). nrf52840 posiada wbudowane 1MB pamięci wewnętrznej pamięci flash. W tej pamięci zapisany jest bootloader, softdevice i aplikacja MeshCore. Przed właściwym programowaniem, żeby upewnić się, że po poprzedniej instalacji nie ma pozostałości, pamięć się zeruje. Do tego właśnie ma służyć funkcja Erase Flash!

W przypadku nrf52x wymazywanie flasha jest trochę bardziej skomplikowane. Normalnie wymagałoby to programatora podłączonego bezpośrednio do płyty głównej (M1 ma port swd - single wire debug). Sam bootloader adafruit dla nrf52 wydaje się nie posiadać funkcji wymazywania chipu (dfu_transport_serial.c w bootloaderze Adafruit: brak wsparcia dla pakietu o typie 0x06 - page erase). Web flasher ładuje więc do pamięci specjalną aplikację, która wymazuje flash – a potem z powrotem resetuje kontroler i wprowadza go w tryb programowania DFU. Ale… co właściwie jest wymazywane?

Jak rozumiem komentarz na stronie github, kod aplikacji czyszczącej znajdziecie tu https://github.com/recrof/QSPIFlash-Formatter. Zakładam, że tą właśnie aplikację pobieracie klikając przycisk ‘Download’ i wybierając ‘ ThinkNode_M1_QSPIFlash_Format-v1.2*’. Warto przyjrzeć się tej aplikacji, bo zawiera ciekawe wskazówki (przydadzą się na przyszłość):
  • od 0xED000 czyszczony jest system plików LFS (little file system), rozmiar: 0x7000 (czyli 28kB) na dane użytkownika,
  • od 0xD4000 czyszczony jest kolejny system plików LFS o rozmiarze 190000 bajtów czyli 18kB na dane aplikacji.
  • czyszczenie czipu... Macronix MX25R1635F (CustomLFS_QSPIFlash.cpp)
W ostatnim kroku czyszczona jest zewnętrza pamięć flash, którą M1 posiada na płycie. Zewnętrzny układ pamięci flash ma rozmiar 2 MB. Też formatuje się go pod LFS.

Podsumowując: funkcja ‘erase flash’ tak naprawdę czyści obszary flasha (wewnętrznego i zewnętrznego) przeznaczone na systemy plików, do składowania danych. Nie usuwa aplikacji MeshCore, tylko ją nadpisuje.

Dygresja
Przedrostek ‘0x’ oznacza liczbę szesnastkową. Zamiast cyferek 0..9 jakie używanym na co dzień w systemie dziesiętnym, system szesnastkowy ma 0..9 oraz A..F. Czyli szestnastkowa 0x0f to dziesiętne 15. Stąd 0x1000 to 0*16^0 + 0*16^1 + 0*16^2 + 1*16^3 czyli 4096. A ponieważ 1 kilo-bajt to 1024 bity (w odróżnieniu do kilo-metra, który ma ‘tylko’ 1000 metrów), 4096 bitów to 4 kilo-bajty. Oczywiste, no nie?


Przycisk: Flash!
Nasz kontroler jest teraz w trybie programowania. Otwiera port szeregowy i czeka na pakiety. Web flasher wysyła kolejne pakiety nowego oprogramowania. Bootloader odbiera je, składa i zapisuje w docelowym miejscu flasha. Po odebraniu wszystkich zresetuje się a następnie wystartuje w normalnym trybie uruchamiając nową aplikację.

Dygresja
Ładowanie aplikacji do wymazywania flasha działa dokładnie tak samo jak ładowanie aplikacji MeshCore


Web flasher używa wsadów spakowanych do zip. Możecie je pobrać je za pomocą przycisku 'Download'. Dla M1 taki wsad będzie miał nazwę jak ThinkNode_M1_companion_radio_ble.zip. Jeżeli go rozpakujecie, w środku znajdziecie:
  • manifest.json
  • firmware.dat
  • firmware.bin
Zacznijmy od manifest.json. To zwykły plik tekstowy w formacie json. Element ‘manifest/application’ wskazuje, że przedmiotem programowania jest aplikacja. Ten plik może wyglądać tak:

{"manifest": {
"application": {
"bin_file": "firmware.bin",
"dat_file": "firmware.dat",
"init_packet_data": {
"application_version": 4294967295,
"device_revision": 65535,
"device_type": 82,
"firmware_crc16": 14057,
"softdevice_req": [
182
]}},
"dfu_version": 0.5}}


Dygresja...
Mógłby tu również być ‘manifest/bootloader’ – do uzupełniania bootloadera, lub ‘manifest/softdevice’ do uzupełniania softdevice. Web flasher programuje tylko aplikację.


Web flasher czyta z manifestu nazwy plików .dat i .bin, które znajdują się w archiwum zip.

Najpierw web flasher wysyła pakiet startowy (typ 0x03). Pakiet ten mówi bootloaderowi, że będzie programowana aplikacja (mode==0x04) i jaki będzie jej rozmiar. Następnie web flasher wysyła pakiet inicjalizacyjny (typ 0x01), który zapisano w pliku firmware.dat. Gdzieś znalazłem, że zakodowano go w formie protobuf. O definicję prototypu można podejrzewać plik: dfu-cc.proto (https://github.com/NordicSemiconductor/ ... u-cc.proto). Niestety wszelkie próby dekodowania przez protoc (również --decode_raw) kończyły się porażką. Być może czegoś tu nie rozumiem.
Spróbujmy zdekodować firmware.dat zmieniając jego postać z binarnej na hex np.:
> certutil -encodehex -f .\firmware.dat firmware.hex

Stąd mamy (MeshCore 1.14.1 dla M1) plik firmware.hex:
52 00 ff ff ff ff ff ff 01 00 b6 00 e9 36

Plik ten pasuje do struktury dfu_init_packet_t z bootloadera (plik dfu_init.h) i zawiera po kolei:
  • Typ urządzenia: 0x0052 (2 bajty), czyli decymalnie 82 – co jest w manifeście pod device_type,
  • wersję urządzenia (0xFFFF, 2 bajty) i wersję aplikacji (0xFFFFFFFF, 4 bajty),
  • Jedyną (0x0001) zgodną wersją softdevice z tym urządzeniem jest 0x00b6 (dec 182) – co również pokrywa się z manifestem.
  • 2 ostatnie bajty (0x36e9, dec 14057) to suma kontrolna crc16 pliku firmware.bin kodu aplikacji.
Z kodu bootloadera wynika, że sprawdzany typ urządzenia musi być równy 0x52… zdefiniowany jako… ADAFRUIT_DEVICE_TYPE. Sprawdzana jest również wersja softdevice. Liczba 182 mapuje się do FWID Softdevice S140 w wersji 6.1.1 – czyli dokładnie takiego, jaki uzyskałem eksperymentując z uf2.Wypadałoby jeszcze sprawdzić crc16 pliku firmware.bin (czyli właściwej aplikacji). Niestety CRC16 nie jest wspierany ani przez powershell ani certutil. Można użyć pythona:) (sprawdziłem, crc16 zgadzał się)

Po wysłaniu pakietu inicjalizującego następuje transfer pliku firmware.bin za pomocą pakietów o typie 0x04. Dla nrf52840 i SDK 6.1.1 aplikacje zapisywane są we flash pod adresem 0x00026000 – zaraz po softdevice.

Dygresja
Dla sdk 7.0.0+ Softdevice jest większy i aplikacje zaczynają się od 0x00027 0000. Organizacja flasha to jednak temat na osobny post.


Transfer zamyka pakiet stop o typie 0x05. Bootloader kończy zapisywanie aplikacji i resetuje kontroler.

Na koniec...
Mam nadzieję, że tym postem udało mi się trochę ‘odczarować’ web flashera. Zapraszam do dyskusji.

Źródła:
https://github.com/microsoft/uf2
https://deadbadger.cz/blog/nordic-mbr-replacement
https://docs.nordicsemi.com/bundle/sdk_ ... der_memory
https://devzone.nordicsemi.com/f/nordic ... r-nrf51822
https://learn.sparkfun.com/tutorials/sp ... ng-further
https://docs.nordicsemi.com/bundle/sds_ ... usage.html
https://devzone.nordicsemi.com/guides/s ... ash-memory
https://cdn-learn.adafruit.com/download ... -sense.pdf
https://judepereira.com/blog/nrf52840-flash-s340/
https://forum.seeedstudio.com/t/cant-up ... 0/290812/5
https://forum.seeedstudio.com/t/cant-up ... /290812/26
https://arduino.github.io/arduino-cli/1 ... ification/
https://docs.nordicsemi.com/bundle/sdk_ ... r_dfu_init
https://devzone.nordicsemi.com/f/nordic ... ion-s-fwid
Ostatnio zmieniony sob mar 28, 2026 7:47 pm przez kera, łącznie zmieniany 2 razy.
bikeman
Site Admin
Posty: 131
Rejestracja: pt gru 15, 2023 9:13 pm
Lokalizacja: SQ6B, QTH Wrocław

Re: MeshCore Web Flash - analiza działania (nRF52)

Post autor: bikeman »

Kawał wiedzy, dużo pracy włożyłeś :-) Dziękuję za publikację. Może warto wrzucić linka do artykułu na pejsbuka, na grupy meshcore i meshtastic?
ODPOWIEDZ