mercoledì 8 maggio 2024

Raspberry pi-pico

Figura 1: Raspberry pi-pico rp2040

Questa scheda è molto complessa a partire dalla MCU RP2040, come complesso è lo sviluppo di applicazioni tramite la SDK a supporto del programmatore. Il chip usa una flash memory esterna da 2Mb espandibile fino a 16Mb. Un alimentatore a commutazione ci permette di alimentarla fornendo una tensione nel range 1.8÷5.5V, ci pensa il convertitore switching a stabilizzare la tensione a 3.3V. All'interno della MCU c'è una CPU dual core ARM cortex-m0+, senza fpu (Float Point Unit), la frequenza di clock massima è di 133MHz, la SDK configura il clock per lavorare a 125MHz.

La SKD è in C, come gestore di progetto e build system usa il software cmake. L'ambiente di sviluppo integrato consigliato è VScode sul quale sarà necessario installare dei plugin. Il C++ è usabile poiché il compilatore è sempre GCC (arm-none-eabi), ma non troverete classi C++ nelle librerie a corredo. L'installazione su Ubuntu LTS 20.04 è abbastanza semplice, ma solo alcuni pacchetti potranno essere installati con il comando apt, per altri invece sarà necessario clonare i repositor da github e da una console a comandi avviare il build, inclusa la SDK. Alcuni strumenti di supporto sono presenti in altri repositor github e anche per questi è necessario clonare e avviare il build.

Installiamo la SDK

Consiglio di creare una cartella di nome devel con dentro la cartella pico e al suo interno verrà clonato il repositor della SDK e molti altri. Se non avete i pacchetti essenziali non potrete procedere, per cui installiamo prima i pacchetti dai repositor di Ubuntu tramite il comando apt.

Installazione della toolchain

Servirà avviare l'aggiornamento tramite sudo apt update, che aggiornerà il sistema, se questo risulta già aggiornato non accadrà nulla, diversamente sarà necessario premere S per confermare l'aggiornamento e allora i vari pacchetti da aggiornare verranno scaricati e poi installati e configurati in automatico.

Nel sistema serviranno anche il compilatore nativo gcc e la toolchain, questo si risolve con un comando semplice tramite apt, per cui aprite un terminale di comando e inserite i seguenti comandi.

user:~$ sudo apt update
user:~$ sudo apt install build-essential git

Quando richiesto inserite la password dell'utente per acquisire le credenziali di amministratore. user:~$ è il prompt dei comandi, il vostro sarà leggermente diverso, in sostanza il vero comando è scritto dopo il $. Quindi sudo apt update e invio. Stessa cosa per il comando seguente. Il primo comando aggiorna il sistema operativo. Il secondo comando installerà il compilatore GCC, make, git e altri pacchetti. GCC è necessario perché all'interno della SDK ci sono degli strumenti in forma sorgente che devono essere trasformati in eseguibili (elf2uf2 e pioasm), questi verranno usati da cmake in automatico quando serve. Il pacchetto git è fondamentale per clonare i repositor da github. Adesso è il momento di installare cmake, gcc-arm-none-eabi e le newlib per architettura ARM.

user:~$ sudo apt install cmake gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib

A questo punto se tutto è andato liscio possiamo passare a clonare i repositor. I principali repositor si trovano tutti su github di seguito la lista.

  • https://github.com/raspberrypi/pico-sdk.git
  • https://github.com/raspberrypi/pico-examples.git
  • https://github.com/raspberrypi/pico-extras
  • https://github.com/raspberrypi/pico-playground

Prima di avviare i comandi per clonare i repositor configuriamo le variabili di ambiente. Le due principali variabili sono: PICO_SDK_PATH e PICO_EXAMPLES_PATH.

Aprite con gedit il file .bashrc e aggiungete le righe di seguito:

# export variabili di ambiente per c_sdk pi-pico
export PICO_SDK_PATH="$HOME/devel/git/pico/pico-sdk"
export PICO_EXAMPLES_PATH="$HOME/devel/git/pico/pico-examples/"

Modificate i percorsi per puntare alle directory in cui volete clonare i repositor. Se volete modificare i percorsi ricordatevi che i comandi a seguire tengono conto di questi percorsi così come li ho specificati. Salvate il file .bashrc e se avete un terminale aperto chiudetelo e riapritelo. Verificate che le variabili di ambiente specificate siano visibile nella bash inserendo i due comandi di seguito specificati.

user:~$ echo $PICO_SDK_PATH
/home/user/devel/git/pico/pico-sdk
user:~$ echo $PICO_EXAMPLES_PATH
/home/user/devel/git/pico/pico-examples/
user:~$ 

Creiamo la cartella e cloniamo i repositor

Inserite i comandi seguenti e premete invio per ogni comando.

user:~$ mkdir -p devel/git/pico
user:~$ cd devel/git/pico
user:~/devel/git/pico$ git clone -b master https://github.com/raspberrypi/pico-sdk.git
user:~/devel/git/pico$ cd pico-sdk
user:~/devel/git/pico/pico-sdk$ git submodule update --init
user:~/devel/git/pico/pico-sdk$  cd ..
user:~/devel/git/pico$ git clone -b master https://github.com/raspberrypi/pico-examples.git

Adesso testiamo le variabili di ambiente per cambiare cartella corrente come di seguito:

user:~/devel/git/pico$ cd `echo $PICO_SDK_PATH`
user:~/devel/git/pico/pico-sdk$ cd `echo $PICO_EXAMPLES_PATH`
user:~/devel/git/pico/pico-examples$

Se non riuscite a scrivere questo carattere `, premete Ctrl + ?. Se per ogni comando viene cambiata la cartella corrente i percorsi e le variabili di ambiente sono corretti. Se ricevete degli errori avete commesso degli errori. Se la cartella corrente è devel/git/pico/pico-examples ci troviamo nella cartella giusta per avviare i seguenti comandi.

user:~/devel/git/pico/pico-examples$ mkdir build 
user:~/devel/git/pico/pico-examples$ cd build
user:~/devel/git/pico/pico-examples/build$ cmake ..

Nel riquadro seguente c'è il risultato parziale dell'ultimo comando (incluso il comando). Notate che di default la costruzione è in modo 'Release', l'altro modo è 'Debug' utile solo nel caso volessimo fare il debug tramite GDB e OpenOCD. Nel caso si voglia il modo 'Debug' il comando si trasforma in cmake -DCMAKE_BUILD_TYPE=Debug ..

user:~/devel/git/pico/pico-examples/build$ cmake ..
Using PICO_SDK_PATH from environment ('/home/user/devel/git/pico/pico-sdk')
PICO_SDK_PATH is /home/user/devel/git/pico/pico-sdk
Defaulting PICO_PLATFORM to rp2040 since not specified.
Defaulting PICO platform compiler to pico_arm_gcc since not specified.
-- Defaulting build type to 'Release' since not specified.
PICO compiler is pico_arm_gcc
-- The C compiler identification is GNU 9.2.1

Al termine di questo comando possiamo avviare la compilazione del primo esempio che di consueto consiste nel fare lampeggiare un led ad intervalli regolari. Per ogni esempio di codice faremo sempre la stessa cosa, cioè si entra dentro la cartella con il comando cd e si scrive make e invio. Di seguito i comandi per avviare la compilazione dell'esempio blink incluso il risultato parziale della compilazione.

user:~/devel/git/pico/pico-examples/build$ cd blink
user:~/devel/git/pico/pico-examples/build/blink$ make
Scanning dependencies of target ELF2UF2Build
[  0%] Creating directories for 'ELF2UF2Build'
[  0%] No download step for 'ELF2UF2Build'
[  0%] No patch step for 'ELF2UF2Build'
[  0%] No update step for 'ELF2UF2Build'
[  0%] Performing configure step for 'ELF2UF2Build'
-- The C compiler identification is GNU 9.4.0

Dal risultato parziale possiamo fare la seguente deduzione: Ogni progetto può avere diverse dipendenze, nel caso specifico leggiamo che ELF2UF2Build è una dipendenza da risolvere prima di avviare la compilazione dell'esempio. Cmake si occupa di risolvere queste dipendenze per noi al minimo costo. Il programma elf2uf2 è contenuto in versione sorgente all'interno della SDK e per potere usare questo programma è necessario avviare la compilazione, come detto ciò viene svolto in automatico da cmake. Chiaramente se il programma elf2uf2 è già stato compilato cmake considera la dipendenza già risolta e ciò ci fa risparmiare tempo di compilazione.

Compilare tutti gli esempi

Se eseguiamo il comando make nella cartella build tutti gli esempi uno dopo l'altro saranno compilati. Visto che il tempo di compilazione di tutti gli esempi non è breve, nel caso vogliate compilarli con un solo comando, aggiungete al comando make l'argomento -j4. Assicuratevi che la cartella corrente sia ~/devel/git/pico/pico-examples/build. L'argomento -j4 impegna 4 core cpu, se il vostro PC ha almeno 4 core cpu il tempo di compilazione si riduce approssimativamente di 4 volte.

user:~/devel/git/pico/pico-examples/build$ make -j4
[  0%] Performing build step for 'ELF2UF2Build'
[  0%] Performing build step for 'PioasmBuild'
[  0%] Built target bs2_default
[  0%] Built target bs2_default_padded_checksummed_asm
[100%] Built target pioasm
[100%] Built target elf2uf2
[  0%] No install step for 'PioasmBuild'
[  0%] No install step for 'ELF2UF2Build'
[  0%] Completed 'PioasmBuild'
[  0%] Completed 'ELF2UF2Build'
[  0%] Built target ELF2UF2Build
[  0%] Built target PioasmBuild
Scanning dependencies of target hello_serial
Scanning dependencies of target hello_usb
Scanning dependencies of target adc_console
[  1%] Built target blink
Scanning dependencies of target adc_dma_capture_resistor_dac_pio_h
[  1%] Generating resistor_dac.pio.h
[  1%] Built target adc_dma_capture_resistor_dac_pio_h

A questo punto siamo pronti per trasferire il primo programma (firmware) nella memoria flash della pi-pico. Il riquadro seguente mostra il risultato del comando ls (comando incluso), dato all'interno della cartella ~/devel/git/pico/pico-examples/build/blink.

user:~/devel/git/pico/pico-examples/build/blink$ ls -l
totale 1144
-rwxrwxr-x 1 user user  21744 mag  4 01:35 blink.bin
-rw-rw-r-- 1 user user 343775 mag  4 01:35 blink.dis
-rwxrwxr-x 1 user user 320392 mag  4 01:35 blink.elf
-rw-rw-r-- 1 user user 266748 mag  4 01:35 blink.elf.map
-rw-rw-r-- 1 user user  61219 mag  4 01:35 blink.hex
-rw-rw-r-- 1 user user  43520 mag  4 01:35 blink.uf2
drwxrwxr-x 4 user user   4096 mag  4 02:10 CMakeFiles
-rw-rw-r-- 1 user user   1001 mag  3 23:03 cmake_install.cmake
drwxrwxr-x 4 user user   4096 apr 29 00:09 elf2uf2
-rw-rw-r-- 1 user user  88218 apr 29 00:09 Makefile
user:~/devel/git/pico/pico-examples/build/blink$ 

Non consideriamo le due cartelle marcate in rosso, il file di nostro interesse al momento è blink.uf2. Colleghiamo il cavetto USB al PC, prendiamo in mano la pi-pico, manteniamo premuto il pulsante BOOTSEL e colleghiamo il connettore USB, rilasciamo il pulsante e riponiamo la pi-pico su un piano isolato. L'operazione appena compiuta configura la pico in modo BOOTSEL. Pochi istanti dopo questa operazione, sul desktop comparirà la notifica RPI-RP2, apriamo File e navighiamo fino alla cartella /home/user/devel/git/pico/pico-examples/build/blink, selezioniamo il file blink.uf2 e trasciniamolo verso sinitra sul device RPI-RP2. In conseguenza di ciò il device RPI-RP2 scompare e la pi-pico esegue il firmware appena trasferito nella flash. Ora ad intuito possiamo dire di aver capito che elf2uf2 serve a trasformare il file blink.elf nel formato di file .uf2. Per coloro che vogliono saperne di più circa il formato di file .uf2 possono inziare dal seguente link su github: https://github.com/microsoft/uf2. Nel mio caso specifico, collegando la pi-pico al PC senza premere BOOTSEL, il pc l'ha montata come mass storage device, presumo che ciò accade solo quando la flash è vuota.

Picotool

Picotool è uno strumento software molto utile per cui vi consiglio di installarlo. Tra le molteplici funzioni di questo strumento c'è ne sono due comodissime, la prima ci permette di entrare in modo BOOTSEL, evitando così la procedura manuale prima descritta. La seconda ci permette di riavviare il firmware, in sostanza è come premere il pulsante reset che sulla pico non è fisicamente presente. Il pin siglato RUN ci permette di eseguire il reset, ma serve una breadboard e un pulsante. Di seguito i due comandi con al descrizione della loro funzione.

Entrare in modo BOOTSEL

user:~$ picotool reboot -uf

Pochi istanti dopo la pico viene montata sul volume RPI-RP2 così possiamo trasferire il firmware nella flash memory.

Riavviare il firmware presente in flash memory (avviare il reset)

user:~$ picotool reboot -f

Immediatamente dopo avere premuto invio, il firmware riparte dall'inizio.

Altre funzioni di picotool

Quante volte vi capiterà di non ricordare qual'è il firmware inserito nella flash della pico? Bene se volete ora picotool vi permette di ricavare informazioni sul firmware e non solo, qui in conclusione vi mostro il comando generico che vi mostrerà tutte le infomazioni utili a ricavare il contenuto della flash memory.

user:~$ picotool info -a
  Program Information
 name:          blinkprint
 description:   This is a test binary.
 features:      UART stdin / stdout
                USB stdin / stdout
 binary start:  0x10000000
 binary end:    0x10008f54

Fixed Pin Information
 0:   UART0 TX
 1:   UART0 RX
 25:  On-board LED

Build Information
 sdk version:       1.5.1
 pico_board:        picopurple
 boot2_name:        boot2_w25q080
 build date:        May  5 2024
 build attributes:  Debug

Device Information
 flash size:   16384K
 ROM version:  3
user:~$ 

Il comando funziona se la pico è in modo BOOTSEL, diversamente se la pico sta eseguendo il firmware, aggingere alla a il carattere f, cioè: user:~$ picotool info -af. Vi faccio notare che la pico che sto usando non è originale e infatti c'è una flash memory da 16MB, l'originale monta una flash da 2MB. Con la pico originale, sotto Device Information compare flash size: 2048K.

Questo articolo si conclude qui, se ci sarà interesse, provvederò al più presto a scrivere l'articolo su picotool.

Licenza Creative Commons
Quest'opera è distribuita con Licenza Creative Commons Attribuzione - Condividi allo stesso modo 4.0 Internazionale