Raspberry Pi Pico – Come iniziare
Pochi giorni fa Raspberry Pi Foundation ha annunciato il Raspberry Pi Pico. Si tratta di un prodotto molto diverso da quelli a cui Raspberry ci ha abituato: non si tratta di una scheda che monta un SOC, su cui quindi gira un sistema operativo, ma una scheda di sviluppo a Microcontrollore.
Raspberry Pi Foundation ha difatti realizzato il proprio primo microcontrollore che prende il nome di RP2040. Da quel punto in poi c’è stato un hype pazzesco perchè le promesse fatte da questo dispositivo sono davvero tante a partire dal prezzo stracciato: l’intera scheda (non il solo microcontrollore) costa infatti soltanto 4 dollari (io l’ho pagata €4,50 da un distributore italiano). Raspberry ci ha già abituato a cose del genere con il Raspberry Pi Compute Module, anche questo inizialmente costava una bazzecola, poi chiaramente col passare del tempo i prezzi… aumentano, anche se non credo succederà con questo, dato che è un microcontrollore che verrà adottato anche da altre aziende per realizzare le proprie schede, quindi si presume che gli alti volumi di vendita tengano il prezzo basso.
Infatti l’RP2040 sarà presto adottato anche da Arduino, Sparkfun, Pimoroni e Adafruit [1] [2] che stanno già realizzando le proprie schede di sviluppo basate su RP2040. La board, Raspberry Pi Pico, è quindi solo il primo carrier realizzato per illustrare le potenzialità del progetto di questo nuovo microcontrollore.
In questo articolo vi parlo brevemente della scheda e vediamo da subito come cominciare a scrivere programmi con essa.
Indice dei contenuti
- 1 Caratteristiche RP2040
- 2 Alimentazione
- 3 Pins non riportati sull’header
- 4 Programmare il Raspberry Pi Pico
- 5 Installare MicroPython
- 6 Programmare in MicroPython con Thonny
- 7 Utilizzare REPL
- 8 Non utilizzare REPL
- 9 Come cancellare i files
- 10 E’ necessario far partire i programmi da Thonny?
- 11 Resettare il Raspberry Pi Pico
- 12 Funzioni MicroPython su Raspberry Pi Pico
- 13 Links
Caratteristiche RP2040
Il perchè del nome RP2040 è abbondantemente spiegato sul datasheet:
Ovvero Raspberry Pi, 2 cores, core M0+, 264kB di memoria ram, assenza di memoria eeprom dati. Da questa semplice cosa si capisce chiaramente, che produrranno altri microcontrollori.
In Realtà la memoria RAM interna totale è di 284kB ma 16kB sono utilizzati per la cache dell’ Execute In Place (XIP) (una funzionalità che permette di eseguire le istruzioni direttamente dalla memoria programma senza copiarle in RAM) e altri 4kB sono utilizzati per l’USB.
Il microcontrollore ha quindi un Core (anzi, due!) ARM Cortex M0+.
Sono presenti due PLL: uno per l’USB, settato a 48MHz e uno per il sistema, settato di default a 125MHz e con la possibilità di arrivare fino a 133MHz.
In realtà sul libro, a pag.125 si legge che il core gira a 48MHz, ma nel codice sorgente dell’SDK si evince che viene abilitato il PLL di sistema ed impostato per girare a 125MHz.
L’RP2040 non ha memoria Flash, è quindi necessario utilizzare flash esterne attraverso il bus QSPI. Sul Raspberry Pi Pico è montata una memoria Flash W25Q16 che offre 2MB di storage per il programma ma l’RP2040 supporta fino a 16MB di memoria Flash esterna.
Altre caratteristiche dell’RP2040 sono:
- 30 GPIO (sul Raspberry Pi Pico ne sono riportati all’esterno solo 26, vedremo dopo perchè)
- 4 GPIO possono essere utilizzati come ingressi analogici (sul Pico ne sono disponibili solo 3)
- 2 UART, 2 SPI, 2 I2C
- 16 canali PWM
- Controller DMA
- Controller USB1.1 con modalità host e device
- 8 PIO
- Serial Wire Debug (SWD)
Il PIO è una cosa interessante: si tratta di funzionalità dei GPIO che permettono al GPIO stesso di lavorare in maniera autonoma sfruttando macchine a stati. Questo torna utile per realizzare, ad esempio, bus di comunicazione per i quali non è presente una periferica hardware dedicata.
Alimentazione
Normalmente il Raspberry Pi Pico viene alimentato tramite la porta USB ma la circuiteria a bordo permette una serie di modalità di alimentazione veramente flessibili che non ci costringono ad utilizzare step-up/step-down esterni. Vediamo un po’ lo schema di questa sezione:
Sul pinout esterno sono presenti quei due punti indicati come VBUS e VSYS sullo schema. A valle troviamo un regolatore buck-boost: cosa vuol dire? Questo tipo di regolatore fornisce in uscita sempre 3.3V sia che la tensione in ingresso sia più alta (buck) sia più bassa (boost). Il regolatore accetta infatti in ingresso da 1.8 a 5.5V. Vediamo quindi come funziona questa catena di alimentazione.
Quando forniamo tensione sulla porta USB, tale tensione è presente sul pin VBUS e tramite il partitore formato da R10 e R1, possiamo monitorare con il GPIO24 la presenza di tale tensione.
Possiamo monitorare solo la presenza dato che il GPIO24 non ha funzione analogica.
Mediante un diodo Schottky si arriva al punto indicato come VSYS e la tensione entra quindi nel regolatore buck-boost. La presenza del Diodo permette di mettere in OR un’altra tensione su VSYS.
Questo vuol dire che se alimentiamo a 5V dalla porta USB (o direttamente da VBUS) è possibile, ad esempio, mettere una batteria Lipo (3.7V) oppure due stilo (3V) su VSYS attraverso un diodo come indicato sul datasheet:
Il diodo aggiuntivo (che dobbiamo inserire obbligatoriamente!) fa in modo che la tensione da VBUS non entri nella seconda sorgente di alimentazione e quindi solo la tensione più alta tra le due riuscirà a passare. La soluzione migliore, invece del diodo, è quella di utilizzare un Mosfet a canale P che isola completamente la batteria/sorgente secondaria su VSYS:
Vi consiglio di leggere il Datasheet del Raspberry Pi Pico per tutti i suggerimenti, ma come vedete c’è davvero molta flessibilità. Da una parte di schema che non ho riportato sopra si nota anche che la tensione su VSYS può essere monitorata dal GPIO29 (che corrisponde all’ingresso analogico numero 3): qui la tensione su VSYS arriverà divisa per 3 grazie ad un partitore.
Il GPIO23 invece controlla una particolare modalità di funzionamento del regolatore buck-boost.
Pins non riportati sull’header
Come dicevo sopra, e ho anticipato con la discussione sulla sezione alimentazione, i GPIO dell’RP2040 sono 30 (numerati da 0 a 29) ma sul Raspberry Pi Pico c’è un vuoto: da GPIO22 si passa a GPIO26 e manca GPIO29. Parte di questo l’avete già capito dalla sezione alimentazione.
- GPIO23 : controllo PS del regolatore buck-boost
- GPIO24 : presenza tensione VBUS
- GPIO25 : led on board
- GPIO29 : monitoraggio tensione VSYS (diviso 3) => ADC3
Programmare il Raspberry Pi Pico
Di default (ovvero: appena lo togliamo dalla scatola) il Pico (userò spesso questo nome, abbreviato, da ora in poi, per evitare di scrivere per esteso il nome), quando è collegato al PC si avvia in modalità storage di massa ed accetta, trascinandoli da una normale finestra di esplora risorse, files in formato UF2.
Il formato UF2 è stato inventato da Microsoft appositamente per flashare microcontrollori attraverso la modalità MSC (Mass Storage Class ovvero una memoria flash rimovibile).
Una volta caricato un file qualsiasi in formato UF2, il Pico, quando andremo a collegarlo la seconda volta al PC, non verrà più visualizzato come memoria di massa ed eseguirà il programma caricato, contenuto nel file UF2. Per poter caricare un nuovo file UF2 bisogna sempre tenere premuto il tasto Bootsel e collegare quindi l’USB al PC.
Nella pagina del Getting Started ufficiale è disponibile addirittura un UF2 che cancella tutto il contenuto riportando il Pico alle impostazioni di fabbrica come appena preso dalla scatola. Ne parlerò dopo.
L’unico programma presente sul Pico quando lo togliamo dalla scatola, quindi, è il solo Bootloader che ha il compito di far vedere la scheda come unità di storage (alla primissima accensione o dopo pressione del tasto), leggere un file UF2 e scriverlo nella memoria programma.
E’ possibile programmare il Pico sia in C/C++ che in MicroPython ma ci sono delle differenze nella modalità di programmazione.
Quando si utilizza il C, alla fine di tutte le operazioni di programmazione e compilazione si ottiene proprio un file in formato UF2: lo si trascina nella memoria di massa (disponibile con il Pico vergine oppure dopo aver premuto il tasto) e non appena finisce il caricamento, il programma viene subito copiato in memoria programma dal bootloader e viene eseguito.
Quando si programma in Python il meccanismo è totalmente diverso: si carica, solo la prima volta, il file UF2 dell’interprete MicroPython. Da questo momento in poi il Pico genera una porta COM e resta qui in ascolto. Il nostro programma scritto in MicroPython (quindi NON compilato) viene caricato nella memoria programma tal quale tramite seriale. Se il programma si chiama main.py verrà eseguito in automatico alla successiva accensione (l’interprete MicroPython rileva quel particolare nome e lo avvia), oppure è disponibile nella memoria programma e può essere eseguito inviando dei comandi all’interprete sulla seriale (di questo se ne occupa un programma apposito sul PC).
Oppure, ancora, sarebbe possibile scrivere un main (che quindi parte in automatico) che visualizza l’elenco dei programmi disponibili (magari su un display) e da all’utente la possibilità di scegliere quale eseguire: questo è quello che succede, ad esempio, con M5Stack.
La differenza abissale quindi, tra i due linguaggi, è che il C viene compilato e quindi eseguito nativamente mentre il python, che è un Linguaggio di scripting, deve essere interpretato per cui è necessario un altro programma a bordo del microcontrollore che, oltre a prendersi una fetta di spazio nella memoria Flash (in MicroPython sono disponibili 1.4MB di memoria programma contro i 2MB totali disponibili al C), legge le istruzioni e le converte in linguaggio macchina. Per questo motivo il Python è decisamente più lento ed inadatto a svolgere determinati compiti (si incontreranno spesso programmi per Pico che includono nello script Python delle istruzioni in assembler). Per contro è un linguaggio molto apprezzato e per molti risulta più facile del C.
Mi fa strano fare questa affermazione perchè per me non è assolutamente così, ma ognuno ha la sua opinione.
Installare MicroPython
Poco fa ho detto che il MicroPython è lento rispetto al C. Perchè quindi questo paragrafo? Semplice, perchè ho preso il Pico proprio per provare questo linguaggio. Sono un po’ abituato al Python sul Raspberry Pi e il MicroPython è praticamente uguale: c’è tutta la questione che non esistono le parentesi graffe e si usa l’indentazione, che tra l’altro è una cosa che personalmente odio… ma a tantissima gente piace e sono più mosso dalla voglia dal capire il perchè piuttosto che da altro.
Ad ogni modo questo articolo non sarà assolutamente un tutorial sul Python/MicroPython ma è incentrato sulla modalità di programmazione del Raspberry Pi Pico in Micropython. Si tratta comunque di un linguaggio molto facile: se siete abituati al C dovete solo abituarvi ad utilizzare le indentazioni al posto delle parentesi graffe, tutto il resto sarà più automatico.
Per programmare in MicroPython sul Pico bisogna avviarlo in modalità Storage di massa: se l’avete appena preso dalla scatola, si avvia già così, altrimenti prima di collegarlo al PC, tenete premuto il tasto Bootsel e collegatelo.
A questo punto andate su questa pagina, scorrete un po’ verso il basso e, dove c’è scritto Download the correct Microphyton UF2… cliccate sul link Raspberry Pi Pico (oppure sul link Raspberry Pi Pico W se avete acquistato il modello dotato di modulo WiFi):
Il File UF2 che scaricate in questa sezione è appunto l’interprete MicroPython. Una volta scaricato, trascinatelo nella memoria di massa del Pico. Su windows si sentirà il suono di periferica disconnessa e dopo un po’ quello di periferica connessa: non sarà più presente lo storage di massa e verrà riconosciuta una nuova porta COM.
In realtà la seguente procedura è stata automatizzata da Thonny (che illustro di seguito), ma ve l’ho illustrata ugualmente per farvi capire il meccanismo del caricamento di un file UF2.
Per programmare in C (lo dico con altre parole) non è necessario caricare un interprete: la toolchain genera un file UF2 del nostro programma.
Programmare in MicroPython con Thonny
Thonny è un programma che consente di comunicare con vari dispositivi programmabili in MicroPython, gestirli, scrivere e testare il codice. Scaricare Thonny dal sito ufficiale.
La prima volta che Thonny viene avviato, nel campo Initial Settings selezionare Standard. Cliccare quindi sul tasto Let’s Go!
Dalla versione 3.3.3 di Thonny il Raspberry Pi Pico è supportato da subito, nelle versioni precedenti era necessario installare un plugin preso dal repository Github di thonny-pico.
Di seguito faccio vedere tutti i passaggi ma in realtà, se si collega un Raspberry Pi Pico vergine (o resettata con l’apposito UF2) Thonny se ne accorge e chiede se installare l’ultima versione di MicroPython e fa tutto in automatico. Questa è una funzionalità molto utile e rapida, ma vedere tutti i passaggi è meglio dal momento che se dovessero esserci problemi, sappiamo dove mettere le mani.
Collegare via USB il Raspberry Pi Pico (NON premete il pulsante!) e avviare nuovamente Thonny. Dal menù Run selezionare Select Interpreter
Nella finestra che compare, dal menù a discesa presente nella scheda Interpreter, selezionare Micropython (Raspberry Pi Pico):
Più in basso selezionare la porta COM relativa al Raspberry Pi Pico (nel mio caso è uscita COM44):
Diamo Ok. Nella Shell deve comparire questo:
I tre segni >>> viola rappresentano un Prompt. Nel caso in cui questa shell non si presenti bisogna provare a staccare e riattacare il cavo USB e ripetere i passaggi da Run > Select Interpreter in poi. Oppure a premere il tasto STOP presente nella barra di Thonny.
Ora dalla Shell è possibile eseguire programmi in MicroPython utilizzando REPL.
Utilizzare REPL
REPL è una sigla che sta per Read Evaluate Print Loop ed indica la possibilità, dell’interprete MicroPython a bordo del Raspberry Pi Pico, di leggere il comando inviato sulla shell, valutarlo (eseguirlo), scrivere una eventuale risposta al comando e Ricominciare daccapo (Loop) ogni volta che viene inviato un comando.
Il REPL è una funzionalità del MicroPython e di altri linguaggi di scripting, non è una cosa propria del Raspberry Pi Pico. E’ una sorta di shell standard.
Vediamo come funziona. Nel riquadro in basso, che ha il titolo Shell, scriviamo ad esempio:
print('Ciao a tutti') |
e diamo invio:
Vediamo che REPL ha eseguito la riga di codice scritta in Python. Ora scriviamo:
from machine import Pin |
Diamo invio. Vediamo che si presenta di nuovo il prompt. Scriviamo quindi:
led=Pin(25, Pin.OUT) |
E diamo invio. Scriviamo:
led.value(1) |
Nella shell compare questo:
e il led sulla Raspberry Pi Pico si accende. Se scriviamo:
led.value(0) |
il led si spegne. Abbiamo eseguito il primo programma scritto in MicroPython utilizzando REPL. Per imparare a programmare in MicroPython sul Raspberry Pi Pico e imparare ad utilizzare tutte le funzioni torna utile il libricino ufficiale, che potete acquistare come cartaceo o scaricare gratuitamente in PDF (ho messo il link a fine articolo).
Non utilizzare REPL
Chiaramente REPL serve soltanto a fare delle prove rapide di funzionamento. Ma un programma intero può essere scritto nell’area superiore di Thonny dove compare l’editor. Nell’area superiore scriviamo
print('Ciao a tutti') |
Diamo invio. Vediamo che non accade nulla. Premiamo il tasto Run (la freccia nel cerchietto verde):
Si presenta una finestra che chiede dove salvare il file appena fatto: se sul computer o direttamente sul Raspberry Pi Pico:
Clicchiamo sul tasto Raspberry Pi Pico e diamo il nome hello_world.py
Il nome del file deve sempre avere estensione .py per essere interpretato come script Python, in aggiunta si può usare qualsiasi nome ma i nomi boot.py e main.py sono riservati, vedremo dopo cosa succede se diamo questi nomi.
Appena diamo invio vediamo che nella shell compare l’output del programma appena salvato:
La prima riga che compare nella Shell %Run -c $EDITOR_CONTENT è in realtà un comando che Thonny ha inviato all’interprete MicroPython residente sul Raspberry Pi Pico, utilizzando REPL.
A questo punto viene la curiosità di andare a vedere dove è stato salvato il programma dato che l’unità rimovibile non è più presente. Da Thonny clicchiamo l’icona Open
Ci si presenta di nuovo una finestra che ci chiede da dove aprire il file:
Capite che le cose cominciano a diventare più chiare: premete ovviamente il tasto Raspberry Pi Pico e vedete cosa accade:
I files si trovano all’interno della Flash del Pico e sono visibili soltanto utilizzando Thonny o altri programmi che comunicano con REPL. Da questo menù possiamo selezionare il file salvato e premere OK per ricaricarlo ed eseguirlo. Il file verrà ricaricato tal quale nell’editor ed eseguito quando andremo a premere il tasto Play.
Viene quindi spontaneo farsi delle domande del tipo “come cancellare i files” e “ma così sono costretto ad avviare ogni volta Thonny per eseguire un programma”. Almeno queste sono le domande che mi sono fatto io e di seguito ci sono le risposte.
Come cancellare i files
Dal menù Open selezioniamo il file che vogliamo eliminare e clicchiamo sulle 3 piccole lineette in fondo alla scritta Raspberry Pi Pico e selezioniamo Delete:
Da questo menù è anche possibile visualizzare lo spazio rimanente selezionando Storage Space
E’ necessario far partire i programmi da Thonny?
No. Se ad un programma diamo il nome main.py questo verrà eseguito in automatico all’accensione del Pico. Facciamo una prova: scriviamo il classico programma per far lampeggiare il led. Nell’editor scriviamo l’esempio che si trova sul repository Github
Questo esempio è già più avanzato di quelli classici perchè sfrutta l’interrupt su un timer
from machine import Pin, Timer led = Pin(25, Pin.OUT) tim = Timer() def tick(timer): global led led.toggle() tim.init(freq=2.5, mode=Timer.PERIODIC, callback=tick) |
Premiamo il tasto Run, scegliamo di salvare sul Raspberry Pi Pico. Diamo il nome main.py.
Il led comincia a lampeggiare. Chiudiamo Thonny. Stacchiamo e riattacchiamo il Pico: vediamo che il led lampeggia perchè il programma è partito in automatico. Se apriamo Thonny, possiamo aprire il contenuto del Pico come abbiamo visto prima e cancellare il main.py se non lo vogliamo più, oppure aprirlo, salvarlo con un nome un diverso (dal menù File > Save As > Raspberry Pi Pico oppure lo salviamo sul computer) e quindi eliminare il main.py.
Come vedete tutta la procedura è abbastanza semplice.
Resettare il Raspberry Pi Pico
Mettiamo il caso che non ci funziona più niente, che abbiamo combinato dei pasticci con un main, che Thonny non vede più la scheda ecc. La soluzione più facile è riportare il Pico alle impostazioni di fabbrica (se ci avevate salvato sopra dei programmi senza farvi un backup, sono solo cavoli vostri). Questo si fa andando in modalità boot (lo ripeto: si preme il tastino e si collega alla porta USB) e caricando un file che si chiama flash_nuke.uf2.
Questo UF2 si può scaricare dalla pagina di documentazione alla sezione Software Utilities. Cliccate qui.
Trascinare quindi il file flash_nuke.uf2 nella memoria di massa del Pico e attendere il riavvio.
Funzioni MicroPython su Raspberry Pi Pico
Le caratteristiche attualmente supportate dal porting di MicroPython su Raspberry Pi Pico, sono indicate al capitolo 3 del documento Raspberry Pi Pico Python SDK:
Quando saranno aggiunte nuove features sarà necessario ricaricare il file UF2 sul Pico.
Il 3 Febbraio abbiamo fatto una Live su Youtube in cui abbiamo parlato di questa scheda: link.
Links
- Getting started (generico per C e MicroPython)
- Getting started (MicroPython, guida passo passo)
- PDF Raspberry Pi Pico SDK per MicroPython
- PDF del libro “Get started with MicroPython on Raspberry Pi Pico – The official Raspberry Pi Pico Guide”
- Datasheet RP2040
- Repository Github con esempi in MicroPython
- Thonny (IDE per Micropython)
- Download Plugin Backend Thonny per Pi Pico
- Tutti gli articoli sul Raspberry Pi Pico