Scuola Politecnica e delle Scienze di Base Corso di Laurea in Ingegneria Informatica Elaborato finale in Misure per l’Automazione e la Produzione Industriale Programmazione di microcontrollori STM32: ADC e gestione interruzioni Anno Accademico 2014/2015 Candidato: Aniello Bossa matr. N46001174 [Dedica] Indice Indice ................................................................................................................................................... V Introduzione ......................................................................................................................................... 7 Capitolo 1: STM32............................................................................................................................... 9 1.1 STM32F3 Discovery board ........................................................................................................ 9 1.1.1 Caratteristiche ..................................................................................................................... 9 1.2 Architettura di sistema ............................................................................................................ 10 1.3 Memory Layout........................................................................................................................ 11 1.4 Safety e security ....................................................................................................................... 11 1.5 Sviluppo Software .................................................................................................................... 12 1.5.1 Realizzazione di un nuovo progetto in ambiente di sviluppo IAR ................................... 12 Capitolo 2: STM32 ADC ................................................................................................................... 21 2.1 Configurazione convertitore A/D............................................................................................. 22 2.1.1 Abilitazione dell’ADC nella periferica RCC .................................................................... 22 2.1.2 Scelta del clock dell’ADC................................................................................................. 23 2.1.3 Configurazione del Regolatore di tensione ....................................................................... 24 2.1.4 Scelta del canale di acquisizione dell’ADC ...................................................................... 24 2.1.5 Configurazione della modalità di campionamento Single-ended o differenziale ............. 25 2.1.6 Auto-Calibrazione ............................................................................................................. 26 2.1.7 Abilitazione dell’ADC ...................................................................................................... 27 2.1.8 Impostazione dei Time Sampling ..................................................................................... 28 2.1.9 Impostazione della sequenza di campionamento .............................................................. 29 2.1.10 Esempio codice ADC ...................................................................................................... 30 2.2 Acquisizione temperatura ........................................................................................................ 31 2.2.1 Codice ADC sensore di temperatura ................................................................................. 32 2.3 Acquisizione Temperatura (Hardware Trigger) ....................................................................... 33 2.3.1 Codice acquisizione temperatura (Hardware Trigger) ...................................................... 34 Capitolo 3: Gestione delle interruzioni .............................................................................................. 36 3.1 Nested Vectored Interrupt Controller (NVIC) ......................................................................... 39 3.2 Extended interrupts and events controller (EXTI) ................................................................... 40 Conclusioni ........................................................................................................................................ 42 Bibliografia ........................................................................................................................................ 43 Introduzione In elettronica digitale il microcontrollore o microcontroller o MCU (MicroController Unit) è un dispositivo elettronico integrato su singolo chip, nato come evoluzione alternativa al Microprocessore ed utilizzato generalmente in sistemi embedded ovvero per applicazioni specifiche (special purpose) di controllo digitale. Il primo computer on-chip ottimizzato per applicazioni di controllo è stato il modello 8048 di Intel, uscito nel 1975, con RAM e ROM sullo stesso chip. Questo componente è stato utilizzato in più di un miliardo di tastiere per PC e numerose altre applicazioni. Nei primi anni di sviluppo del microcontrollore, la maggior parte dei modelli era commercializzata in due varianti: la più economica era dotata di memoria di programma programmata in fabbrica (ROM) su specifiche del cliente oppure programmabile dall'utente una sola volta (OTP, One Time Programming); la seconda, più costosa, aveva la memoria di programma cancellabile EPROM mediante esposizione a luce ultravioletta del chip tramite la finestrella trasparente che lo sovrastava. La programmazione del firmware veniva fatta direttamente in linguaggio macchina. Lo sviluppo della tecnologia CMOS e successivamente della HCMOS, nella prima metà degli anni ottanta, ha fornito un impulso decisivo alla diffusione dei microcontrollori, consentendo una notevole riduzione dei consumi e della dissipazione nei chip. Per molti anni Motorola è stata leader mondiale per i microcontrollori: il suo 68HC11 si rivelò essere una pietra miliare, allorché fu presentato sul mercato nel 1985; oltre alla RAM ed alla ROM integrava convertitori A/D, porte di I/O, SPI (Serial Peripheral 7 Interface), SCI (Serial Communication Interface), timers multifunzione, EEPROM, interrupts ed altro ancora, comprendendo persino un firmware di Monitor (Buffalo) che permetteva di effettuare il caricamento di programmi in RAM e il debug on-chip, tramite interfaccia seriale. Nel 1993 Microchip ha introdotto il modello di MCU PIC16C84, caratterizzato da memoria programma in EEPROM, ovvero cancellabile elettricamente, che permetteva sia lo sviluppo veloce del prototipo del prodotto finito, sia la modifica del Firmware a circuito montato (In-System Programming). La semplificazione del contenitore (package), senza finestrella in quarzo, ha contribuito a ridurre il costo finale del componente. Nello stesso anno Atmel ha presentato il primo MCU che utilizzava una memoria di tipo flash, ancora più semplice e veloce da programmare/modificare, più compatta e con un ciclo di vita (cancellazioni) molto più elevato. Nel corso degli ultimi anni, una delle maggiori tendenze è stata l’adozione di cpu con architettura ARM7 e ARM9. L’architettura ARM indica una famiglia di microprocessori RISC a 32-bit sviluppata da ARM Holdings e utilizzata in una moltitudine di sistemi embedded grazie alle sue caratteristiche di basso consumo. Nel 2007 la STMicroelectronics annuncia la STM32F1-series, la loro prima serie basata sul nuovo core ARM Cortex-M3, che garantisce nuovi standard per i costi e le performance. Una delle componenti chiave del core Cortex-M3 è il Nested Vector Interrupt Controller (NVIC). NVIC fornisce una struttura di interrupt standard per i microcontrollori basati su Cortex e un vettore dedicato alle interrupt per più di 240 periferiche dove ad ogni fonte di interruzione può essere assegnata una priorità. Lo scopo di questa tesi è quella di avere un primo approccio con un microcontrollore della famiglia STM32, analizzeremo in particolare il funzionamento dell’ADC e la gestione delle interruzioni. 8 Capitolo 1: STM32 STM32 è una famiglia di microcontrollori della STMicroelectronics. Le diverse serie di microcontrollori vengono raggruppate in base al core: Cortex-M7, Cortex-M4F, Cortex-M3, Cortex-M0+ o Cortex-M0. Ogni microcontrollore è costituito da un processore, una memoria SRAM, una memoria flash, un’interfaccia di debugging e diverse periferiche. In questa tesi esamineremo nello specifico la STM32F3. 1.1 STM32F3 Discovery board Innanzitutto è importante far distinzione tra board e microcontrollore. Il microcontrollore è soltanto una parte della board. 1.1.1 Caratteristiche Core ARM Cortex-M4 32-bit CPU con FPU (72 MHz max) Alimentazione da 3V a 5V Memoria : o Flash 256 Kbytes o SRAM 48 Kbytes CRC Quattro ADCs 0.20 μS con 9 risoluzione di 12/10/8/6 bits Due canali DAC da 12-bit L3GD20, ST MEMS sensore di movimento, giroscopio digitale a 3 assi LED1 (ROSSO) accensione 3.3 V LED2(ROSSO/VERDE) comunicazione USB Otto LED Due bottoni (utente e reset) Interfacce di comunicazione: o CAN (2.0B Active) o Due I²C fast mode plus (1Mbit/s) o Tre SPI o Cinque USART 1.2 Architettura di sistema STM32 è composta dal Cortex core il quale è connesso alla memoria FLASH da un Instruction bus (I-bus) dedicato. Il Cortex e i System busses sono collegati alla matrice dell’ARM Advanced High Speed Busses (AHB). La SRAM interna è connessa direttamente all’ AHB cosi come l’unità DMA. Le periferiche sono locate su due ARM Advanced Peripheral Busses (APB), ognuno di questi APB è collegato all’ AHB. L’ AHB è tarato alla stessa velocità del Cortex core, entrambi gli AHB hanno un proprio prescaler con il quale può essere diminuita la velocita così da ridurre il consumo. È importante notare che APB2 può lavorare a 72 MHz mentre APB1 lavora a 36 MHz. Sia il Cortex che il DMA possono essere bus master, ma a causa del parallelismo intrinseco della matrice dei bus sono arbitrati se entrambi tentano di accedere alla SRAM, APB1 o APB2. 10 Il meccanismo di arbitraggio garantirà 2/3 del tempo di accesso al DMA e 1/3 al Cortex. 1.3 Memory Layout Sebbene STM32 ha numerosi busses interni, al programmatore vengono riservati 4 Gbyte dello spazio degl’indirizzi. La memoria di programmazione inizia a 0x00000000. La on-chip SRAM inizia a 0x20000000 e tutte le altre SRAM interne sono posizionate nei bit iniziali. Le periferiche utente sono memory mapped ed iniziano dall’indirizzo 0x40000000. Infine i registri del Cortex iniziano dall’indirizzo 0xE0000000. 1.4 Safety e security Oltre a richiedere maggiore potenza di elaborazione e periferiche più sofisticate, i microcontrollori devono operare in ambienti critici per la sicurezza. La STM32 ha una serie di caratteristiche hardware di supporto che garantiscono l’integrità. Queste caratteristiche includono un rilevatore di bassa tensione, un sistema di sicurezza del clock e due watchdog separati. Il primo watchdog è un windowed watchdog, questo deve essere aggiornato in un periodo di tempo predefinito se viene attivato troppo presto o troppo tardi genererà un trigger. 11 Il secondo watchdog è indipendente e possiede un oscillatore esterno separato dal clock di sistema. Un altro aspetto importante della sicurezza è la protezione del codice, la memoria FLASH dell’STM32 può essere bloccata in lettura, in questo caso la memoria è bloccata anche in scrittura così da impedire l’inserimento di codice non attendibile nel vettore delle interruzioni. Inoltre il resto della memoria FLASH può essere bloccata in scrittura. 1.5 Sviluppo Software Il software che utilizzeremo per lo sviluppo di un progetto sarò IAR Embeddeb Workbench, questo software ci permetterà di programmare in codice C. 1.5.1 Realizzazione di un nuovo progetto in ambiente di sviluppo IAR Apriamo l’ambiente di sviluppo IAR Creiamo un nuovo workspace. Dal menu a tendina selezioniamo le voci FILE->NEW->WORKSPACE Creiamo un nuovo progetto.Sempre dal menu a tendina selezioniamo le voci PROJECT->CREATE NEW PROJECT Compare la schermata 12 In questa schermata selezioniamo la voce Empty proect e premiamo OK. Compare la schermata che ci chiede di salvare il progetto nella cartella desiderata. In questo esempio creiamo una cartella che conterrà tutti i nostri progetti futuri e una sottocartella che conterrà il nostro primo progetto. Nominiamo il progetto e salviamolo nella cartella. 13 Nel Workspace compare quindi il nostro primo progetto. Posizioniamoci sul progetto nel workspace con il cursore del mouse e con il tasto destro selezioniamo l'opzione Options... 14 Compare la schermata che ci permette di selezionare le varie opzioni del progetto, Options for node "Primo progetto" Di default è selezionata la categoria "General Options"->Target. Qui dobbiamo selezionare il device. Quindi in Processor variant spuntiamo su Device. 15 In corrispondenza di Device c'è l'icona che apre la lista dei device dalla quale occorre selezionare il device STM32F303xC 16 Questo processore ha un'unità Floating point per operazioni su numeri con virgola mobile per cui in FPU troviamo VFPUv4. Una volta selezionato il device selezioniamo la categoria C/C++ Compiler e quindi l'opzione Preprocessor per selezionare le cartelle a cui il compilatore deve fare riferimento. Per aggiungere cartelle al progetto clicchiamo sull'iconcina in corrispondenza di Additional include directories. Quindi si apre la schermata Edit Include Directories e in questa schermata clicchiamo su <Click To Add> e selezioniamo le cartelle da aggiungere nel progetto. Il file stm32f30x.h si trova nella sottocartella Libraries: C:\..\STM32F3-Discovery_FW_V1.1.0\Libraries\CMSIS\Device\ST\STM32F30x\Include Per includere il file nel progetto nel main aggiungiamo l'include #include <stm32f30x.h> 17 e nelle opzioni del progetto nella categoria C/C++ Compiler->Preprocessor aggiungiamo la cartella che include il file: Inserire soltanto il file stm32f30x.h nel nostro progetto non è sufficiente. Infatti se si prova a compilare il progetto viene generato un errore. Questo errore è dovuto al fatto che il file stm32f30x.h richiama a sua volta il file "core_cm4.h" che si trova però in un'altra cartella che dobbiamo indicare nel preprocessor. Il file si trova in: C:\..\STM32F3-Discovery_FW_V1.1.0\Libraries\CMSIS\Include Aggiungendo anche questa nuova cartella al progetto l'errore viene quindi risolto. Per fare in modo che il riferimento alla cartella di progetto non venga perso, nel caso in cui si decidesse di eseguire il progetto su un altro PC, selezioniamo sostituiamo il percorso cliccando sull'iconcina a fianco del percorso scelto. Come passo successivo dobbiamo selezionare il Debugger, selezioniamo quindi la categoria Debugger. Se disponiamo della scheda selezioniamo il Debbuger ST-LINK dal menu Driver in Setup. 18 Una volta selezionato ST-LINK sempre nella categoria Debugger selezioniamo Dowunload e spuntiamo l'opzione Use flash loader. 19 Infine nella Categoria ST-LINK spuntiamo l'opzione SWD, e premiamo OK per salvare le opzioni impostate. 20 Capitolo 2: STM32 ADC Analog to Digital Converter (ADC), in italiano convertitore analogico-digitale, è un circuito elettronico in grado di convertire un segnale analogico con andamento continuo (ad es. una tensione) in una serie di valori discreti. La risoluzione di un ADC indica il numero di valori discreti che può produrre. È usualmente espressa in Bit. Per esempio, un ADC che codifica un ingresso analogico in 256 livelli discreti ha una risoluzione di 8 bit, essendo 28 = 256. La risoluzione può anche essere definita elettricamente, ed espressa in volt. La risoluzione in volt di un ADC è uguale alla minima differenza di potenziale tra due segnali che vengono codificati con due livelli distinti adiacenti. L’STM32 offre fino a 4 convertitori digitali. L’ADC ha un alimentazione indipendente che può essere compresa tra 2.4V e 3.6V, il riferimento è collegato internamente all’ADC o può essere collegato tramite un pin dedicato. Entrambi gli ADC offrono una risoluzione di 12-bit e un tasso di conversione di 1MHz con fino a 18 canali multiplex, 16 dei quali sono messi a disposizione per misurare segnali esterni. Dei restanti due, uno è collegato ad un sensore di temperatura interno e il secondo è collegato ad una tensione di riferimento interna. L’ ADC nell’STM32 usa il SAR (successive approximation register), per cui la conversione avviene in più fasi. Il numero delle fasi è uguale al numero di bit del convertitore ADC, ogni passo è guidato dal clock dell’ADC. 21 2.1 Configurazione convertitore A/D Nel microcontrollore sono disponibili 4 convertitori AD di tipo SAR da 12 bit, suddivisi in 2 gruppi, ognuno composto da 2 convertitori uno dei quali può funzionare da master e l’altro da slave; questo ci permette di poter raddoppiare la frequenza di campionamento agganciando le due conversioni. Gruppo 1 Gruppo 2 ADC1 Master ADC2 Slave ADC3 Master ADC4 Slave Per quanto concerne le connessioni, bisogna in primo step considerare che ciascun convertitore può essere connesso ad un certo numero di canali interni ed esterni, in particolare ADC1 dispone di 14 canali in totale a cui può essere collegato; 10 canali esterni e 4 canali interni. Questi canali, selezionati uno alla volta mediante un multiplexer, arrivano al Sample&Hold e quindi all'ingresso dell'ADC1 (p.201 ADCs main features) 2.1.1 Abilitazione dell’ADC nella periferica RCC Da RCC register map (p.132 del Reference Manual) troviamo che il bit per abilitare l'ADC si trovano nel RCC_AHBENR. In questo caso notiamo che c'è un unico bit ADC12 per abilitare la coppia ADC1 e ADC2 e un altro bit ADC34 per abilitare la coppia ADC3 e ADC4. Infatti gli ADC 22 non possono essere abilitati singolarmente. Se si abilita ADC1 si abiliterà anche ADC2, lo stesso discorso vale per gli altri due. 2.1.2 Scelta del clock dell’ADC Il Clock dell'ADC è comune ad entrambi gli ADC, ADC1 e ADC2. IL Clock può essere derivato dal clock del bus AHB, dividendo questo clock per un fattore 1,2 o 4. Il fattore di divisione è fissato dai bit CKMODE[1:0] del registro ADC12_CCR (ADC_Common Control Register). Abbiamo scelto di impostare il clock dell'ADC pari a quello derivato dell'AHB e del "SysTick", clock di sistema che è pari a 72 MHz. Dobbiamo quindi scegliere come fattore di scala il valore 1. Per selezionare questo fattore di scala dobbiamo impostare i bit di CKMODE[1:0]='01'. 23 2.1.3 Configurazione del Regolatore di tensione La conversione avviene confrontando il segnale di ingresso con una tensione di riferimento pari alla tensione di alimentazione. La tensione è fornita da un regolatore di tensione. Per abilitare il regolatore occorre eseguire una procedura di abilitazione e attendere 10 μs prima di abilitare l'ADC (ADEN=1) oppure eseguire un'operazione di calibrazione. Per poter abilitare il regolatore di tensione allora nell'ADC1_CR occorre portare i bit ADVREGEN[1:0] dallo stato di reset '10' allo stato '00' e quindi allo stato di abilitazione '01'. I bit che ci interessano e sui quali agire sono il bit 28 e il bit 29. 2.1.4 Scelta del canale di acquisizione dell’ADC Per vedere come sono realizzate le connessioni fisicamente tra ADC e PIN, si fa riferimento al Data Sheet Manual, Pinouts and pin description in cui troviamo l’elenco dei pin di out della board: scorrendo l’elenco notiamo che PA0 è connesso al canale 1 (ADC1_IN1) di ADC1 come emerge nel Additional Functions. Quindi per acquisire la tensione su PA0 bisogna andare a convertire il canale 1 di ADC1, invece per acquisire la tensione su PA1 bisogna convertire il canale 2 di ADC1 e così via per gli altri PIN 24 2.1.5 Configurazione della modalità di campionamento Single-ended o differenziale Il Convertitore ha 2 ingressi potendo funzionare sia in modalità single-ended che in modalità differenziale. In modalità single-ended la conversione avviene rispetto ad una tensione di riferimento fissata una volta per tutte in fase di configurazione. In modalità differenziale come differenza di due tensioni poste in ingresso al convertitore. Scegliamo la modalità single-ended dal momento che la tensione che vogliamo misurare varia tra [0 ] V ed è solo uno dei due ingressi che può variare. La tensione di riferimento in modalità single-ended è 0 V. Quindi avremo a disposizione un convertitore AD a 12 bit ad approssimazioni successive (SAR), in modalità single-ended, in configurazione Master che effettua una quantizzazione silenziata uniforme. Infatti la soluzione adottata è tale che il numero di livelli di restituzione del convertitore a 12 bit sarà pari -1= 4095, in modo da avere una quantizzazione uniforme silenziata e fondo scala 3 V. In questo modo otteniamo un quanto di circa Q= 25 = 0,0007326 V. Per il canale 1 bisogna quindi dire se l'acquisizione avviene in modalità single-ended o differenziale. Questo avviene scrivendo i bit DIFSEL[15:0] del registro ADC_DIFSEL. Questa operazione deve essere effettuata quando il convertitore è disabilitato (ADEN=0). Poichè per selezionare la modalità single-ended per il canale 1 dovremmo scrivere 0 nel bit di posto 1, e questo bit al reset è proprio 0, potremmo anche non mettere questa istruzione. 2.1.6 Auto-Calibrazione Dopo questa prima fase di inizializzazione del convertitore, si procede con la fase successiva di auto-calibrazione dell’AD, procedura che deve avvenire con il convertitore ancora in modalità off cioè bit ADEN settato a 0. Nel caso single-ended dobbiamo porre il bit ADCALDIF (modalità single-ended) del registro ADC1_CR pari a 0. Se avessimo voluto eseguire la procedura di calibrazione per la modalità di acquisizione differenziale allora avremmo dovuto settare ADCALDIF=1. Quindi la procedura di auto-calibrazione ha inizio ponendo il bit ADCAL=1 e dobbiamo aspettare fino a quando ADCAL=0 che indica che la calibrazione è terminata. 26 2.1.7 Abilitazione dell’ADC A questo punto dobbiamo abilitare la periferica ADC portando al valore logico alto il bit ADEN del registro ADC1_CR. Tuttavia la periferica sarà pronta per poter lavorare soltanto quando il bit ADRDY del registro ADC_ISR sarà diventato 1. Pertanto dopo aver alzato il bit ADEN rimaniamo in attesa della condizione ADRDY==1 mediante un ciclo while. 27 2.1.8 Impostazione dei Time Sampling Terminate queste operazioni resta ancora da fissare il Tempo di Sample (Tempo di campionamento che equivale al tempo di chiusura dell'interruttore del circuito di Sample&Hold). Questo tempo dipende dalla dinamica del segnale di ingresso ( ) ed è il tempo che occorre per portare la tensione sulla capacità di Hold ( ) ad una tensione parti a quella dell'ingresso ( ). In questo tempo la tensione di uscita insegue la tensione di ingresso. Ciascun canale del convertitore può essere campionato con un tempo di campionamento differente, programmabile settando i bit SMP[2:0] dei registri ADC_SMPR1 e ADC_SMPR2. E' pertanto possibile selezionare i seguenti valori: Dato che il convertitore è a 12 bit di tipo SAR il tempo totale di conversione sarà: TCONV = Tempo di campionamento + 12,5 ADC Clock cycles 28 2.1.9 Impostazione della sequenza di campionamento Come ultima operazione di configurazione dobbiamo impostare la sequenza di campionamento. Infatti è possibile organizzare la conversione in un gruppo, dove il gruppo è costituito da una sequenza di conversioni che può essere fatta su alcuni canali. Quindi nei bit SQ1[4:0] del registro ADC1_SQR1 scriviamo il numero del primo canale da cui acquisire, in SQ2[4:0] il numero del secondo e così via, fino all'ultimo canale della sequenza SQ16[4:0] del registro ADC1_SQR1. Quindi ciascuna sequenza può essere costituita da un minimo di 1 ad un massimo di 16 conversioni. L'ordine dei canali da cui acquisire può essere qualsiasi. Ciascun canale può essere convertito più volte nella stessa sequenza. La lunghezza della sequenza è invece fissata dai bit L[3:0]. A questo punto la conversione di una sequenza può iniziare dando un Segnale di Start of Convertion. Il segnale di Start of Convertion viene dato all'ADC portando ad 1 il bit ADSTART del registro ADC1_CR. Il convertitore avvisa che la singola conversione è terminata alzando il flag di EOC (End of Convertion) e che la conversione della sequenza è terminata alzando il flag EOS (End of Sequence). Una volta che la sequenza di conversione è terminata il bit ADCSTART ritorna a 0 inibendo l'inizio di una nuova conversione. I flag EOC ed EOS vengono riportati a 0 via software. Tuttavia il flag EOC ritorna a 0 non appena leggiamo il dato acquisito dal Data Register (ADC1_DR). Nel diagramma temporale seguente è riportata la sequenza delle operazioni. Per iniziare una nuova conversione dobbiamo rialzare il bit ADSTART. Questa modalità di campionamento è detta NON CONTINUA. Ogni volta infatti per avviare la conversione di una sequenza dobbiamo dare il segnale di Start of Convertion. Esiste un'altra modalità questa volta CONTINUA nella quale il segnale di Start of Convertion deve essere dato soltanto all'inizio. La conversione della sequenza procede poi ciclicamente fino a quando non si alza via software il flag ADSTOP del registro ADC_CR. A questo punto anche il flag ADSTART viene riportato a 0 dall'hardware e la conversione ciclica si interrompe. Per impostare un'acquisizione continua della sequenza dobbiamo settare il flag CONT del registro ADC1_CFGR al valore logico alto. Al termine della conversione il DATA REGISTER contiene il valore convertito e acquisito su PA0. Per poter leggere questo valore dobbiamo convertirlo in tensione. Effettuiamo quindi un’operazione di casting trasformando il dato in tipo float. Il valore è quindi ottenuto moltiplicando il dato per il quanto del convertitore Q=3/4095. Mediante una funzione printf possiamo quindi visualizzare il dato acquisito nel Terminal I/O dell'ambiente di sviluppo. 29 2.1.10 Esempio codice ADC 30 2.2 Acquisizione temperatura In questo paragrafo misureremo la temperatura grazie al sensore di temperatura connesso internamente al canale ADC1_16, il quale converte in digitale l’uscita del sensore di temperatura. Il periodo di campionamento del sensore di temperatura deve essere maggiore di 2.2µs, come possiamo leggere nel paragrafo 12.9 del Reference Manual. Quindi come prima cosa dobbiamo configurare l’ADC come nel paragrafo precedente apportando qualche correzione. Impostiamo il canale di acquisizione sul canale 16 modificando il registro ADC1_SQR1 e inseriamo il valore 16 all’interno della prima sequenza. Pertanto alzeremo il quarto bit di SQ1 (24=16). Settiamo il Time Sampling tale che sia maggiore di 2.2µs, settando il clock dell’ADC pari a quello di sistema (72 MHz), ci basta scegliere il periodo di campionamento paria a 181.5 ADC clock. 181.5/72*10-6 s ≈ 2.5µs Dopo queste operazioni possiamo abilitare il sensore di temperature dal registro ADC1_CCR alzando il bit TSEN, quest’operazione deve essere eseguita quando il bit ADEN è 0. 31 Successivamente possiamo prelevare il dato da ADC1_DR e applicare la seguente formula per il calcolo della temperatura: Temperatura (in °C) = {(V25 – VTS) / Avg_Slope} + 25 Dove VTS è la tensione misurata dal sensore di temperature, V25 e Avg_Slope sono dei parametri caratteristici che troviamo nel DataSheet. 2.2.1 Codice ADC sensore di temperatura 32 2.3 Acquisizione Temperatura (Hardware Trigger) La conversione Analogico-Digitale può essere effettuata dall'ADC via software oppure controllata mediante un hardware trigger proveniente dall'esterno della periferica. Sull'ADC sono disponibili 16 external triggers. Se è selezionata questa modalità non dovremo più avviare la conversione via software ma una volta alzato il bit ADSTART questa sarà avviata una sola volta (CONT=0) oppure ciclicamente (CONT=1). Attraverso un multiplexer controllato dai bit EXTSEL[3:0] del registro CFGR dell'ADC selezioniamo l'evento di trigger desiderato. I possibili eventi di trigger per esempio per l'ADC1 e l'ADC2 sono riportati nella tabella 35 del Reference Manual. 33 L'evento esterno fissa di fatto la frequenza di campionamento dell'ADC nel caso in cui il bit CONT=0. Configuriamo il Timer2 per generare un Update Event ogni secondo e dare il via ad una conversione della temperatura. Per dire quindi all'ADC che la conversione inizia all'arrivo dell'Event Update generato dal Timer2 dobbiamo settare i bit EXTSEL[3:0] del registro CFGR con la sequenza di bit '1011', così come evidenziato in tabella. Affinchè l'evento sia rilevato dall'ADC dobbiamo configurare anche i bit EXTEN[1:0] del registro CFGR. Se selezioniamo la sequenza '00' allora l'ADC ignora il trigger esterno, se selezioniamo '01' si accorge della transizione 0->1(salita) del trigger, '10' della transizione 1->0 (discesa), '11' di entrambe. Per settare i Timer 2 dobbiamo conoscere la frequenza con cui lavora, dato che si trova sul bus APB1 il TIM2 lavora ad una frequenza di 36MHz quindi dobbiamo settare il registro TIM2 autoreload a 36 000 000. Non approfondiamo di più la configurazione del Timer perché non è oggetto di questa tesi. 2.3.1 Codice acquisizione temperatura (Hardware Trigger) 34 35 2.4 Calcolo valore medio della tensione con utilizzo del DMA In questo paragrafo vedremo come utilizzare la periferica DMA (Direct Memory Access) per gestire automaticamente la Look-Up Table (LUT) senza l'utilizzo di un contatore e operando direttamente in hardware. Sul microcontrollore sono presenti 2 periferiche DMA che in totale possono gestire 12 richieste di servizio provenienti da altrettante periferiche per trasferire velocemente dati dalle periferiche alla memoria e viceversa. In questo modo possiamo realizzare dei trasferimenti di dati dalla memoria alla periferiche o dalle periferiche alla memoria rapidamente e senza impiegare risorse della CPU, che può realizzare altre operazioni mentre avvengono questi trasferimenti. Il DMA deve conoscere l'indirizzo del registro della periferica al/dal quale trasferire/prelevare il dato, l'indirizzo della prima locazione di memoria in cui inserire/prelevare il dato, la dimensione dell'array in memoria. Su ciascun canale del DMA soltanto una richiesta alla volta, proveniente dalle periferiche (TIMx(x=1...4, 6, 7, 15..17), ADC1 , SPI1, SPI2/I2S2, I2Cx(x=1,2), DAC_Channel[1,2], e USARTx (x=1..3)), può essere abilitata. Le richieste verso il DMA possono essere indipendentemente attivate o disattivate programmando il DMA control bit nel corrispondente registro della periferica. La tabella 26 del Reference Manual riassume le richieste disponibili per ciascun canale del DMA1. Dato che noi vogliamo trasferire le acquisizioni effettuate dall’ADC1 in un area di memoria, osserviamo che questa richiesta arriva sul canale 1 del DMA1. Come nel capitolo precedente non ci soffermeremo sulla configurazione del DMA, vedremo solo come configurare l’ADC. 36 Per abilitare la collaborazione dell’ADC con il DMA, andiamo nel registro ADC_CFGR e settiamo i bit DMAEN e DMACFG. Il resto della configurazione è uguale a quella dell’esempio precedente, tranne per le interruzioni esterne dato che in questo caso non useremo il TIMER2 come fonte di interruzione. 2.4.1 Codice calcolo valore medio 37 38 Capitolo 3: Gestione delle interruzioni L’unità delle interruzioni ha 19 linee di interruzione le quali sono connesse al vettore delle interruzioni attraverso NVIC. Sedici di queste linee sono connesse ai pin GPIO e possono generare interruzioni sul fronte di salita, di discesa o entrambi. Le restanti 3 linee sono connesse a RTC allarm interrupt, USB wake up e all’unita di rilevamento alimentazione. NVIC fornisce vettori di interruzioni individuali per le linee EXTI 0-4, l’allarme RTC, USB wake up e all’unita di rilevamento alimentazione. Le restanti linee EXTI sono collegate in gruppi di linee 5-9 e 10-15. EXTI e importante per il controllo dell’alimentazione su STM32. Le 16 linee EXTI dedicate ai pin GPIO possono essere associate a qualsiasi combinazione di pin della porta, questo è realizzato attraverso quattro registri di configurazione. In questi registri ad ogni campo EXTI si associano 4 bit, questo campo permette ad ogni linea EXTI di essere mappata su una delle 5 porte. 3.1 Nested Vectored Interrupt Controller (NVIC) Il dispositivo STM32F3 incorpora un Nested Vectored Interrupt Controller in grado di gestire fino a 66 canali di interruzione mascherabili e 16 livelli di priorità. I vantaggi del NVIC sono: Bassa latenza delle interruzioni L’indirizzo del Interrupt entry vector table è passato direttamente al core Trattamento precoce delle interruzioni Stato del processore salvato automaticamente 39 NVIC e l’interfaccia del core sono strettamente accoppiati, questo accoppiamento stretto consente al processo di interruzione di avere una bassa latenza e di trattare efficientemente le interruzioni in ritardo. Questa bassa latenza viene realizata grazie all’utilizzo di uno stack, il processore all’ingresso di un interruzione salva automaticamente nello stack il suo stato e rimuove lo stato dallo stack quando l’interruzione termina. L’implementazione hardware dei registri NVIC la troviamo a p.193 del Program Manual: 3.2 Extended interrupts and events controller (EXTI) L’ EXTI gestisce le interruzioni asincrone esterne ed interne, genera una richiesta di evento alle CPU/Interrupt Controller e una richiesta di risveglio al Power Manager. EXTI gestisce 28 linee di eventi esterni e 8 linee di eventi interni. Il fronte di attivazione di ogni linea esterna può essere scelto indipendentemente, mentre per le interruzioni interne la scelta del fronte è limitata a quello di salita. Un interruzione potrebbe essere messa in attesa, la gestione in questo caso e diversa a seconda se l’interruzione sia esterna o interna. Nel caso di un interruzione esterna, viene istanziato un registro che indica la fonte dell’interruzione, quando l’interruzione è interna lo stato sospeso è garantito dalla periferica, quindi non è necessario un flag specifico. 40 41 Conclusioni In conclusione abbiamo visto come si sono evoluti i microcontrollori, partendo dal primo computeron-chip di Intel uscito nel 1975 fino ad arrivare all’STM32. Quest’ultimo microcontrollore ha avuto un enorme successo, successo dovuto alle sue performance elevate e al suo basso costo. Oggi del microcontrollore ne viene fatto un uso massiccio in svariati campi industriali, dall’automotive agli elettrodomestici, questo ci fa capire come il microcontrollore sia un oggetto fondamentale e quindi bisogna adattarlo ai più svariati settori. Come abbiamo constatato nel caso dell’STM32, questa specifica famiglia di board sono facilmente programmabili, la facilita di programmabilità, non solo di questa specifica board, fa si che questi component siano usati dentro e fuori le nostre case automatizzando processi delicati che hanno bisogno di un elevata precisione. Siamo circondati da microcontrollori nella vita quotidiana senza che ce ne rendiamo conto. 42 Bibliografia [1] STMicroelectronics, RM0316 Reference Manual [2] STMicroelectonics, UM1570 User Manual [3] STMicroelectronics, STM32F302xx/STM32F303xx Datasheet [4] STMicroelectronics, PM0214 Program Manual [5] Hitex Development Tools, The Insider’s Guide To The STM32 ARM® Based Microcontroller 43