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