🛠 Exploiter les 3 blocs PIO et 12 machines d'état du RP2350 (avec IRQ dédiées)
Objetivos
El ADN de los chips RP2: los PIO (Programmable I/O). El RP2350 duplica la apuesta respecto al RP2040: 3 bloques PIO en lugar de 2, 12 máquinas de estado (4 por bloque) en lugar de 8, y sobre todo 2 IRQ dedicadas por bloque (PIO0/1/2_IRQ_0/1) donde el RP2040 compartía un solo par (datasheet RP2350, §3.2 tabla de interrupciones). Vas a ejecutar un PIO autónomo mientras la CPU hace otra cosa, y luego entender por qué 12 SM abren arquitecturas que el RP2040 no permitía.
Material
- 1 × placa RP2350 genérica + MicroPython rp2 (firmware RP2350)
- 1 × LED en GP25 (resistencia 330 Ω) o LED integrada
- 1 × osciloscopio lógico o simplemente una LED visible — el resto es software
Código completo
# 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)
Verificación esperada
El LED GP25 parpadea a ~1 Hz mientras el bucle Python corre a 500 ms: el PIO ejecuta su propio programa, sin ninguna instrucción de CPU. El freq=2000 de la máquina, dividido por los ~2 × 32 × 30 ciclos del doble contador, da aproximadamente 1 Hz. Luego empuja el contador: reutiliza los índices 4..11 con programas diferentes — los 12 espacios deben activarse todos, prueba de los 3 bloques.
Errores frecuentes
- Reutilizar un índice SM ya activo:
ValueError: PIO state machine in use— 12 espacios, planifícalos (0-3 PIO0, 4-7 PIO1, 8-11 PIO2). - Olvidar que cada bloque PIO tiene su memoria de instrucciones propia, compartida entre sus 4 SM: dos programas puestos en el mismo bloque en los mismos offsets se sobreescriben — dos programas en bloques diferentes son independientes, ese es todo el interés del 3er bloque.
- Frecuencia PIO vs frecuencia del sistema:
freq=deStateMachinees el reloj que das a la SM, pero el techo viene del sistema — el RP2350 está a 150 MHz, no a 125 MHz por defecto como el RP2040: recalibra los retardos[nop] [29]migrados de scripts RP2040. - Esperar una IRQ PIO «como en RP2040»: aquí cada bloque tiene 2 IRQ propias (PIO0_IRQ_0, PIO0_IRQ_1, etc.) — en C, activa
PIO0_IRQ_0_IRQnde forma distinta aPIO1_IRQ_0_IRQn; se acabaron los handlers que desempaquetan las interrupciones de todos los bloques. - WS2812: el timing de 800 kHz es crítico — mantén una SM dedicada por cadena, y sabe que MicroPython ya lo hace vía
neopixel(que coloca un PIO internamente). - Las 12 SM no reemplazan al DMA: PIO = fabricar/medir señales, DMA (16 canales en RP2350) = mover datos; combinarlos (PIO + FIFO + DMA) es el patrón de las adquisiciones de alta velocidad.
- 150 MHz ≠ 200 MHz: un analizador lógico PIO calibrado en un RP2040 overclockeado a 200 MHz muestrea mal en RP2350 — reprograma la frecuencia de muestreo.
Otros tutoriales para esta placa
- 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
Ejemplos de código para esta placa
clignotante.pyPythonbouton-interruption.pyPythonpwm-servo.pyPythonlecture-adc.pyPythonneopixel.pyPythonoled-i2c.pyPython