🛠 Exploiter les 3 blocs PIO et 12 machines d'état du RP2350 (avec IRQ dédiées)
Objectifs
L'ADN des puces RP2 : les PIO (Programmable I/O). Le RP2350 double la mise par rapport au RP2040 : 3 blocs PIO au lieu de 2, 12 machines d'état (4 par bloc) au lieu de 8, et surtout 2 IRQ dédiées par bloc (PIO0/1/2_IRQ_0/1) là où le RP2040 partageait une seule paire (datasheet RP2350, §3.2 table d'interruptions). Tu vas faire tourner une PIO autonome pendant que le CPU fait autre chose, puis comprendre pourquoi 12 SM ouvrent des architectures que le RP2040 ne permettait pas.
Matériel
- 1 × carte RP2350 générique + MicroPython rp2 (firmware RP2350)
- 1 × LED sur GP25 (résistance 330 Ω) ou LED embarquée
- 1 × oscilloscope logique ou simple LED visible — le reste est logiciel
Code complet
# pio_double.py — une PIO autonome + PWM matériel en parallèle
import rp2, time
from machine import Pin, PWM
# --- PIO0/SM0 : clignotement ~1 Hz, 100 % autonome (CPU libre) ---
@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
def blink_1hz:
set(pins, 1)
set(x, 31) [6]
label('high')
nop [29]
jmp(x_dec, 'high')
set(pins, 0)
set(x, 31) [6]
label('low')
nop [29]
jmp(x_dec, 'low')
sm = rp2.StateMachine(0, blink_1hz, freq=2000, set_base=Pin(25))
sm.active(1)
# Plan des 12 SM sur RP2350 : indices 0..3 -> PIO0,
# 4..7 -> PIO1, 8..11 -> PIO2. Sur RP2040, l'indice 8 lève une erreur ;
# ici sm2 = rp2.StateMachine(9, ...) est légal.
# --- PWM matériel en parallèle : 50 Hz « servo » sur GP2 ---
# (PWM du RP2350 : 8 tranches/16 canaux sur RP2350A,
# 12 tranches/24 canaux sur RP2350B — une tranche par fréquence servo)
servo = PWM(Pin(2), freq=50, duty_u16=int(65535 * 1.5 / 20))
n = 0
while True:
n += 1 # le CPU ne fait QUE tourner ici : la PIO pilote la LED
time.sleep_ms(500)
Vérification attendue
La LED GP25 clignote à ~1 Hz pendant que la boucle Python tourne à 500 ms : la PIO exécute son propre programme, sans aucune instruction CPU. Le freq=2000 de la machine, divisé par les ~2 × 32 × 30 cycles du double compteur, donne environ 1 Hz. Pousse ensuite le compteur : réutilise les indices 4..11 avec des programmes différents — les 12 places doivent toutes s'activer, preuve des 3 blocs.
Erreurs fréquentes
- Réutiliser un indice SM déjà actif :
ValueError: PIO state machine in use— 12 places, planifie-les (0-3 PIO0, 4-7 PIO1, 8-11 PIO2). - Oublier que chaque bloc PIO a sa mémoire d'instructions propre, partagée entre ses 4 SM : deux programmes posés sur le même bloc aux mêmes offsets se écrasent — deux programmes sur des blocs différents sont indépendants, c'est tout l'intérêt du 3e bloc.
- Fréquence PIO vs fréquence système :
freq=deStateMachineest le clock que tu donnes à la SM, mais le plafond vient du système — le RP2350 est à 150 MHz, pas 125 MHz par défaut comme le RP2040 : recalibre les délais[nop] [29]migrés de scripts RP2040. - Attendre une IRQ PIO « comme sur RP2040 » : ici chaque bloc a 2 IRQ propres (PIO0_IRQ_0, PIO0_IRQ_1, etc.) — en C, active
PIO0_IRQ_0_IRQndistinctement dePIO1_IRQ_0_IRQn; fini les handlers qui déballent les interruptions de tous les blocs. - WS2812 : le timing 800 kHz est critique — garde une SM dédiée par chaîne, et sache que MicroPython le fait déjà via
neopixel(qui pose une PIO en interne). - Les 12 SM ne remplacent pas le DMA : PIO = fabriquer/mesurer des signaux, DMA (16 canaux sur RP2350) = déplacer des données ; les combiner (PIO + FIFO + DMA) est le pattern des acquisitions haut débit.
- 150 MHz ≠ 200 MHz : un analyseur logique PIO calibré sur un RP2040 overclocké à 200 MHz échantillonne faux sur RP2350 — reprogramme la fréquence d'échantillonnage.
Autres tutoriels pour cette carte
- Flasher MicroPython sur une carte RP2350 générique et faire clignoter la première LED
- Console série sur RP2350 : USB CDC natif et UART0 de secours
- Lire l'ADC 12 bits et le capteur de température interne du RP2350
- Pico SDK 2.x sur une carte RP2350 générique : CMake, board header et PICO_BOARD
- Basculer les cœurs de Arm Cortex-M33 à Hazard3 RISC-V avec ARCHSEL
- Secure boot et TrustZone-M sur RP2350 : signer son firmware sans se faire avoir
Exemples de code pour cette carte
clignotante.pyPythonbouton-interruption.pyPythonpwm-servo.pyPythonlecture-adc.pyPythonneopixel.pyPythonoled-i2c.pyPython