Laboratorio microcontrollori e open source Terza parte

Transcript

Laboratorio microcontrollori e open source Terza parte
POuL
Laboratorio microcontrollori e open source
Terza parte
Politecnico Open unix Labs
20 aprile 2012
Laboratorio microcontrollori e open source Terza parte
1/ 43
Introduzione Per chi si è perso le prime lezioni
Questo corso è una breve introduzione ai microcontrollori, concentrandosi sia sugli
aspetti software di programmazione che hardware di costruzione di circuiti.
Verranno presentate due piattaforme per lo sviluppo di applicazioni:
Arduino che è una piattaforma molto popolare basata su microcontrollori
Atmel a 8bit
STM32, una architattura di microcontrollori più potente a 32bit, usando il
sistema operativo Miosix.
Tutto il corso sarà tenuto in ambiente Linux, usando solo strumenti Open Source.
POuL
Laboratorio microcontrollori e open source Terza parte
2/ 43
Struttura del corso Per chi si è perso le prime lezioni
Il corso si compone di tre lezioni.
POuL
Lezione 1: Basi di Arduino
Breve introduzione ai microcontrollori
Breve introduzione ad Arduino
Ampia sessione di sperimentazione pratica con semplici esempi usando Arduino
Lezione 2: Basi di STM32 e Miosix
Breve introduzione ai microcontrollori STM32
Breve introduzione a Miosix
Ampia sessione di sperimentazione pratica con semplici esempi usando STM32
e Miosix
Lezione 3 (oggi): Progetti avanzati
Verranno mostrati progetti più complessi basati sia su STM32 che Arduino
Laboratorio microcontrollori e open source Terza parte
3/ 43
Prima di cominciare
Questa sarà l'ultima lezione di questo corso. Per chi, dopo aver seguito il corso,
volesse comprarsi un Arduino o una stm32f4discovery è possibile acquistarli online.
Per esempio, è possibile comprarli da RS (https://it.rs-online.com/web/) con il
vantaggio che si può scegliere se farsi spedire a casa il materiale (pagando le spese
di spedizione) oppure andare diretamente a ritirare i componenti a Vimodrone
(raggiungibile con la metro).
Oltre alle board di sviluppo sullo stesso sito è possibile comprare anche le
breadboard, led, resistenze, pulsanti, li, etc.
POuL
Laboratorio microcontrollori e open source Terza parte
4/ 43
Prima di cominciare
POuL
Laboratorio microcontrollori e open source Terza parte
5/ 43
Prima di cominciare
POuL
Laboratorio microcontrollori e open source Terza parte
6/ 43
Progetto #1: Giochino LCD
Speciche del progettino:
Realizzare un piccolo gioco collegando un pulsante e lo schermo LCD. Il giocatore
deve schiacciare il pulsante quando sul display appare un determinato simbolo (X)
e non deve schiacciarlo quando ne esce un altro (O).
I simboli devono apparire in una posizione casuale dello schermo e rimanere
visualizzati per un numero variabile di millisecondi. Due LED (rosso e verde)
segnaleranno all'utente se ha premuto il pulsante correttamente.
POuL
Laboratorio microcontrollori e open source Terza parte
7/ 43
Progetto #1: Interrupt
Esistono tecniche per controllare lo stato di un ingresso in Arduino.
POuL
Polling Si controlla periodicamente lo stato dell'ingresso per controllare se
è cambiato.
Interrupt Con l'aiuto di hardware dedicato l'evento viene noticato
direttamente al software.
Laboratorio microcontrollori e open source Terza parte
8/ 43
Progetto #1: Interrupt in Arduino
Il funzionamento degli interrupt è analogo a quello che (forse) avete studiato in un
corso di informatica. Usano la funzione
attachInterrupt
è possibile associare al
cambiamento di stato di un ingresso la chiamata di una funzione.
POuL
attachInterrupt(<interrupt>, <function>, <mode>)
interrupt Numero dell'interrupt. In Arduino sono disponibili l'interrupt 0
associato al pin 2 e l'interrupt 1 associato al pin 3.
function La funzione da richiamara quando si verica l'evento.
mode Modo in cui devi vericarsi l'evento:
LOW
CHANGE
RISING
FALLING
Quando il segnale diventa basso
Quando il segnale cambia valore
Quando il segnale passa da basso ad alto
Quando il segnale passa da alto a basso
Laboratorio microcontrollori e open source Terza parte
9/ 43
Progetto #1: Numeri casuali
Vogliamo che il nostro gioco non sia prevedibile. Il posizionamento del simbolo, la
scelta del simbolo e il tempo di visualizzazione devono essere casuali.
In arduino esistono delle funzioni per generare un numero casuale.
randomSeed(<value>) Inizializza il generatore di numeri casuali.
random(<min>, <max>) Genera un numero casuale tra un minimo
(incluso)
e un massimo (escluso).
Tipicamente si sceglie come seed iniziale il valore letto da un input analogico che
collegato (questop garantisce una discreta casualità).
POuL
Laboratorio microcontrollori e open source Terza parte
10/ 43
Progetto #1: Giochino LCD
POuL
Pratica: costruzione del circuito
Laboratorio microcontrollori e open source Terza parte
11/ 43
Progetto #2: Memebox
Conoscete gli internet meme?
Speciche:
Collegare due pulsanti e delle cue alla board stm32f4discovery, il primo pulsante
deve far partire il sad trombone, il secondo un rickroll.
POuL
Laboratorio microcontrollori e open source Terza parte
12/ 43
Progetto #2: Memebox
Organizzazione del progettino
POuL
Hardware: il DAC audio
Hardware: la periferica I2S
Teoria: il DMA
Software: compressione audio
Software: come embeddare un le audio in un programma
Software: la classe ADPCMSound e la classe Player
Pratica: costruzione del circuito
Laboratorio microcontrollori e open source Terza parte
13/ 43
Progetto #2: Memebox | DAC Audio
La board stm32f4discovery ha tra le sue periferiche un DAC di tipo CS43L22.
Questo DAC non è interno al microcontrollore, si tratta di un circuito integrato
separato.
Le sue principali caratteristiche sono:
POuL
Uscita stereo per cue e per altoparlante (la board usa solo l'uscita cue)
Il DAC è a 24bit, ed è in grado di decodicare segnali campionati no a
96KHz
Il microcontrollore comunica con il DAC attraverso due bus, uno di tipo I2S
per inviare i dati audio, e uno di tipo I2C per inviare comandi, come alzare o
abbassare il volume.
Laboratorio microcontrollori e open source Terza parte
14/ 43
Progetto #2: Memebox | I2S
I2S è un protocollo per trasferire dati audio non compressi, come può essere lo
stream tra un processore e un DAC audio.
Il microcontrollore STM32 ha una periferica I2S. Tale periferica può essere usata
in modalità
POuL
Polled: il processore invia un campione audio, aspetta che venga trasmesso,
poi invia il successivo...
Interrupt: il processore invia il primo campione audio direttamente, poi
quando è stato trasmesso, un interrupt viene generato che provvede a inviare
il secondo. Trasmesso anche il secondo campione verrà generato un altro
interrupt che invia il terzo campione...
DMA: il processore prepara un buer con un certo numero di campioni, poi
avvia il DMA che invierà al DAC audio i vari campioni, uno dopo l'altro
mentre la CPU ha la possibilità di riempire un secondo buer. Una volta
trasmesso l'intero buer il DMA genera un interupt che congurerà il DMA
per trasmettere il buer che nel frattempo la CPU avrà preparato...
Laboratorio microcontrollori e open source Terza parte
15/ 43
Progetto #2: Memebox | DMA
Stime dei tempi:
Il DAC è stato congurato per produrre un segnale audio stereo a 44.1KHz.
Quindi occorre che la CPU invii due campioni (destro e sinistro), 44100 volte al
secondo, ossia un campione ogni 11µs. Si tratta di un tempo troppo piccolo
perchè la CPU possa fare altro, non conviene usare la modalità polled.
D'altronde, usando gli interrupt la CPU dovrebbe servire 2*44100=88200
interrupt al secondo, che considerando l'overhead richiesto per entrare e uscire da
un interrupt porterebbe a uno spreco della CPU.
Il DMA è quindi la soluzione più attraente per questo genere di appliazioni, anche
considerando che se lo stream audio dovesse interrompersi anche per pochi
millisecondi, l'utente se ne accorgerebbe.
POuL
Laboratorio microcontrollori e open source Terza parte
16/ 43
Progetto #2: Memebox | compressione
I le audio raggiungono facilmente anche grandi dimensioni, quindi conviene
memorizzarli compressi.
La CPU dell'STM32 è abbastanza potente da decodicare formati come l'MP3,
ma decodicare formati così complessi richiederebbe troppe linee di codice.
Una soluzione semplice è la codica ADPCM che riduce la dimensione dei le
audio a un quarto della dimensione originale, ed è abbastanza semplice.
POuL
Laboratorio microcontrollori e open source Terza parte
17/ 43
Progetto #2: Memebox | embedding
Dove memorizzare un le audio nella board?
Se la board avesse un connettore per memorie microSD si potrebbe usare il
backend di lesystem di Miosix, ma la board non ha questa possibilità. Però la
memoria FLASH interna dell'STM32 è molto grande, ben 1MB, quindi si può
pensare di memorizzare l'audio al suo interno.
Per fare questo, si può usare un tool come
xxd,
una utility da linea di comando
per Linux che converte qualunque le in un le .h con un vettore in C contenete il
contenuto del le:
const unsigned char sad_trombone_bin[] = {
0xbf, 0x81, 0x90, 0x19, 0x96, 0xa3, 0x13, 0x04, 0x4a, 0x1b, 0x9b,
0x59, 0x38, 0xa0, 0x91, 0x15, 0x23, 0x71, 0x40, 0x10, 0x01, 0x11,
...
0xa1, 0x08, 0x1b, 0xbb, 0xf3, 0xa1, 0xa1, 0xb2, 0xa1, 0x91
};
const unsigned int sad_trombone_bin_len = 73618;
Nota: xxd non dichiara il vettore
const,
bisogna aggiungerlo a mano per far sì
che il compilatore lo allochi in FLASH e non in RAM.
POuL
Laboratorio microcontrollori e open source Terza parte
18/ 43
Progetto #2: Memebox | la classe Player
Insieme con il kernel Miosix ci sono degli esempi, e uno di questo è proprio un
driver per il DAC audio della board stm32f4discovery.
Per usare questo esempio occorre copiare il contenuto della directory
miosix/examples/sad_trombone
nella top level directory (ossia quella con il
main.cpp).
Questa cartella contiene anche il le .h con il suono del sad trombone.
POuL
Laboratorio microcontrollori e open source Terza parte
19/ 43
Progetto #2: Memebox | la classe Player
Il codice del
main()
di esempio è il seguente:
#include "player.h"
#include "sad_trombone.h"
int main()
{
ADPCMSound sound(sad_trombone_bin,sad_trombone_bin_len);
Player::instance().play(sound);
}
Potete partire da questo per implementare il progetto.
POuL
Laboratorio microcontrollori e open source Terza parte
20/ 43
Progetto #2: Memebox
Pratica: costruzione del circuito
POuL
Laboratorio microcontrollori e open source Terza parte
21/ 43
Progetto #3: LED RGB
Speciche:
Collegare un LED RGB a un Arduino. Collegare l'Arduino a un PC tramite il cavo
USB. Scrivere un programma lato PC per cambiare il colore del LED.
POuL
Laboratorio microcontrollori e open source Terza parte
22/ 43
Progetto #3: LED RGB
Pratica: costruzione del circuito
POuL
Laboratorio microcontrollori e open source Terza parte
23/ 43
Progetto #4: Accelerometro
Speciche:
Usando l'accelerometro interno alla board stm32f4discovery, leggere il valore
dell'accelerazione sui tre assi, trasferirla ad un PC e plottarla a schermo.
POuL
Laboratorio microcontrollori e open source Terza parte
24/ 43
Progetto #4: Accelerometro
Organizzazione del progettino
POuL
Teoria: I registri di periferica
Hardware/Software: La periferica SPI dell'STM32
Hardware: l'accelerometro LIS302DL
Software: La seriale in Miosix e
printf()
Software: GUI in Qt preconfezionata
Pratica: costruzione del circuito
Laboratorio microcontrollori e open source Terza parte
25/ 43
Progetto #4: Accelerometro | Registri di periferica
Molti programmatori, anche esperti, non hanno un idea precisa di come il software
interagisca con l'hardware. Questa slide si propone di risalire i vari livelli di
astrazione all'interno di un sistema operativo come GNU/Linux, no al punto che
ci interessa, l'interazione diretta con l'hardware.
Libreria userspace. E' normalmente il livello di astrazione a cui i programmatori
sono maggiormente abituati. Ad esempio, se un programmatore volesse interagire
con la USB su GNU/Linux, utilizzerebbe libusb. (http://www.libusb.org)
Ok, ma... come fanno queste librerie a interagire con l'hardware? Facendo
chiamate al kernel del sistema operativo.
Ok, ma... come sono implementate nel kernel queste chiamate? Facendo altre
chiamate ad un driver di periferica.
(ci stiamo avvicinando...) Ok, ma... come sono implementati i device driver?,
come comunicano con l'hardware?
POuL
Laboratorio microcontrollori e open source Terza parte
26/ 43
Progetto #4: Accelerometro | Registri di periferica
Il metodo più comune è quello dei registri di periferica. Le periferiche hardware si
presentano al software come un set registri, che non sono altro che locazioni di
memoria mappate a specici indirizzi nello spazio di indirizzamento, e quindi
accessibili tramite software.
Caveat: I registri di periferica non vanno confusi coi registri della CPU.
POuL
Laboratorio microcontrollori e open source Terza parte
27/ 43
Progetto #4: Accelerometro | Registri di periferica
I registri di periferica sono per certi versi paragonabili a delle variabili allocate in
RAM, in quanto
POuL
sono accessibili allo stesso modo (essendo mappati nello stesso spazio di
indirizzamento)
in molti casi sono leggibili e scrivibili dal software (alle volte però capita di
avere a che fare con registri read-only).
hanno una dimensione, solitamente di 8, 16 o 32bit, esattamente come gli
unsigned char, unigned short e unsigned int.
Laboratorio microcontrollori e open source Terza parte
28/ 43
Progetto #4: Accelerometro | Registri di periferica
Ciononostante, ci sono delle dierenze fondamentali tra i registri di periferica e le
variabili
POuL
Quello che viene scritto in questi registri causa azioni nel mondo reale
(l'accensione di un LED, l'attivazione di un ADC, l'invio di un carattere
tramite una porta seriale, etc.)
Si trovano a specici indirizzi di memoria. Quando una variabile viene
allocata sullo stack o sull'heap, al programmatore non importa se viene
allocata all'indirizzo 0xbc60 o 0xbe12, mentre se il registro di periferica
si trova all'indirizzo 0x101e5018 occorre essere sicuri di stare scrivendo
esattamente a quell'indirizzo, o non si otterranno i risultati voluti.
I registri di periferica non sono ad uso esclusivo del programmatore, come le
variabili. Sono condivisi tra il software e l'hardware. Per esempio l'hardware
puo` decidere di ippare bit all'interno dei registri per segnalare eventi
specici, cosa che non succede con le normali variabili.
Laboratorio microcontrollori e open source Terza parte
29/ 43
Progetto #4: Accelerometro | Registri di periferica
Come si fa a sapere quali periferiche si hanno a disposizione, quali registri ha una
specica periferica, a che indirizzo sono mappati e come usarli? Per un
microcontrollore le periferiche disponibili sono documentate dal produttore in un
documento, solitamente chiamato datasheet o programming guide.
Inoltre, il produttore del microcontrollore fornisce un le .h con la denizione di
tutti i registri spesso raggruppati per periferica, ad esempio la periferica GPIO può
avere molti registri, uno dei quali si chiama CRL. Per scrivere 0 in questo registro
si può scrivere:
void clearReg()
{
GPIO->CRL = 0;
}
POuL
Laboratorio microcontrollori e open source Terza parte
30/ 43
Progetto #4: Accelerometro | La periferica SPI
Il bus SPI è un bus di comunicazione molto usato per trasferire dati tra due
circuiti integrati posti sulla stessa board.
In questo caso lo useremo per comunicare tra l'accelerometro e il microcontrollore.
Guardando lo schema elettrico della board stm32f4discovery, l'accelerometro ha le
seguenti connessioni:
MOSI
PA7
MISO
PA6
SCK
PA5
CS
PE3
POuL
Laboratorio microcontrollori e open source Terza parte
31/ 43
Progetto #4: Accelerometro | La periferica SPI
Finora abbiamo scoperto che la maggior parte dei piedini di un microcontrollore
sono GPIO, ossia sono congurabili e usabili via software. In realtà, nella maggior
parte dei microcontrollori i piedini hanno anche una o più alternate function.
Quando si congura un GPIO come alternate function viene assegnato ad una
periferica. Non è più controllabile in software, ma viene gestito in hardware dalla
periferica.
In questo caso quindi vogliamo congurare i GPIO a cui è collegato l'accelerometro
come alternate function, in modo che siano gestiti dalla periferica SPI in hardware.
POuL
Laboratorio microcontrollori e open source Terza parte
32/ 43
Progetto #4: Accelerometro | La periferica SPI
Guardando il datasheet, si scopre che l'alternate function 5 dei GPIO PA5, PA6 e
PA7 li collega alla periferica SPI1, che è quello che vogliamo.
Il quarto segnale, PE3 che gestisce il CS o Chip select lo gestiremo invece noi in
software tramite un normale GPIO.
POuL
Laboratorio microcontrollori e open source Terza parte
33/ 43
Progetto #4: Accelerometro | La periferica SPI
Il codice per congurare i GPIO da Miosix è:
typedef
typedef
typedef
typedef
Gpio<GPIOA_BASE,7>
Gpio<GPIOA_BASE,6>
Gpio<GPIOA_BASE,5>
Gpio<GPIOE_BASE,3>
mosi;
miso;
sck;
cs;
int main()
{
mosi::mode(Mode::ALTERNATE);
mosi::alternateFunction(5);
miso::mode(Mode::ALTERNATE);
miso::alternateFunction(5);
sck::mode(Mode::ALTERNATE);
sck::alternateFunction(5);
cs::mode(Mode::OUTPUT);
cs::high();
...
POuL
Laboratorio microcontrollori e open source Terza parte
34/ 43
Progetto #4: Accelerometro | La periferica SPI
Il primo registro che vedremo si chiama RCC->APB2ENR
Questo registro fa parte del gruppo di registri RCC o Reset and Clock Control. In
questo registro c'è un bit, il numero 12, chimato SPI1EN, che attiva la periferica
SPI1. Nel le fornito da ST c'è anche una macro che denisce
RCC_APB2ENR_SPI1EN (112).
#define
Il codice per attivare questo bit (senza toccare gli altri bit del registro) è quindi:
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
POuL
Laboratorio microcontrollori e open source Terza parte
35/ 43
Progetto #4: Accelerometro | La periferica SPI
Una volta congurati i GPIO come alternate function e accesa la periferica SPI1,
occorre congurarla come scritto nel reference manual.
Per farlo, esiste il registro SPI1->CR1. Questo registro ha i seguenti bit che
andranno settati:
SPI_CR1_SSM
e
SPI_CR1_SSI
per dire alla periferica che il CS lo gestiamo
noi in software.
SPI_CR1_MSTR mette la periferica in master mode
SPI_CR1_BR_2 per congurare una velocità di 2.6MHz
SPI_CR1_SPE serve per attivare la periferica dopo la congurazione
Il codice da scrivere è
SPI1->CR1 = SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_MSTR
| SPI_CR1_BR_2 | SPI_CR1_SPE;
POuL
Laboratorio microcontrollori e open source Terza parte
36/ 43
Progetto #4: Accelerometro | La periferica SPI
Ok, adesso la congurazione è nita. A questo punto abbiamo nito?
No, occorre scrivere delle funzioni per andare a leggere e scrivere dalla SPI.
Per farlo esistono altri due registri:
POuL
SPI1->DR
Data register, scrivendo in questo registro si trasmette un byte
attraverso la SPI, leggendo si preleva un byte ricevuto dalla SPI.
SPI1->SR
Status register, contiene il bit
SPI_SR_RXNE,
settato dall'hardware
per per sapere quando il trasferimento di un byte attraverso la SPI è
completato.
Laboratorio microcontrollori e open source Terza parte
37/ 43
Progetto #4: Accelerometro | La periferica SPI
void spiSend(unsigned char byte)
{
SPI1->DR=byte;
while((SPI1->SR & SPI_SR_RXNE)==0) ; //Wait
byte=SPI1->DR; //Dummy read, causa l'azzeramento del bit RXNE
}
unsigned char spiReceive()
{
SPI1->DR=0; //Dummy write, causa la ricezione di un byte dalla S
while((SPI1->SR & SPI_SR_RXNE)==0) ; //Wait
return SPI1->DR;
}
POuL
Laboratorio microcontrollori e open source Terza parte
38/ 43
Progetto #4: Accelerometro | LIS302DL
Prima di poter leggere l'accelerometro bisogna inizializzarlo con il seguente codice:
void accelInit()
{
cs::low();
spiSend(0x20);
spiSend(0x47);
cs::high();
}
Questa procedura e i numeri 0x20 e 0x47 sono riportati sul datasheet
dell'accelerometro LIS302DL.
POuL
Laboratorio microcontrollori e open source Terza parte
39/ 43
Progetto #4: Accelerometro | LIS302DL
A questo punto, si può scrivere il codice per leggere l'accelerazione lungo un asse:
// axis==0 : read X axis
// axis==1 : read Y axis
// axis==2 : read Z axis
signed char accelRead(int axis)
{
cs::low();
spiSend(0x80 | (0x29+2*axis));
signed char result=spiReceive();
cs::high();
return result;
}
Anche questo codice è stato scritto a partire dal datasheet dell' accelerometro.
POuL
Laboratorio microcontrollori e open source Terza parte
40/ 43
Progetto #4: Accelerometro | La seriale e printf()
Su Miosix, si può stampare sulla seriale con
printf().
Solo che la board stm32f4discovery non ha un adattatore USB/seriale come
l'Arduino, il che rende dicile collegare la seriale a un computer.
Si potrebbe usare la USB, ma Miosix non ha ancora i driver per la periferica USB
di questa board.
Allora si può ricorrere a un convertitore USB/seriale esterno, acquistabile
separatamente.
Si può anche usare un Arduino come se fosse un adattatore USB/seriale, basta
togliere l'ATmega328. Questa è la soluzione che useremo.
POuL
Laboratorio microcontrollori e open source Terza parte
41/ 43
Progetto #4: Accelerometro | GUI in Qt
Lato PC si può usare (da Linux) il comando
screen /dev/ttyUSB0 19200
per vedere cosa viene stampato sulla seriale.
Per plottare i graci delle accelerazioni è stata fatta una GUI in Qt che apre la
seriale e plotta a schermo i dati.
POuL
Laboratorio microcontrollori e open source Terza parte
42/ 43
Progetto #4: Accelerometro
Pratica: costruzione del circuito
POuL
Laboratorio microcontrollori e open source Terza parte
43/ 43