Logging na 8kHz na ESP32-S3 v Arduino: spuštění programu z PSRAM (XiP)
Procesor IMU na Jupiteru se přesunuje na SPI s frekvencí 10MHz v příští desce, aby mohl zaznamenávat na frekvenci 8kHz, oproti 2kHz, kterou zvládá na I2C dnes. Na Rocketry Fóru si někdo oprávněně položil otázku, zda ESP32-S3 na frekvenci 240MHz opravdu může „zaznamenávat" na frekvenci 8kHz, namísto toho, aby jen čtl senzor touto rychlostí. Je to dobrá otázka, a přestože jsem si byl jistý, že to zvládneme, dosud jsem to neověřil, takže jsme to místo hádání správně změřili. Zde je to, co jsme zjistili, a na konci je znovu vytvořená knihovna Arduino, kterou jsme nakonec dostali, pokud si ji chcete vyzkoušet ve svých vlastních projektech.
Není to opravdu rychlost procesoru
Věc, která zastavuje většinu projektů ESP32 v rychlém zaznamenávání, není procesor, ale flash paměť. Při normálním sestavení se program spouští přímo z téže flash paměti, do které zaznamenáváte, přes malou mezipaměť. Pokaždé, když zapíšete do flash paměti, ESP vypne mezipaměť na obou jádrech, dokud se zápis nedokončí, takže jakýkoli kód, který ještě není v interní RAM, prostě zastaví. Ne zpomalí se, ale zastaví se. Zápis stránky trvá přibližně milisekundu a vymazání bloku o velikosti 64KB může zmrazit vše na 100 až 200ms. Pro letový počítač provozující pevnou smyčku, to je skutečný problém.
Co zaznamenáváme
Každý vzorek IMU je gyroskop jako tři 16bitová celá čísla a zrychlení jako tři 24bitová celá čísla, akcelerometry nízké a vysoké g sloučené do jednoho čtení, takže 15 bajtů na vzorek.
Zpočátku jsme plánovali skladovat sloučené zrychlení jako float, ale nakonec se ukázala jako lepší volba celá čísla. Jednotka je přesně 1/2048 g, což je vlastní krok akcelerometru nízké g v jeho rozsahu 16g (ST se 0,488mg je toto číslo zaokrouhleno), takže jeho čtení spadají na celá čísla a nic, co senzor měří, se neztratí. Převod zpět na g je dělení 2048, které je přesné, a 24 bitů pokrývá přibližně ±4000g, mnohem více, než je nutné pro rozsah 256g s vysokým g. To jsou 3 bajty na osu místo 4, a na rozdíl od float jej lze později delta kódovat, pokud budeme chtít (více níže).
Všechno ostatní, co Jupiter zaznamenává (letový stav 500Hz, barometr, magnetometr, GNSS, napájení a tak dále) přidává přibližně 20kB/s bez ohledu na frekvenci IMU, takže čím rychleji jdeme, tím menší podíl dat to představuje: 40% na 2kHz, čtvrtina na 4kHz a pouze 14% na 8kHz.
| Frekvence IMU | Data IMU (kB/s) | Ostatní data (kB/s) | Celkem (kB/s) | S delta (kB/s) |
|---|---|---|---|---|
| 2kHz | 30 | 20 | 50 | 42 |
| 4kHz | 60 | 20 | 80 | 64 |
| 8kHz | 120 | 20 | 140 | 108 |
Údaj ostatních dat je přibližný. Sloupec s delta je naše odhad celkového počtu do flash paměti při zrychlování, kde vibrace motoru činí delta kódování nejméně účinné, přičemž jsou delta kódovány pouze data IMU. Na startovní plošině a v klouzavé fázi by byla nižší. Více o delta kódování níže.
Jak Jupiter zaznamenává
- IMU dávkuje své vzorky ve své vlastní FIFO, takže smyčka nedělá 8000 čtení za sekundu. Běží na 500Hz a táhne všechno, co čeká v jedné dávce každý průchod, což je 16 vzorků na průchod na 8kHz.
- Každý surový vzorek přejde do kruhových vyrovnávacích pamětí v PSRAM. Nic se nem promíchává, kruhy jsou pevné bloky paměti s pozicemi čtení a zápisu, a záznamník je prostě prochází na místě. To také znamená, že data před spuštěním jsou již k dispozici, když je detekováno spuštění.
- Malá vyrovnávací paměť 4KB v interní RAM shromažďuje záznamy a zapisuje je do vyhrazené surové flash oddílu. Tento oddíl se před letem vymaže, takže během letu jde jen o zápis stránky, žádné mazání a žádný souborový systém v cestě.
- Po přistání komprimuje celý let do jednoho souboru, proustředka tak, aby nikdy nepotřeboval celý let v paměti, bez ohledu na rychlost, kterou byl zaznamenáván.
To všechno se však stále setkává s výše popsaným problémem flash paměti, což je místo, kde přichází příští část.
Spouštění programu z PSRAM
ESP32-S3 může při spuštění zkopírovat program do PSRAM a spustit jej odtud místo z flash paměti (Espressif mu říkají XIP z PSRAM). Jakmile to dělá, zápis flash už nepotřebuje vypnutou mezipaměť, takže smyčka pokračuje, když se flash zapisuje. Problém pro uživatele Arduino je, že se jedná o nastavení, které se nepoužívá v předkompilovaných knihovnách Espressifu, takže se jedná o něco, co nemůžete zapnout ze svého skicu, takže jsme znovu vytvořili knihovny S3 pro Arduino core s tímto zapnutým.
ECC, protože rakety se zahřívají
Mezitím jsme zapnuli ECC pro PSRAM. Espressif hodnotí osmit PSRAM v S3R8 na 65C, a 85C s ECC zapnutým. 65C zní hodně, ale tmavá raketa sedící na startovní plošině na slunci se uvnitř překvapivě zahřeje, takže pro letový počítač se zdálo rozumné začít. Stojí šestnáctinu PSRAM, kterou můžeme snadno ušetřit.
Stojí za zmínku, že se jedná o teplotní rating okolí, nikoliv o teplotním ratingu interního čipu. A jak Jupiter nepoužívá RF (Wifi/BT atd.), bude se pravděpodobně trochu více natahovat.
Ještě jeden malý: kde se nachází vyrovnávací paměť zápisu
Zjistili jsme, že vyrovnávací paměť zápisu 4KB také záleží. Pokud je v PSRAM, ovladač flash ESP-IDF jej zkopíruje přes malou vyrovnávací paměť 32 bajtů a zapíše každých 32 bajtů jako samostatný příkaz do flash čipu. Pokud je v interní RAM, jej předá přímo, 64 bajtů příkaz, což je maximum, co řadič flash S3 vezme v jednom. Každý příkaz stojí zhruba totéž, co nese, takže poloviční příkazy je téměř dvojnásobná rychlost: napřed jsme naměřili 209kB/s z PSRAM a 335kB/s z interní RAM. 4KB interní RAM není nic, takže ta byla snadná změna.
Test
Do firmware jsme přidali test, který zapisuje letovou vyrovnávací paměť stejně jako záznamník letů, zatímco smyčka 500Hz pokračuje v běhu, poté hlásí, jak špatně byla smyčka zadržena. Zapisuje na 55kB/s, poté 166kB/s, poté plnou rychlostí, poté vymazává vše, co zapsal. Tyto dvě sazby byly nastaveny z našeho dřívějšího plánu float (18 bajtů na vzorek) pro zaznamenávání 2kHz a 8kHz, takže jsou mírně vyšší, než je potřeba pro celé číslo, což činí test o něco obtížnějším než skutečný život. Abychom byli jasní v jedné věci, IMU na této desce je stále na I2C na 2kHz, takže rychlejší fáze jsou zátěž flash paměti rychlejšího zaznamenávání, ne rychlejší vzorkování. Stejná deska, stejný test, pouze vyměněné knihovny Arduino.
Každá buňka je stock Arduino core nejdřív, poté naše přestavěné knihovny s programem v PSRAM a ECC zapnutým. Smyčka by měla běžet na 500Hz, průchod každých 2ms, a nejhorší mezera je nejdelší doba mezi dvěma průchody.
| Zatímco flash | Rychlost smyčky | Nejhorší mezera | Přetečení FIFO |
|---|---|---|---|
| Zápis na 55kB/s | 349 → 499Hz | 15,8 → 5,4ms | 42 → 0 |
| Zápis na 166kB/s | 193 → 499Hz | 15,0 → 5,2ms | 77 → 0 |
| Zápis plnou rychlostí | 196 → 499Hz | 12,9 → 4,6ms | 24 → 0 |
| Mazání (bloky 64KB) | 17 → 499Hz | 202 → 4,9ms | 3 → 0 |
Na stock core se smyčka zhroutí, jakmile je flash obsazen, nemohla ani držet krok s fází 166kB/s (zvládla 160), a vymazání ji zastaví na 200ms. Každé přetečení je FIFO IMU plná a vzorky jsou ztraceny. S programem v PSRAM drží 499Hz skrz to všechno, včetně mazání. Nejhorší mezera asi 5ms je jen nejpomalejší průchod smyčky (děje se to bez jakéhokoliv zápisu flash paměti vůbec), FIFO IMU ji nasákne, a nic se neztratí.
Delta kódování
Delta kódování znamená ukládání, o kolik se každé čtení změnilo od posledního, namísto samotného čtení. Při těchto rychlostech je jeden vzorek velmi blízko dalšímu, takže většina změn se vejde do jednoho nebo dvou bajtů namísto dvou nebo tří. To je místo, kde si celá čísla vydělají své stravné: změna mezi dvěma celými čísly je sama o sobě malé celé číslo, zatímco bity float se nezmenšují, když se hodnota stěží pohne. V krocích 1/2048 g se změna až asi 4g mezi vzorky vejde do 2 bajtů.
Kolik se ušetří, závisí na tom, co raketa dělá. Na startovní plošině nebo v klouzavé fázi by se většina vzorků snížila na 6 až 8 bajtů, ale při zrychlování s motorem, který třeseuje všechno, je to spíše 11, a zrychlování je to, co záleží, protože tam je rychlost zaznamenávání nejvyšší. To je náš přibližný odhad spíše než měření prozatím. Jupiter v tuto dobu nepoužívá delta kódování v letové vyrovnávací paměti, protože to nepotřebuje pro rychlost. Kde by to pomáhalo, je čas zaznamenávání: vyrovnávací paměť letů 7,8MB obsahuje přibližně 58 sekund plného surovky na 8kHz, nebo přibližně 75 sekund delta kódovaného, než hybridní zaznamenávání sníží rychlost.
Takže jak rychle by to mohlo zaznamenávat?
Složením naměřených rychlostí flash paměti se velikostmi dat výše je uvedeno maximum, které každá konfigurace zvládne:
| Konfigurace | Flash, plnou rychlostí (kB/s) | Max rychlost, surové / delta (kHz) | Data 8kHz, surové / delta (kB/s a podíl flash paměti) |
|---|---|---|---|
| Stock core, vyrovnávací paměť v PSRAM* | 160 | 9 / 12 | 140 / 108 88% / 68% |
| Stock core, vyrovnávací paměť v interní RAM* | 306 | 19 / 25 | 140 / 108 46% / 35% |
| Přestavěné knihovny, vyrovnávací paměť v PSRAM | 209 | 12 / 17 | 140 / 108 67% / 52% |
| Přestavěné knihovny, vyrovnávací paměť v interní RAM (Jupiter) | 335 | 21 / 28 | 140 / 108 42% / 32% |
* Flash si poradí na stock core, ale smyčka ne. Poklesla pod 200Hz a ztratila vzorky IMU při každé rychlosti, kterou jsme vyzkoušeli, takže v praxi nemůže čistě zaznamenávat při žádné z nich.
Surové je 15 bajtů na vzorek, delta kódované je náš odhad zrychlování 11 bajtů, oboje zahrnuje 20kB/s všeho ostatního, a to jsou plné rychlosti měřené se spuštěnou smyčkou, zaokrouhleny dolů bez čehokoliv uchovávaného. Sběrnice SPI 10MHz není límit u žádné z nich, mohla by nést kolem 59 000 vzorků za sekundu.
Takže 8kHz potřebuje přibližně 140kB/s proti 335kB/s, kterou flash vezme plnou rychlostí, přibližně 42% bez jakéhokoliv delta kódování vůbec, nebo přibližně 108kB/s (32%) s ním. Procesor také nepracuje tak těžce: na 2kHz se většina průchodu smyčky čeká na sběrnici I2C, a na SPI 10MHz by mělo stejné čtení na 8kHz trvat přibližně 0,3ms. IMU sama se zastavuje na 8kHz, takže zbytek je bezpečnostní rezerva. Je to stále bench testování, dokud se deska SPI neobjeví, a výchozí hodnoty budou stejně nižší, přičemž zaznamenávání sníží jeho rychlost po zrychlování, ale S3 vypadá, že se s tím dobře vypořádá.
Vyzkoušejte si to sami
Vzhledem k tomu, že jsme dělali těžkou práci, přestavěné knihovny ESP32-S3 jsou ke stažení na konci tohoto příspěvku pro kohokoli jiného, kdo používá Arduino. Jsou pro esp32 core 3.3.12 z Boards Manageru pouze a nahrazují tuto složku:
Windows %LOCALAPPDATA%\Arduino15\packages\esp32\tools\esp32s3-libs\3.3.12 Mac ~/Library/Arduino15/packages/esp32/tools/esp32s3-libs/3.3.12 Linux ~/.arduino15/packages/esp32/tools/esp32s3-libs/3.3.12
Na Windows zavřete Arduino IDE, poté otevřete příkazový řádek (v nabídce Start zadejte cmd, ne PowerShell) a vložte toto. Najde zip ve složce Downloads bez ohledu na to, co stahování přidalo k jeho názvu, a zachová vaši původní složku jako 3.3.12.stock:
cd /d "%LOCALAPPDATA%\Arduino15\packages\esp32\tools\esp32s3-libs"
ren 3.3.12 3.3.12.stock && for %f in ("%USERPROFILE%\Downloads\*esp32s3-libs-3.3.12-xip-ecc*.zip") do tar -xf "%f"
rmdir /s /q "%LOCALAPPDATA%\arduino\cores"
Poslední řádek vymaže mezipaměť zkompilovaného jádra IDE, aby se znovu sestavil proti novým knihovnám. Chcete-li se vrátit k stock verzi:
cd /d "%LOCALAPPDATA%\Arduino15\packages\esp32\tools\esp32s3-libs" ren 3.3.12 3.3.12.xip-ecc && ren 3.3.12.stock 3.3.12 rmdir /s /q "%LOCALAPPDATA%\arduino\cores"
Nepoužívejte funkci Extract All aplikace Explorer na zip, některé cesty v něm jsou příliš dlouhé a tiše přeskočí soubory. Výše uvedený příkaz nebo 7-Zip jsou v pořádku.
Několik věcí, které je třeba vědět:
- Otestovali jsme to na S3 s 8MB osmit PSRAM (S3R8), s PSRAM nastaveným na OPI PSRAM v nabídce Nástroje. Nevyzkoušeli jsme to na quad PSRAM, a jak se program spouští z PSRAM, nehodí se pro desky bez jakéhokoliv.
- Program se zkopíruje do PSRAM při spuštění, takže ztratíte tolik PSRAM, plus šestnáctinu za ECC.
- Je sestaven s esp32-arduino-lib-builder Espressifu na ESP-IDF 5.5.5, stejně jako oficiální knihovny 3.3.12, pouze s přidanými dvěma nastavením. Veškerý kredit patří Espressifu. Je neoficiální a tak, jak je, takže si nechte svou stock složku.
Pokud byste raději sestrojili sami, je to esp32-arduino-lib-builder Espressifu (Linux nebo WSL), vrácený na verze uvedené v souboru versions.txt v oficiální složce knihoven 3.3.12, s těmito dvěma řádky přidanými do configs/defconfig.esp32s3 před spuštěním buildu:
CONFIG_SPIRAM_XIP_FROM_PSRAM=y CONFIG_SPIRAM_ECC_ENABLE=y
Procesor IMU na Jupiteru se přesunuje na SPI s frekvencí 10MHz v příští desce, aby mohl zaznamenávat na frekvenci 8kHz, oproti 2kHz, kterou zvládá na I2C dnes. Na Rocketry Fóru si někdo oprávněně položil otázku, zda ESP32-S3 na frekvenci 240MHz opravdu může „zaznamenávat" na frekvenci 8kHz, namísto toho, aby jen čtl senzor touto rychlostí. Je to dobrá otázka, a přestože jsem si byl jistý, že to zvládneme, dosud jsem to neověřil, takže jsme to místo hádání správně změřili. Zde je to, co jsme zjistili, a na konci je znovu vytvořená knihovna Arduino, kterou jsme nakonec dostali, pokud si ji chcete vyzkoušet ve svých vlastních projektech.

