// WIKI

x-cube-n6-camera-capture-nucleo

Esplorazione dello STM32N6: webcam UVC con encoder H.264 hardware.

Pubblicato il Aggiornato il STM32N6 · Cortex-M55H.264 HW encoderMIPI-CSI2 + ISPFreeRTOS + USBXCMake / Ninja
Codice su GitHub ↗

Lo STM32N6 è la prima MCU STM32 con NPU integrata (Neural-ART, 600 GOPS, 3 TOPS/W) per AI on-device, su core Arm Cortex-M55 @ 800 MHz con vettoriale Helium, 4,2 MB di RAM, ISP dedicato e acceleratori media/grafica; non ha flash interna (esecuzione Load & Run da NOR Octo-SPI esterna). Questo è il primo di una serie di progetti con cui iniziamo a testarne le capability: parte dalla pipeline acquisizione→encode H.264→streaming UVC su USB (Nucleo-N657X0-Q); seguiranno progetti che sfruttano la NPU per AI on-device. Nota: questo specifico firmware esercita il percorso imaging + encoder H.264 hardware, non ancora la NPU. Contenuti dal README del repository; il riferimento autoritativo resta GitHub.

Perché lo STM32N6

Lo STM32N6 è la prima MCU STM32 con NPU integrata: l’acceleratore Neural-ART eroga ~600 GOPS con efficienza 3 TOPS/W, abilitando inferenza AI on-device finora riservata ai microprocessori. Il core è un Arm Cortex-M55 @ 800 MHz (1280 DMIPS / 3360 CoreMark), primo Cortex-M con vettoriale Helium (MVE) — DSP e ML accelerati sulla CPU.

Completano il quadro 4,2 MB di RAM contigua (la più ampia su STM32), ISP dedicato, interfacce camera multiple e acceleratori grafici/multimediali, senza flash interna (esecuzione Load & Run da NOR Octo-SPI). In questo progetto, sul concreto: STM32N657X0HxQ, PLL1 a 800 MHz, encoder H.264 hardware (IP Verisilicon H1), ricevitore MIPI-CSI2 + ISP, USB High-Speed.

È il primo di una serie: qui validiamo end-to-end la catena imaging→encode→USB su una board accessibile (Nucleo), come base concreta su cui innestare i progetti successivi che sfruttano la NPU per AI on-device.

Cosa fa il firmware

All’avvio configura clock (PLL1 → 800 MHz) e MPU, porta su il ricevitore MIPI-CSI2 e il sensore IMX335 tramite la Camera Middleware ST + libreria ISP, e cattura i frame via DCMIPP in formato YUY2.

Il piano di luma viene dato in pasto all’encoder H.264 hardware dello STM32N6 (IP Verisilicon H1); un piano di crominanza grigio statico rende il flusso un bitstream YUV 4:2:0 valido. Le NAL unit H.264 vengono impacchettate in payload UVC Frame-Based e inviate all’host su USB High-Speed. Tutto gira su FreeRTOS con un task dedicato a cattura, encode e USB.

Risultato: una webcam UVC standard con un singolo stream, default 480×272 H.264 a 30 fps.

La pipeline di imaging: dal sensore al frame

Il sensore IMX335 non emette pixel pronti all’uso: invia su MIPI-CSI2 un flusso di dati RAW Bayer, dove ogni fotosito porta un solo colore secondo la matrice del filtro. La conversione in un’immagine visualizzabile avviene a bordo dello STM32N6, in due stadi.

Il ricevitore MIPI-CSI2 deserializza le due corsie differenziali (D-PHY), ricostruisce i pacchetti di riga e li consegna al DCMIPP (Digital Camera Memory Interface Pixel Processor), il blocco di acquisizione dello STM32N6. Il DCMIPP, appoggiandosi all’ISP (Image Signal Processor) configurato dalla libreria ST, esegue demosaicizzazione, bilanciamento del bianco, correzione del colore e conversione di spazio, scrivendo in RAM frame in formato YUY2 (YUV 4:2:2 packed: luminanza a piena risoluzione, crominanza sottocampionata in orizzontale).

Separare luminanza (Y) e crominanza (U, V) è esattamente ciò che serve allo stadio successivo, perché l’encoder video lavora su piani Y/UV e perché l’occhio umano è molto più sensibile alla luminanza che al colore — la base di tutta la compressione video moderna.

L’encoder H.264 hardware

Lo STM32N6 integra un encoder video H.264 hardware (IP Verisilicon H1): un blocco dedicato che comprime i frame senza caricare la CPU. Riceve in ingresso un’immagine YUV 4:2:0 e produce un bitstream H.264 organizzato in NAL unit (Network Abstraction Layer), le stesse unità con cui l’H.264 viaggia in qualunque file o stream.

In questo firmware l’encoder riceve solo il piano di luma prodotto dal DCMIPP; il piano di crominanza viene riempito con un grigio statico, così il bitstream resta un YUV 4:2:0 formalmente valido ma l’immagine è monocromatica. È un compromesso voluto: senza PSRAM esterna sul Nucleo non c’è banda/RAM per gestire anche i piani colore lungo tutta la pipeline. La compressione hardware riduce di molto la banda richiesta sull’USB — quanto, e quanto serva davvero a questa risoluzione, è nei conti più sotto.

Trasporto UVC su USB High-Speed

Le NAL unit H.264 non vengono salvate su file: vengono impacchettate in payload UVC Frame-Based e spinte verso l’host su USB High-Speed (480 Mbit/s). La USB Video Class (UVC) è la classe standard che rende una telecamera utilizzabile senza driver; il formato Frame-Based è quello previsto da UVC per stream compressi o non standard come l’H.264.

All’enumerazione il dispositivo si presenta come la webcam “STM32 N6 Camera”, espone i propri descrittori (formato, risoluzione, frame rate) e negozia lo stream con l’host tramite i controlli Probe/Commit. Da lì in poi è una webcam come un’altra: qualunque applicazione UVC la apre.

Architettura software su FreeRTOS

Il firmware gira su FreeRTOS, con USBX (Azure RTOS / ThreadX) per lo stack USB. Un task dedicato orchestra l’intero percorso cattura → encode → invio: attende il frame YUY2 dal DCMIPP, lo passa all’encoder H.264, raccoglie le NAL unit risultanti e le consegna allo stack UVC per la trasmissione. Il disaccoppiamento fra acquisizione, compressione e USB tramite RTOS è ciò che mantiene i 30 fps stabili senza che un blocco resti in attesa a vuoto dell’altro.

Hardware

Board NUCLEO-N657X0-Q (STM32N657X0HxQ, Cortex-M55, ST-LINK/V3 onboard, USB utente High-Speed su CN13). NOR esterna Macronix MX25UM51245G (512 Mbit Octo-SPI, onboard) per FSBL + applicazione firmata.

Camera Sony IMX335 (5 MP, 2-lane MIPI) su daughterboard MIPI-CSI2 MB1854. La Camera Middleware supporta anche altri sensori (non testati sul Nucleo). I pin di boot del Nucleo vanno impostati su Flash boot per il funzionamento standalone.

Boot model (Load & Run)

Il Nucleo-N6 non ha flash interna: il codice risiede sulla NOR Octo-SPI esterna. Il BootROM verifica la firma dell’FSBL e lo carica in AXISRAM2; l’FSBL porta su l’Octo-SPI in memory-mapped, copia l’applicazione firmata in AXISRAM e ci salta.

FSBL a 0x70000000, applicazione a 0x70100000; entrambi i binari firmati con STM32_SigningTool_CLI (chiavi dummy, solo per sviluppo). Il sotto-progetto FSBL è interamente vendorizzato in Tools/FSBL/, derivato dal template ST Template_FSBL_LRUN e convertito in build CMake standalone.

Differenze vs l’esempio ST (DK → Nucleo)

È un port/adattamento dell’esempio ufficiale ST x-cube-n6-camera-capture (board DK) al Nucleo-N657X0-Q: niente PSRAM esterna (tutti i buffer stanno in AXISRAM/DTCM interna), niente LCD/touch (l’unico output è lo stream UVC), FSBL completamente vendorizzato per poter programmare ed eseguire standalone.

Build con CMake + Ninja + task VS Code per build/sign/flash: STM32CubeIDE non è richiesto, solo STM32CubeProgrammer. Tutto il codice ST/terze parti è congelato (vendored) nel repository: niente pack esterni o progetti CubeMX.

Build, firma e flash

Toolchain testato: arm-none-eabi-gcc 14.3.1 + patch ST, CMake ≥ 3.22, Ninja ≥ 1.10, STM32CubeProgrammer 2.22.0 (richiesto per sign + flash). Wrapper cube-cmake (estensione VS Code STM32) per puntare al GCC bundled; qualsiasi arm-none-eabi-gcc su PATH va bene.

I task VS Code coprono: Configure/Build app e FSBL, Sign FSBL/App, Program FSBL (0x70000000) / App (0x70100000), il one-shot “Build + Sign + Program App” e il provisioning iniziale “Full Program (FSBL + App)”. External loader: MX25UM51245G_STM32N6570-NUCLEO.stldr.

Uso come webcam

Dopo Program App: reset della board, collegare il cavo USB utente (CN13, USB-C sul Nucleo) al PC. Compare un device UVC “STM32 N6 Camera”; si apre con qualunque app UVC — Windows Camera, OBS, VLC, ffplay (es. ffplay -f dshow -i video="STM32 N6 Camera").

Risoluzione dei problemi

  • Il dispositivo non compare. Verifica che i pin di boot del Nucleo siano su Flash boot e che FSBL e applicazione siano stati programmati entrambi (FSBL a 0x70000000, app a 0x70100000). Senza un FSBL valido il BootROM non avvia nulla.
  • Compare ma lo stream non parte. Collega il cavo alla USB utente (CN13), non alla porta ST-LINK: sono due connettori distinti. Alcune app aprono solo formati non compressi — usa un player che gestisce UVC Frame-Based/H.264 (OBS, VLC, ffplay).
  • Immagine assente o corrotta. Controlla che la daughterboard MIPI-CSI2 MB1854 con l’IMX335 sia inserita correttamente; un sensore diverso non è testato e può richiedere una configurazione ISP differente.

Dalla cattura all’AI on-device

Questo firmware esercita il percorso imaging + encoder H.264, non ancora la NPU. È il primo passo deliberato di una serie: validare end-to-end la catena sensore → ISP → encode → USB su una board accessibile, prima di innestare l’inferenza. I progetti successivi sfrutteranno l’acceleratore Neural-ART per AI on-device — rilevamento, classificazione o pre-elaborazione direttamente sullo stream, senza inviare i frame a un host. La pipeline costruita qui resta la base su cui quegli sviluppi si appoggeranno.

I tre collegamenti della catena, contati

I conti su tutta la catena servono perché il collo di bottiglia non sta dove l’intuizione lo mette — e sapere quale sia è esattamente ciò che dice se una risoluzione superiore è raggiungibile o no.

Il trasporto USB: il piu’ scarico dei tre

Una singola endpoint isocrona su USB High-Speed trasporta al massimo 3 transazioni da 1024 byte per microframe, cioè 196,6 Mbit/s. Contro quel budget:

Risoluzione Pixel YUY2 a 30 fps Sta in una endpoint isocrona HS?
480×272 130 560 62,7 Mbit/s sì
640×480 307 200 147,5 Mbit/s sì
854×480 409 920 196,8 Mbit/s no
1280×720 921 600 442,4 Mbit/s no
1920×1080 2 073 600 995,3 Mbit/s no

Il risultato è controintuitivo e va detto con precisione: a 480×272 il flusso non compresso ci starebbe, occupando il 32 % del budget. L’H.264 qui non serve a far entrare lo stream nell’USB — serve perché esercitare l’encoder hardware è lo scopo del progetto, e perché è l’unica strada per le risoluzioni che l’USB non regge: il non compresso sfonda il budget appena sopra i 409.600 pixel, quindi 854×480 è già fuori e il 720p chiederebbe 442 Mbit/s.

La memoria: il vincolo che morde davvero

Quello che ferma le risoluzioni alte su questa board non è l’USB e non è l’encoder: è la RAM, e il conto è semplice perché un frame YUY2 occupa esattamente due byte per pixel.

Risoluzione YUY2 (16 bpp) Solo luma (8 bpp) Doppio buffer YUY2 Rispetto a 480×272
480×272 255 kB 128 kB 0,50 MB × 1,0
640×480 600 kB 300 kB 1,17 MB × 2,4
854×480 801 kB 400 kB 1,56 MB × 3,1
1280×720 1800 kB 900 kB 3,52 MB × 7,1
1920×1080 4050 kB 2025 kB 7,91 MB × 15,9

Un 480×272 in doppio buffer sta in mezzo megabyte; il 720p ne chiede 3,52, sette volte tanto — e a quello va aggiunto ciò che serve all’encoder per i suoi frame di riferimento, che l’H.264 richiede per la predizione inter-frame. Senza PSRAM esterna il Nucleo non ha spazio per quella somma: è la ragione tecnica precisa del limite dichiarato più sotto, e la colonna «solo luma» spiega anche il compromesso monocromatico — rinunciare alla crominanza dimezza l’occupazione lungo tutto il percorso di codifica, da 255 a 128 kB per frame.

Il collegamento più sollecitato della catena è il primo, e la ragione è che il DCMIPP scala a valle: sul link CSI-2 viaggia il RAW alla risoluzione con cui il sensore è configurato, non i 480×272 dell’uscita.

Cosa viaggia sul link Data rate Capacità (2 lane) Occupazione
2592×1944 RAW10 30 fps (piena risoluzione) 1512 Mbit/s 2000 Mbit/s 75,6 %
1296×972 RAW10 30 fps (binning 2×2) 378 Mbit/s 2000 Mbit/s 18,9 %
480×272 RAW10 30 fps (se si potesse croppare così) 39 Mbit/s 2000 Mbit/s 2,0 %

Alla piena risoluzione dell’IMX335 le due lane sono al 75,6 % di occupazione: il link è il componente più vicino al proprio limite di tutta la catena, mentre l’USB sta al 32 % e l’encoder non fatica. È anche il motivo per cui il binning sul sensore, quando disponibile, conviene sempre: dividere per quattro i pixel sul link libera banda che nessuno stadio a valle potrà restituire. I conti si possono rifare con il calcolatore di banda MIPI CSI-2 — ricordando di aggiungere il blanking, che su questi numeri vale un altro 20–30 %.

Riassunto della catena, in una riga: MIPI 76 %, encoder comodo, USB 32 %, RAM esaurita. Chi volesse salire di risoluzione su questa board deve partire dall’ultimo termine, non dai primi tre.

Limiti noti

Output monocromatico: l’encoder H.264 richiede input YUV 4:2:0 ma viene riempito solo il piano di luma (crominanza grigia statica) — è un compromesso RAM/banda dovuto all’assenza di PSRAM sul Nucleo; la build DK dell’esempio originale fornisce il colore.

Stream singolo 480×272 @ 30 fps (risoluzioni superiori richiederebbero PSRAM esterna); le chiavi di firma sono le chiavi dummy di sviluppo ST — da non usare in produzione. Stato: prototipo funzionante, port personale pubblicato as-is.

Crediti e licenza

Riusa e adatta codice da progetti ST upstream, tutto vendorizzato nel repo con la rispettiva licenza originale: l’esempio camera-capture DK, lo STM32CubeN6 (HAL/CMSIS/BSP/FSBL ref.), l’encoder H.264 Verisilicon H1 + EWL, la stm32-camera-middleware + ISP, USBX (Azure RTOS / ThreadX), il kernel FreeRTOS e l’ExtMem Manager ST.

I file specifici dell’applicazione seguono i termini dell’esempio ST da cui derivano; ogni componente di terze parti mantiene il proprio file di licenza accanto ai sorgenti.

Ultimo aggiornamento: · Trovato un errore o un dato superato? Segnalacelo

← Torna all’indice Wiki

Un progetto simile?

Acustica, embedded, strumenti di calcolo: se hai un caso d’uso vicino, parliamone.