Přeskočit na obsah

Build firmwaru

Firmware pro PicoPad je build CircuitPythonu se zapnutým nativním modulem picogame.

Předpoklady: ARM GCC ≥ 14 a inicializované submoduly.

Terminal window
# z kořene forku CircuitPythonu
make -C ports/raspberrypi BOARD=pajenicko_picopad -j"$(nproc)"

Výstup: ports/raspberrypi/build-pajenicko_picopad/firmware.uf2. Nahraj přes BOOTSEL (podrž BOOTSEL při zapojení, pak přetáhni .uf2 na disk RPI-RP2) jako každý CircuitPython firmware.

Viz Spuštění na hardwaru pro stranu zařízení a Vejít se do RAM pro RAM rozpočet.

Kde picogame žije ve stromu

Sekce “Kde picogame žije ve stromu”

Engine je ve větvi picogame forku CircuitPythonu. Implementaci obsahují dva adresáře modulu a volby buildu zapínají samotný modul i volitelné backendy.

Cesta Co
shared-bindings/picogame/ Python API + docstringy: __init__, Scene, Sprite, Bitmap, Tilemap, Canvas, Particles, Display, Framebuffer
shared-module/picogame/ přenositelné C jádro — implementace blit / scene / tilemap / particles / canvas, bez závislosti na portu
ports/*/common-hal/picogame/Display.c volitelný rychlý backend konkrétního portu (raspberrypi a espressif ho mají)

Změny v systému buildu:

Soubor Změna
py/circuitpy_mpconfig.mk registruje pět flagů CIRCUITPY_PICOGAME* — všechny výchozí 0
py/circuitpy_defns.mk překládá picogame/% jen při CIRCUITPY_PICOGAME = 1; přidá common-hal/picogame/Display.c jen při FAST_DISPLAY = 1
ports/raspberrypi/boards/pajenicko_picopad/ deska, která engine zapíná (konfigurace níže)

Přenositelné jádro v shared-module/ skládá pixely do řádkového bufferu a předává jej kompatibilnímu busdisplay přes bus.send. Tento backend mohou použít porty, které sestaví picogame a zpřístupní podporovaný SPI displej. Každý bus.send blokuje CPU, dokud se strip nepřenese přes SPI, takže vykreslování a přenos probíhají za sebou.

ports/raspberrypi/common-hal/picogame/Display.c je jediné místo, kde engine sahá do portu — aby toto čekání omezil. Řídí SPI a DMA na RP2040 přímo:

  • Překryv. Používá dva řádkové buffery a jeden strip přenáší pomocí DMA po SPI, zatímco CPU skládá další. Vykreslování a přenos tak běží souběžně. Na předchozí DMA čeká teprve těsně před znovupoužitím toho bufferu.
  • Přímý proud dat. Otevře GRAM okno panelu jednou přes busdisplay, které nastaví DC pro první datový strip. Zbývající stripy potom přenáší přes DMA bez opakovaného nastavování a přepínání DC.
  • Znovu použitý DMA kanál. Kanál se zabere jednou a zůstává přidělený přes měkké restarty i spouštění her. pico-SDK jej při měkkém restartu neuvolní, takže nové zabrání při každém vytvoření objektu by dostupné kanály postupně vyčerpalo.

CIRCUITPY_PICOGAME_FAST_DISPLAY zapíná typ pg.Display i příslušný soubor common-hal. Bez této volby zůstává přenositelný backend přes bus.send. Překryv pomáhá při překreslení více stripů, takže u malého dirty regionu je rozdíl malý a u celé obrazovky větší. Hodnota 25–30 % naměřená v benchmarku PicoPadu závisí na konfiguraci; podmínky popisuje stránka Takt, SPI a limity displeje.

Deska zapíná engine ve svém mpconfigboard.mk:

CIRCUITPY_PICOGAME = 1 # přelož engine dovnitř
CIRCUITPY_PICOGAME_FAST_DISPLAY = 1 # backend s asynchronním DMA pro port raspberrypi
CIRCUITPY_PICOGAME_RGB444 = 0 # podpora COLMOD v panelu (viz Volby buildu)
OPTIMIZATION_FLAGS = -O2 … # vyladěné pro Cortex-M0+ (viz dodatek)
CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' # + odpovídající změna linker skriptu

SPI hodiny displeje (v board.c). Požaduj 62,5 MHz (125/2) pro ST7789, ne 60 — dělička PL022 (jen sudá) zaokrouhlí 60 dolů na poloviční rychlost. Viz Hodiny, SPI a limity displeje.

Ponech firmware obecný. Ponech plnou sadu modulů zapnutou; vypni jen to, co zařízení fyzicky nemůže použít.

Modul Stav Proč
picogame (+ rychlý DMA displej) zapnuto engine
nativní _stage (CIRCUITPY_STAGE) zapnuto umožní běh původních her ugame/stage vedle kompatibilní vrstvy picogame-stage
ulab, synthio, audio, displayio, bitmaptools, vectorio, Wi-Fi, keypad, … zapnuto obecné moduly se do firmwaru vejdou
picodvi, _eve vypnuto zařízení nemá DVI ani FT8xx hardware
qrio vypnuto dekódování QR vyžaduje kameru, kterou PicoPad nemá, a backend quirc zabírá přibližně 32 KB; generování QR přes adafruit_miniqr funguje dál

Měřený build využil přibližně 88 % firmwarové oblasti 1,5 MB. Hodnota se mění s verzí CircuitPythonu a zapnutými moduly.

Flag Výchozí Co dělá
CIRCUITPY_PICOGAME 0 přeloží engine dovnitř
CIRCUITPY_PICOGAME_FAST_DISPLAY 0 použije Display s asynchronním DMA pro porty raspberrypi a espressif; ostatní desky zůstanou na přenositelném backendu přes bus.send
CIRCUITPY_PICOGAME_RGB444 0 deska oznámí podporu 12bitového RGB444 (COLMOD) přes picogame.RGB444_SUPPORTED, aby hra zapnula Display(rgb444=True) jen tam, kde to pomáhá. Na PicoPadu je volba vypnutá, protože náklady na balení pixelů po stripech převážily úsporu přenosu SPI.
CIRCUITPY_PICOGAME_FRAMEBUFFER 0 backend s celoobrazovkovým framebufferem v RAM pro platformy s vlastním obrazovým výstupem (RP2350 DVI/HSTX, desktopový simulátor a WASM playground) místo SPI stripů
CIRCUITPY_PICOGAME_ROMFS_KB 0 vyčlení oblast assetů ve flashi (v KB) pro 0-copy ROMFS-XIP bitmapy; nastavují ji jen -romfs varianty firmwaru (např. 64)

Výška stripu. Na SPI displeji se obrazovka skládá po STRIP_H řádcích. picogame_game.setup() alokuje dva buffery o šířka × STRIP_H × 2 bajtech. Framebufferový backend je nealokuje a vrací pro oba hodnotu None. Výchozí hodnota SPI backendu závisí na FAST_DISPLAY: 8 řádků s DMA a 24 bez DMA. Jde o výchozí hodnoty pro výkon měřených backendů; menší hodnota vždy používá méně RAM. Nastavení pro desku změň přes -DPICOGAME_STRIP_H=N a pro hru přes picogame_game.setup(strip_h=N); za běhu čti picogame.STRIP_H. Víc ve Vejít se do RAM.


Dodatek: optimalizace překladače (vyladěné −O2)

Sekce “Dodatek: optimalizace překladače (vyladěné −O2)”

rp2 port CircuitPythonu má výchozí -O3. Na Cortex-M0+ PicoPadu (bez SIMD, bez FPU, 16 KB XIP cache) je většina toho, co -O3 přidává, mrtvá váha — auto-vektorizéry nemají SIMD, na který by mířily, a klonování funkcí / těžké rozvíjení smyček jen nafukuje flash. Deska proto dodává -O2 plus pět levných smyčkových průchodů, které pixelovým smyčkám pomáhají, což se rychlostí enginu rovná -O3 do ~1 % za ~150 KB méně flashe:

OPTIMIZATION_FLAGS = -O2 -funswitch-loops -fpredictive-commoning -fgcse-after-reload \
-ftree-partial-pre -fsplit-paths

Jádro interpretu MicroPythonu (gc.o, vm.o) zůstává na -O3 přes nastavení SUPEROPT_*, takže rychlost běhu Pythonu tahle volba neovlivní. Nejteplejší jediná smyčka (základní sprite blit) navíc nese #pragma GCC unroll 4 — na M0+ ~8 % rychleji za +0,3 KB; -funroll-loops přes celý firmware by přetekl flash oblast.

Naměřeno na zařízení; všechny buildy používají CircuitPython 10.3.0. Méně = rychlejší a nejlepší ve sloupci tučně. Engine = picogame_bench_hotpath.py (108 spritů 32×32 přes 120 snímků na 320×240, ms/snímek min); Python = bench_optlevel.py (ms/op); flash = celý velikost obrazu v KB. Řádek O2+ je dodávaný referenční build; každé 🟢/🟡/🔴 značí, jak daleko buňka sedí od něj (lepší / ≤5 % horší / >5 % horší).

bg-fill
ms
plain
ms
plain+bg
ms
tint
ms
transpose
ms
bignum
ms
int
ms
float
ms
fib
ms
ulab-py
ms
ulab-np
ms
flash
KB
-O3 (výchozí rp2) 24.9 🟢−1.2% 36.3 🟡+0.8% 37.0 🟡+0.1% 80.2 🟢−0.5% 46.1 🟡+0.3% 98.8 🔴+8.8% 20.84 🟡+2.1% 40.80 🟡+1.3% 657.8 🟢−0.0% 2.63 🟢−2.2% 0.76 🔴+17% 1499 🔴+11%
-O2 25.3 🟡+0.4% 38.2 🔴+5.9% 39.1 🔴+5.7% 81.2 🟡+0.8% 53.9 🔴+17% 92.0 🟡+1.3% 20.29 🟢−0.6% 40.34 🟡+0.1% 660.2 🟡+0.3% 3.77 🔴+40% 0.66 🟡+1.5% 1326 🟢−1.4%
-Os 27.0 🔴+7.4% 43.6 🔴+21% 46.4 🔴+25% 121.9 🔴+51% 103.0 🔴+124% 113.3 🔴+25% 21.18 🟡+3.7% 44.07 🔴+9.4% 667.3 🟡+1.4% 3.00 🔴+11% 0.73 🔴+12% 1167 🟢−13%
O3− (−O3 bez vektorizérů + klonování) 25.2 🟡+0.1% 36.2 🟡+0.5% 37.2 🟡+0.6% 81.5 🟡+1.1% 46.1 🟡+0.2% 96.1 🔴+5.8% 20.32 🟢−0.5% 40.95 🟡+1.7% 662.8 🟡+0.7% 2.75 🟡+2.2% 0.68 🟡+4.6% 1480 🔴+10%
O2+ (dodávaný — baseline) 25.2 36.0 37.0 80.6 46.0 90.8 20.42 40.28 658.0 2.69 0.65 1345

-Os zmenší flash nejvíc, ale rozbije affine/blend smyčky (tint +51 %, transpose +124 %); O3− rychlost enginu sedí, přesto zůstává +134 KB, protože celofirmwarové inlinování -O3 přežije; sloupce Pythonu se téměř nemění, protože jádro interpretu je -O3 v každém buildu. (bench_displayio.py vyšel napříč úrovněmi plochý, tak je vynechaný.)