Generatore di forme d`onda arbitrarie basato su STM32F303

Scuola Politecnica e delle Scienze di Base
Corso di Laurea in Ingegneria Informatica
Elaborato finale in Misure per l’Automazione e la Produzione Industriale
Generatore di forme d’onda arbitrarie
basato su STM32F303
Anno Accademico 2015/2016
Candidato:
Antonio Sorrentino
matr. N46002022
[Dedica]
Indice
Indice.................................................................................................................................................. III
Introduzione ......................................................................................................................................... 5
Capitolo 1: STM32............................................................................................................................... 7
1.1 STM32F3 ................................................................................................................................... 7
1.1.1 Board STM32F3 ................................................................................................................. 6
1.1.2 Architettura di sistema ........................................................................................................ 6
1.2 Sviluppo Software ...................................................................................................................... 8
1.2.1 Creazione di un nuovo Progetto .......................................................................................... 6
Capitolo 2: Periferiche ....................................................................................................................... 13
2.1 DAC ......................................................................................................................................... 13
2.1.1 Descrizione modalità di funzionamento singola ............................................................... 16
2.1.2 Conversione ...................................................................................................................... 17
2.1.3 Richieste DMA ................................................................................................................. 18
2.1.4 Registri del DAC............................................................................................................... 19
2.1.4.1 Registro DAC_CR .................................................................................................. 19
2.1.4.2 Registro DAC_DHR12R1....................................................................................... 20
2.1.4.3 Registro DAC_DOR1 ............................................................................................. 21
2.1.4.4 Registro DAC_SR ................................................................................................... 21
2.1.5 Configurazione del DAC .................................................................................................. 22
2.2 DMA ........................................................................................................................................ 13
2.2.1 Principali caratteristiche .................................................................................................... 22
2.2.2 Descrizione funzionale...................................................................................................... 24
2.2.2.1 Transazioni .............................................................................................................. 24
2.2.3 Arbiter ............................................................................................................................... 25
2.2.4 Mappa delle richieste DMA .............................................................................................. 26
2.2.5 Registri DMA.................................................................................................................... 27
2.2.5.1 DMA interrupt status register ................................................................................. 27
2.2.5.2 DMA flag clear register .......................................................................................... 28
2.2.5.3 DMA configuration register .................................................................................... 28
2.2.6 Configurazione del DMA.................................................................................................. 29
2.3 Timer ........................................................................................................................................ 31
2.3.1 Principali caratteristiche .................................................................................................... 31
2.3.2 Funzionamento di base...................................................................................................... 32
2.3.3 Configurazione del Timer ................................................................................................. 33
2.4 Gestione delle interruzioni ....................................................................................................... 33
2.4.1 Extended interrupts and events controller (EXTI) ............................................................ 35
2.4.2 Configurazione interruzione esterna ................................................................................. 37
Capitolo 3: Codice ............................................................................................................................. 38
Conclusioni ........................................................................................................................................ 40
Bibliografia ........................................................................................................................................ 41
Introduzione
Un generatore di segnale è un dispositivo utilizzato per produrre forme d’onda con
determinate caratteristiche scelte a priori, ovvero di generare un segnale periodico. Un
generatore di segnali viene utilizzato principalmente per effettuare il testing di circuiti
elettrici ed elettronici infatti nella fase di progetto e di produzione di dispositivi elettronici,
debbano essere provati dei circuiti e capita che si abbia bisogno di segnali come quello
generato da un componente che non è facilmente reperibile, per questo viene utilizzato un
generatore di segnali, oppure può essere utilizzato come dispositivo di comando di processo,
o come strumento campione.
Scopo di questa tesi è la realizzazione di un generatore di forme d’onda elementari tramite
componenti a basso costo.
L’idea è quella di conservare in memoria un certo numero di campioni di un singolo periodo
della forma d’onda desiderata, e poi trasmettere tali campioni a un DAC in modo che esso
trasformi tali valori digitali nel relativo valore analogico avendo l’accortenza di inviarli a
tale dispositivo a una velocità costante e facendo in modo di rispettare il valore di frequenza
scelto.
Waveform
DAC
Memory
5
Amp
Nel nostro caso abbiamo scelto di generare tre tipi di forme d’onda: onda sinusoidale, onda
triangolare e onda esponenziale (in quest’ultimo caso scegliendo di avere un esponenziale
crescente nel primo semiperiodo e uno decrescente nel secondo). Ovviamente sarà possibile
selezionare sia l’ampiezza che la frequenza del segnale.
Scopo di questa tesi è la realizzazione di tale generatore di segnale tramite un
microcontrollore dell’azienda STMicroelectronics, in particolare utilizzeremo la board F3
Discovery della famiglia STM32, di cui andremo ad analizzare nel dettaglio il DAC, i
Timer e il DMA (Direct Memory Access).
6
Capitolo 1: STM32
STM32 rappresenta una famiglia di microcontrollori basati su core ARM, internamente ogni
microcontrollore consiste di un processore, una memoria RAM statica, una memoria flash,
una interfaccia per il debugging e varie periferiche.
1.1 STM32F3
La serie STM32F3 è basata sul core ARM Cortex M4F che opera a frequenze fino a
massimo 72 MHz il quale incorpora al suo interno una FPU (Floating Point Unit), una MPU
(Memory Protection Unit) e una ETM (Embedded Trace Macrocell).
1.1.1 Board STM32F3
 Core ARM Cortex-M4 32-bit CPU
con FPU (72 MHz max);
 Alimentazione attraverso ingresso
esterno da 3V a 5V o tramite bus USB;
 Memoria : Flash 256 Kbytes, RAM 48 Kbytes;
 Quattro ADCs 0.20 μS con 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) per accensione a 3.3 V;
 LED2(ROSSO/VERDE) per comunicazione
USB;
7
 Otto LED colorati Rosso (Led 3 e 10) Verde (Led 6 e 7) Arancione (Led 5 e 8) e Blu (Led
4 e 9)
 Due pulsanti (utente e reset)
1.1.2 Architettura di sistema
L’architettura principale della serie STM32F3 è formata da un master (che può essere o il
Cortex-M4 oppure uno dei due DMA) collegati a una Matrice di bus alla quale sono collegati
la memoria Flash, la SRAM e le varie periferiche.
Figura 1
Il core Cortex-M4 è collegato con la Matrice di bus con l’I-bus (Instruction bus) che viene
usato dallo stesso per caricare le istruzioni di fetch ed è collegato con la memoria Flash,
SRAM e CCM RAM. Il DCode bus (load e debug access) connette anch’esso il Cortex con
la Matrice di bus ed è usato per caricare/salvare dati nel Code Space. Il S-Bus (System Bus)
collega il Cortex con la Matrice di bus e viene usato per accedere ai dati nelle periferiche o
nella SRAM. I DMA bus connettono il DMA con la Matrice di bus. La Matrice di bus
8
gestisce l’accesso dei Master tramite un meccanismo di arbitraggio, tale meccanismo usa un
algoritmo del tipo Round Robin per permettere ai Master (Cortex oppure DMA di accedere
agli Slave. I due ponti AHB\APB permettono la connessione tra il bus AHB e i due bus
APB, APB1 limitato alla frequenza di 36 MHz, APB2 con massima frequenza 72 MHz. Una
periferica prima di essere utilizzata dovrà esserne abilitato il relativo clock in uno dei registri
RCC_AHBENR, RCC_APB1ENR oppure RCC_APB2ENR.
1.2 Sviluppo Software
Il software che sarà utilizzato per lo sviluppo di questo progetto è IAR Embedded
Workbench che ci darà la possibilità di programmare in C.
1.2.1 Creazione di un nuovo Progetto
Per cominciare dobbiamo aprire l’ambiente di lavoro IAR, ci troveremo davanti la seguente
schermata.
A questo punto possiamo creare un nuovo workspace tramite il menu a tendina FILE, e poi
creiamo un nuovo progetto tramite PROJECT->CREATE NEW PROJECT, appare la
seguente schermata.
9
Scegliamo di creare un progetto vuoto in C con un main, e lo salviamo in una determinata
cartella che andremo a scegliere. A questo punto dobbiamo configurare una serie di opzioni
del nostro progetto, per fare ciò dobbiamo cliccare con il tasto destro del mouse sul nome
del progetto e dal menù che appare selezionare la voce Options come mostrato nella figura.
A questo punto dal menu che appare dalla categoria General Options nella scheda Target
alla voce Processor Variant selezioniamo in Device la board che andremo ad utilizzare
10
ossia STM32F303XC così come mostrato di seguito.
Una seconda cosa da fare è selezionare le cartelle a cui il compilatore deve fare riferimento,
quindi andiamo nella categoria C/C++ Compiler nella scheda PreProcessor e clicchiamo
sul pulsante in corrispondenza dell’opzione Additional include directories, e cliccando
nella schermata che appare selezioniamo il percorso come di seguito in figura.
11
A questo punto nella categoria Debugger nella scheda Setup alla voce Driver selezioniamo
ST-LINK.
Sempre nella categoria Debugger spuntiamo l’opzione Use flash loader(s) nella scheda
Download.
L’ultima opzione da configurare si trova nella categoria ST-LINK bisogna spuntare
12
l’opzione SWD nella scheda Setup.
Ora siamo pronti per iniziare a scrivere il nostro programma, prima però dobbiamo parlare
dei componenti fondamentali della nostra Board che andremo ad utilizzare ossia il DAC
(Digital to Analog Converter), i Timer, il DMA (Direct Memory Access) e la gestione delle
interruzioni.
13
Capitolo 2: Periferiche
Questo capitolo sarà completamente dedicato a descrivere le periferiche della board che
sono state utilizzate per realizzare il progetto. In particolare abbiamo utilizzato: un DAC per
convertire il segnale campionato tramite un’opportuna funzione generatrice in un segnale
analogico, un DMA affinchè il trasferimento dei campioni dalla memoria (dove sono
memorizzati in un vettore) al DAC avvenisse in modo automatico senza la necessità di
gestirlo tramite software, un Timer utilizzato come trigger per effettuare la generazione con
il DAC in un preciso istante di tempo in modo da soddisfare il valore di frequenza inserito
dall’utente, inoltre è stata gestita anche un’interruzione esterna dovuta al fatto che si è
scelto di cambiare la forma d’onda generata tramite la pressione del pulsante user (tasto blu
sulla board). Di seguito riportiamo le varie specifiche delle periferiche.
2.1 DAC
Il DAC (Digital to Analog Converter) è un componente elettronico che permette di
trasformare un codice numerico in un segnale analogico tramite una determinata legge di
conversione.
Nel caso del STM32F3 abbiamo un DAC a 12 bit, ciò vuol dire che possiamo generare
212=4096 codici distinti. Il DAC di questa board genera tensioni comprese tra 0V e 3V,
quindi al codice 0 corrisponderà la tensione 0V mentre al codice 4095 corrisponderà una
tensione pari a 3V.
La Risoluzione di questo dispositivo è pari a 3V/4096 =0,7mV ossia fra la tensione generata
con un determinato codice e quella generata con il codice successivo c’è un salto pari proprio
alla Risoluzione.
14
Le caratteristiche di questo dispositivo sono le seguenti:
•
Può essere configurato per essere utilizzato o nella modalità a 12 bit oppure nella
modalità a 8 bit, nel caso della modalità a 12 bit questi possono essere allineati a
destra oppure a sinistra;
•
La Board presenta un unico DAC con due canali di conversione che possono essere
usati indipendentemente oppure simultaneamente (dual mode), il canale 1 è mappato
sul pin PA4, mentre il canale 2 è mappato sul pin PA5;
•
Possibilità di generare onde di rumore e onde triangolari;
•
Utilizzo del servizio DMA per entrambi i canali;
•
Rilevazione di errori underrun nel caso di utilizzo del DMA;
•
Utilizzo di trigger esterno per iniziare la conversione;
Di seguito si riporta il diagramma a blocchi del DAC integrato sulla board STM32F3.
Figura 2
Il DAC per scelta progettuale integra un buffer di uscita che può essere usato per ridurre
l’impedenza di uscita e per guidare carichi esterni senza la necessità di dover aggiungere un
amplificatore operazionale. Tale buffer può essere anche disabilitato tramite il settaggio di
15
un bit specifico come vedremo in seguito, nel caso in cui il buffer sia abilitato però bisogna
tenere in conto che il DAC non riuscirà a generare tutti i codici da 0 a 4096, come possiamo
notare dalla seguente tabella presa dal Datasheet della board pag. 112 che riporta le
specifiche elettriche del DAC, con il buffer abilitato la periferica genera tensioni a partire
da 0.2V fino a 2.8V.
Figura 3
Per quanto riguarda invece i tempi di conversione, sempre dalle caratteristiche elettriche
della periferica si evince che questi sono tipicamente di 3µs quando i codici sono “lontani”
16
ossia se ad esempio vogliamo passare da una tensione di uscita del DAC di 0V a 3V e di 1
µs quando invece sono “vicini”.
Figura 4
2.1.1 Descrizione modalità di funzionamento singola
Per poter utilizzare questa periferica bisogna prima di tutto abilitarne il clock, per far ciò
dobbiamo abilitare il relativo bit, consultando IL RCC register map p.132 del Reference
Manual vediamo che tale bit si trova all’interno del registro RCC_APB1ENR e risulta essere
precisamente il bit 29 di tale registro.
Figura 5
17
Dopo questa operazione preliminare è possibile alimentare il canale del DAC scelto tramite
il settaggio del relativo bit nel registro CR (Control Register). Il dispositivo può funzionare
come un DAC a 8 bit oppure a 12 bit, il dato da caricare nel caso di utilizzo a 12 bit può
essere allineato o a desta oppure a sinistra, nel caso di utilizzo a 8 bit può essere allineato
solo a destra.
Figura 6
2.1.2 Conversione
Per caricare il dato da convertire non possiamo accedere direttamente al registro DOR (Data
Output Register) del DAC ma abbiamo accesso al registro preliminare il DHR (Data
Holding Register), ed è proprio questo registro che dobbiamo caricare con il dato da
convertire nelle varianti 8 o 12 bit allineati a dx o sx come descritto in precedenza.
Dobbiamo ora parlare di come poter trasferire il dato dal DHR al DOR per poter poi essere
effettivamente convertito. In un particolare registro avremo un bit TEN (Trigger Enable) il
quale quando posto a zero una volta caricato il DHR effettuerà la copia di quest’ultimo nel
DOR dopo un ciclo di clock, quando invece il bit TEN è settato il trasferimento del dato dal
registro preliminare avviene in seguito a un trigger, e precisamente il trasferimento del dato
nel DOR avviene tre cicli di clock dopo il verificarsi del trigger. Quando il registro DOR è
caricato con il dato da convertire, la corrispondente tensione analogica sarà disponibile dopo
un tempo di assestamento che dipende dalla tensione di alimentazione e dal dalla tensione
che era stata generata in precedenza.
Il dispositivo effettua una conversione lineare tra 0V e 3V secondo la seguente legge:
VOUT = 3V* (DOR/4095)
18
Come abbiamo già detto se il bit TEN è settato la copia del DHR nel DOR avviene tre cicli
di clock dopo l’avvenimento di un trigger, con la board in uso per questo dispositivo ci sono
otto possibili fonti distinte di eventi che possono essere selezionate tramite 3 bit definiti
come TSEL (Trigger Selection), di seguito riportiamo la tabella 49 estratta dal Reference
Manual della board pag.306 con i vari trigger che possono essere selezionati:
Come si può notare ci sono vari trigger pilotati da TIMER, uno guidato da una linea esterna
EXTI linea 9 e un Software Trigger per dare il comando di conversione tramite software.
Dopo aver caricato il dato nel DHR, questo rimane in tale registro fin quando l’interfaccia
del DAC non rileva un fronte di salita sul timer TRGO oppure sulla linea esterna e al
verificarsi dell’evento trasferisce il dato nel DOR dopo tre cicli di clock, nel caso di
Software Trigger invece il trasferimento del dato nel DOR prende solo un ciclo di clock.
2.1.3 Richieste DMA
Entrambi i canali del DAC possono essere serviti da due canali DMA per trasferire i codici
da convertire dalla memoria a uno dei registri DHR senza dover passare dalla CPU e
soprattutto senza dover gestire questi trasferimenti da parte del software. Per abilitare tali
richieste bisogna settare un bit specifico nel DAC il bit DMAEN (DMA Enable) nel registro
19
CR, inoltre bisognerà andare a configurare dei parametri per il DMA cosa di cui parleremo
nel capitolo dedicato a tale periferica. Lato DAC una richiesta di servizio DMA viene
effettuata quando occorre un trigger esterno, tranne che un software trigger, in tal caso il
DHR viene caricato con il valore di un determinato codice in memoria e avviene la
procedura di conversione come prima descritto. Nel caso in cui il DAC generi una nuova
richiesta DMA prima che sia stato ricevuto l’ack per la richiesta precedente si genera una
condizione detta di UNDERRUN, la seconda richiesta non viene accolta inoltre nessun altra
viene rilasciata e viene settato un bit precisamente il DMAUDR (DMA Underrun Error) nel
registro SR (Status Register) del DAC per segnalare la condizione di errore. Per ripristinare
il funzionamento delle richieste DMA bisogna anzitutto pulire il bit DMAUDR via software
(basta scriverci un uno), disabilitare il DMA e riconfigurare sia il DMA che il canale del
DAC scelto facendo in modo o di diminuire la frequenza delle richieste al DMA o cercando
di diminuire il carico di lavoro del DMA, dopo questo è possibile abilitare nuovamente il
DMA e il trigger per la conversione. Nel caso in cui sia settato uno specifico bit è possibile
generare un’interruzione per segnalare la condizione di underrun.
2.1.4 Registri del DAC
Di seguito vengono riportati una serie di registri del DAC illustrandone le funzionalità.
2.1.4.1 Registro DAC_CR (DAC CONTROL REGISTER)
Tale registro è a 32 bit in cui i bit 14-15-30-31 sono dei bit riservati, come dice il nome è
un registro di controllo in cui i bit da 0 a 13 sono relativi al canale 1 del DAC e i bit da 16
a 29 sono i duali dei precedenti solo che si riferiscono al canale 2 del DAC.
20
Di seguito riportiamo il significato dei bit per quanto riguarda il canale 1:
•
Bit 0 EN1: DAC canale 1 bit abilitazione. Tale bit viene utilizzato per abilitare o
disabilitare il canale 1 del DAC via software quando è settato il canale è abilitato.
•
Bit 1 BOFF1: DAC canale 1 buffer uscita disable. Tale bit è utilizzato per abilitare
o disabilitare il buffer di uscita via software, quando è settato il buffer è disabilitato.
•
Bit 2 TEN1: DAC canale 1 trigger enable. Tale bit è utilizzato per abilitare l’utilizzo
del trigger via software. Quando è settato il trigger è abilitato.
•
Bit 5:3 TSEL: DAC canale 1 trigger selection. Questi tre bit vengono utilizzati per
selezionare via software la fonte di trigger esterno così come riportato nella tabella
49 del Reference Manual.
•
Bit 12 DMAEN1: DAC canale 1 DMA enable. Tale bit è utilizzato per
abilitare\disabilitare la modalità DMA tramite software. Quando è settato l’utilizzo
del DMA è abilitato.
•
Bit 13 DMAUDRIE: DAC canale 1 DMA Underrun Interrupt Enable. Tale bit è
utilizzato per abilitare via software il servizio di interruzione in caso di underrun.
2.1.4.2 Registro DAC_DHR12R1
Questo è il registro DHR del DAC canale 1 a 12 bit allineati a destra. Ḗ un registro a 32 bit
in cui viene inserito il codice da convertire nei bit da 0 a 11 mentre i restanti sono riservati.
Figura 7
21
Questo è solo uno dei possibili registri DHR utilizzabili, nella modalità di utilizzo singolo
ci sono anche il DAC_DHR12L1 (Registro DHR 12 bit allineati a sinistra) e DAC_DHR8R1
(Registro DHR 8 bit allineati a destra), ovviamente tali registri sono duplicati per il canale
2 e ce ne sono altri per il funzionamento in modalità duale.
2.1.4.3 Registro DAC_DOR1
Figura 8
Questo è il registro DOR del DAC canale 1. Ḗ un registro a 32 bit in cui i bit utilizzati sono
dal bit 0 a 11 i restanti sono riservati, ovviamente ne esiste un altro per il canale 2.
Ovviamente tali bit sono a sola lettura in quanto come abbiamo già detto non abbiamo
accesso in scrittura a questo registro.
2.1.4.4 Registro DAC_SR (DAC Status Register)
Questo registro è anch’esso a 32 bit, di questi abbiamo il bit 13 DMAUDR1 (DAC canale
1 DMA underrun flag) utilizzato per segnalare la condizione di underrun relative alle
richieste DMA del canale 1 e il bit 29 DMAUDR2 (DAC canale 2 DMA underrun flag) che
ha la stessa funzionalità ma per il canale 2 del DAC. Questi bit sono settati via hardware e
puliti via software scrivendo un uno nel bit corrispondente.
22
Figura 9
2.1.5 Configurazione del DAC
Nel nostro progetto come avremo modo di vedere inseguito nel codice ho utilizzato il canale
1 del DAC per generare il segnale analogico configurato in modo da avere il buffer di uscita
disabilitato BOFF1 registro CR uguale a 0 in modo da poter generare segnali che possono
variare da 0V a 3V, inoltre è stata abilitata la modalità di utilizzo con trigger bit TEN1
uguale a 1 e in particolare è stato utilizzato il trigger generato dall’update del Timer2 bit
TSEL1 pari a 100 poi è stato settato l’utilizzo del servizio DMA tramite il settaggio del bit
DMAEN1 per caricare il registro DHR, nel nostro caso è stato utilizzato il DHR12R1 (DHR
canale 1 a 12 bit allineamento a destra).
2.2 DMA
Il DMA (Direct Memory Access) è una periferica che permette lo spostamento di dati senza
dover passare per la CPU lasciandola libera di poter effettuare altre operazioni. La board
presenta due controller DMA completamente indipendenti ognuno dei quali serve più canali,
ovviamente ogni controller gestisce più canali in base ad una priorità.
2.2.1 Principali caratteristiche
•
Il dispositivo presenta 12 possibili canali indipendenti;
•
Ogni canale è configurabile tramite software ed è connesso ad un hardware dedicato
per le richieste DMA;
•
Le priorità tra richieste provenienti dai canali di un controller DMA sono
23
programmabili a livello software su 4 livelli (molto alta, alta , media, bassa), nel caso
di richieste con uguale priorità software vengono servite le richieste con priorità
hardware più bassa ossia le richieste provenienti dai canali con valori più bassi
(canale 1 ha maggiore priorità rispetto a canale 2 e così via), questa suddivisione è
stata fatta tenendo in conto gli aspetti di criticità del dato, infatti sui canali più bassi
sono state mappate quelle periferiche time critical che bisogna servire per prime in
caso di più richieste;
•
Diverse modalità di trasferimento, il controller permette di trasferimenti di 8-16-32
bit (byte, half word, word), per velocizzare è possibile impacchettare questi dati e
spacchettarli alla destinazione, ovviamente bisogna accordare sorgente e
destinazione sulla dimensione del dato.
•
Sono supportate due possibili modalità di utilizzo quella lineare chiedo n transazioni
le effettuo e mi fermo, oppure la modalità buffer circolare, chiedo n transazioni le
effettuo e dopo ritorno in testa e ricomincio.
•
Per la gestione il controller DMA prevede 3 flag: uno per indicare che è avvenuto
mezzo trasferimento, uno per indicare che il trasferimento è terminato e un altro per
indicare che è avvenuto un problema.
•
Possibilità di effettuare trasferimenti memoria-memoria, memoria-periferica,
periferica-memoria, periferica-periferica.
•
Possibilità di eseguire fino a 65536 transazioni.
Di seguito viene riportato lo schema a blocchi del DMA supportato dalla board in uso.
24
Figura 10
2.2.2 Descrizione funzionale
Come si evince dallo schema a blocchi i due controller sono indipendenti dal core, ciò
potrebbe creare un problema nel caso in cui DMA e Core volessero accedere allo stesso
dato, il sistema è gestito in modo tale da rendere disponibile il dato al Core nel mezzo ciclo
immediatamente successivo all’operazione del DMA, quindi il DMA ha priorità rispetto al
Core. I due controller DMA supportano un certo numero di canali per effettuare delle
richieste, in particolare DMA1 supporta fino a 7 canali, invece DMA2 supporta fino a 5
canali.
2.2.2.1 Transazioni
Per iniziare una transazione la periferica in seguito a un evento invia segnale di richiesta al
25
controller DMA, questi in base alla priorità del canale serve la richiesta e invia un ACK alla
periferica. Molta importanza riveste la configurazione del canale, di seguito vengono
riportati i vari passi:
•
Impostazione del registro CPAR (Peripheral Address Register), sarà settato con
l’indizzo del registro della periferica verso/dal quale saranno spostati i dati;
•
Impostazione del registro CMAR (Memory Address Register), dovrà essere settato
con l’indirizzo della prima cella di memoria dalla quale o verso la quale si vogliono
spostare i dati;
•
Impostazione del registro CNDTR con il numero totale di transazioni che si vogliono
eseguire;
•
Configurazione della priorità software tramite il registro CCR;
•
Configurazione della direzione di trasferimento (memoria-memoria, memoriaperiferica, periferica-memoria, periferica-periferica) tramite il registro CCR;
•
Configurazione della modalità di utilizzo lineare o buffer circolare configurando il
registro CCR;
•
Incremento del puntatore di memoria e periferica, questi puntatori possono essere
incrementati o meno a seconda di come vengono impostati i bit PINC (Peripheral
increment) e MINC (Memory Increment), ovviamente l’incremento del puntatore è
commisurato alla size del dato (8-16-32 bit);
•
Impostazione della size del dato;
•
Generazione di interruzioni per segnalare mezzo trasferimento, trasferimento
completato oppure un errore;
2.2.3 Arbiter
L’arbitro si occupa di soddisfare le richieste in base alla loro priorità e quindi invia le
sequenze di accesso alla periferica/memoria.
Come già detto ci sono quattro livelli di priorità software a parità della quale viene servita
la richiesta con priorità hardware più bassa a seconda del canale da cui arriva la richiesta,
quindi se crediamo che una data richiesta sia critica ma si trova mappata in una posizione
26
scomoda come canale dobbiamo necessariamente dargli una priorità software alta per
permettere che sia servita.
2.2.4 Mappa delle richieste DMA
Di seguito si riporta la tabella 26 estratta dal Reference Manual della board pag.160 in cui
si riportano per quanto riguarda il DMA1 come sono mappate le richieste sui vari canali.
Di seguito invece riportiamo la tabella 27 estratta sempre dal Reference Manual pag.162
che invece riporta la mappatura delle richieste per quanto riguarda il controller DMA2.
27
Le richieste da parte delle periferiche su ogni singolo canale sono logicamente in OR prima
di arrivare al controller DMA, quindi per ogni canale deve essere abilitata una sola richiesta
per volta. Inoltre è prevista la possibilità per alcune periferiche di ricevere le richieste su un
altro canale DMA come possiamo notare nel caso del controller DMA2 per ADC2, questo
di base è mappato sul canale 1, ma può essere mappato anche su canale 3 basta effettuare
una rimappatura del SYSCFG registro CFGR1.
2.2.5 Registri DMA
Di seguito vengono riportati una serie di registri del DAC illustrandone le funzionalità.
2.2.5.1 DMA interrupt status register (DMA_ISR)
Figura 11
Questo registro è a sola lettura in cui vengono riportate per ogni canale le seguenti
condizioni:
•
TEIF:Transfer Error Interrupt Flag, viene settato via hardware quando avviene
un’errore di trasmissione, per resettarlo bisogna settare il bit corrispondente nel
registro IFCR.
•
HTIF:Half Transfer Interrupt Flag, tale bit viene settato via hardware quando è
avvenuto mezzo trasferimento, anch’esso viene pulito scrivendo un uno nel
corrispondente bit del registro IFCR.
•
TCIF:Transfer Complete Interrupt Flag, tale bit invece viene settato via hardware
quando viene completato il trasferimento, per resettarlo basta settare il relativo bit
nel registro IFCR.
28
•
GIF:Global Interrupt Flag, tale bit viene settato via hardware quando avviene
almeno una delle condizioni precedenti, per resettarlo basta settare il relativo bit nel
registro IFCR.
2.2.5.2 DMA interrupt flag clear register (DMA_IFCR)
Figura 12
Questo è un registro a 32 bit dove i bit 28-29-30-31 sono riservati, i restanti sono a sola
scrittura e servono per resettare i bit corrispondenti del registro ISR dalle varie condizioni
di errore che si sono verificate.
2.2.5.3 DMA canale x configuration register (DMA_CCR)
Questo registro è a 32 bit, dove i bit dal 15 al 31 sono riservati, è un registro molto
importante in quanto in esso vengono impostate le configurazioni del canale selezionato.
Figura 13
29
•
Bit 0 EN bit di abilitazione del canale;
•
Bit 1-2-3 vengono utilizzati per abilitare il servizio di interruzione relativamente agli
eventi di trasferimento completato, mezzo trasferimento, errore di trasferimento;
•
Bit 4 DIR serve per impostare la direzione del trasferimento secondo la seguente
modalità, quando il bit è a zero si legge dalla periferica, se invece è a 1 si legge dalla
memoria;
•
Bit 5 CIRC quando viene settato si attiva la modalità circolare altrimenti è attiva
quella lineare;
•
Bit 6-7 PINC (Peripheral Increment) e MINC (Memory Increment) sono utilizzati
per abilitare rispettivamente l’incremento per la periferica e la memoria;
•
Bit 8-9 PSIZE (Peripheral Size) e bit 10-11 MSIZE (Memory Size) sono utilizzati
per impostare la dimensione del dato (8-16-32 bit);
•
Bit 12-13 PL serve per impostare la priorità del canale (bassa, media, alta, molto
alta);
•
Bit 14 MEM2MEM è utilizzato per abilitare i trasferimenti memoria-memoria;
Altri registri che riservano importanza sono il registro DMA_CNDTR utilizzato per
impostare il numero di transazioni da eseguire, il DMA_CPAR per impostare l’indirizzo
base del registro della periferica sui cui effettuare la transazione e il DMA_CMAR in cui
impostiamo l’indirizzo base della cella di memoria sui effettare la prima transazione.
2.2.6 Configurazione del DMA
Per questo progetto ho utilizzato il canale 3 del DMA2 per inviare i codici da convertire al
registro DHR 12 bit allineato a destra del DAC rispettando la tabella X. Per generare il
nostro segnale periodico, quest’ultimo è stato campionato con un determinato numero di
campioni che sono stati memorizzati in un vettore in memoria, poi tramite l’utilizzo del
DMA questi sono stati fatti generare al DAC ottenendo il segnale voluto. In pratica ciò che
abbiamo dovuto configurare per il nostro canale DMA sono stati i registri CPAR con
l’indirizzo del DHR del DAC, CMAR con l’indirizzo della prima cella di memoria del
30
vettore in cui sono stati memorizzati i campioni, il registro CNDTR con il numero di
transazioni da effettuare (ovvero pari al numero dei campioni scelto), poi tramite il registro
CCR è stato configurato la priorità, la dimensione dei dati (entrambe a 16 bit), è stata
impostata la modalità circolare (ovvero terminato di generare un periodo si ricomincia di
nuovo per generarne uno nuovo in modo da avere un segnale periodico), incremento della
memoria (in quanto i campioni sono memorizzati in celle di memoria adiacenti), e poi è
stata impostata la direzione di trasferimento (in questo caso lettura dalla memoria).
Ovviamente per far si che il segnale generato rispetti una determinata frequenza che viene
da noi impostata dobbiamo far in modo di generare un nuovo campione in un istante di
tempo prestabilito, per far ciò è stato utilizzato un Timer per guidare la generazione dei
campioni. Nel prossimo capitolo diamo dei cenni sul funzionamento di questo dispositivo.
2.3 Timer
La board STM32F3 presenta dei Timer hardware che possono essere usati per una varietà
di scopi, come generare segnali a varie frequenze, generazione di PWM oppure essere usati
da trigger per eventi a determinate frequenze, oppure per misurare il tempo trascorso tra due
eventi o per effettuare conteggi. La board presenta fino a 10 timer che possono essere
raggruppati in tre categorie, Basic Timers (TIM6-TIM7), General Purpose Timers
(TIM2-TIM3-TIM4-TIM15-TIM16-TIM17), Advanced Timers (TIM1-TIM8). I Timer
hanno tutti un’architettura comune, gli Advanced Timer hanno caratteristiche hardware
aggiuntive. Tutti i Timers sono completamente indipendenti e non condividono alcuna
risorsa, inoltre possono essere sincronizzati.
2.3.1 Principali Caratteristiche Timer General Purpose
Di seguito si elencano le principali caratteristiche dei Timer General Purpose:
•
Up, down, up/down auto reload counter
•
Fino a 4 canali indipendenti per: Input capture, Output compare, PWM generation,
One-pulse mode output
31
•
Circuito di sincronizzazione per controllare il timer con segnali esterni o per
interconnettere più timer
Figura 14
2.3.2 Funzionamento di base
Il contatore può essere configurato per effettuare un conteggio a incremento, decremento o
centrale (incrementa e poi decrementa). Lo schema di base prevede tre registri, il counter
register (CNT), prescaler register (PSC), auto-reload register (ARR). Il registro CNT è
quello deputato a memorizzare il numero di conteggi effettuati, per misurare il tempo il
timer conta il numero di impulsi di clock che si verificano dal quale conoscendo la frequenza
di clock (72MHz) è possibile risalire al tempo trascorso. Il registo PSC viene utilizzato per
dividere la frequenza del clock di un fattore compreso tra 1 e 65536. Il registro ARR invece
contiene il numero di conteggi da effettuare, per leggere o scrivere su questo registro
bisogna accedere al registro di preload. Il registro di preload modifica con il suo contenuto
il valore del registro ARR in base al valore del bit ARPE (Auto Reload Preload Enable) nel
32
registro CR1, il particolare il registro ARR può essere modificato o in ogni istante dopo che
il registro di preload è stato modificato oppure dopo che si è verificato un evento di update.
L’evento di update si verifica quando il contatore raggiunge l’overflow (oppure underflow
se stiamo contando a decremento). Inoltre è possibile scegliere una modalità di conteggio
singola (faccio un unico conteggio e mi fermo) oppure continua (dopo aver terminato un
conteggio azzero e riparto) configurando il bit OPM (One Pulse Mode) del registro CR1.
Quando avviene un evento di update tutti i registri vengono aggiornati e viene settato il bit
UIF (Update Interrupt Flag). L’evento di update può essere usato come trigger per guidare
altre periferiche, per abilitare tale funzionalità bisogna settare i bit 4-5-6 del registro CR2
chiamati MMS (Master Mode Selection) con il valore 010.
2.3.3 Configurazione del Timer
Per questo progetto ho utilizzato Timer 2 come trigger per la generazione dei campioni con
il DAC. Il valore da inserire nel registro ARR del Timer viene calcolato in automatico in
base alle scelte fatte dall’utente che inserisce la frequenza del segnale che si vuole generare.
2.4 Gestione delle Interruzioni
La gestione delle interruzioni è demandata all’NVIC (Controllore del vettore delle
interruzioni innestate), che gestisce 66 canali di interruzioni mascherabili, sedici linee di
interruzione del core Cortex-M4. La priorità delle interruzioni è programmabile su 16 livelli.
NVIC e il core sono fortemente accoppiati ciò permette di elaborare le interruzioni con una
bassa latenza e di elaborare in modo efficiente interruzioni arrivate in ritardo. Tutte le
interruzioni incluse le eccezioni del core sono gestite dall’NVIC come possiamo notare dalla
tabella del vettore delle interruzioni a pag.183 del Reference Manual e di cui per comodità
di seguito si riporta una parte.
33
Figura 15
Possiamo pensare alla memoria lineare come se fosse partizionata in varie zone, la prima è
quella che corrisponde al vettore delle interruzioni, di questa zona una parte è dedicata al
core, la successiva è quella dedicata alla gestione delle interruzioni generate dalle
periferiche, tale servizio deve essere abilitato sia all’interno della periferica tramite
un’opportuno bit, inoltre devo comunicare al core che il servizio delle interruzioni è
abilitato, per questo il controllore del vettore delle interruzioni innestate (NVIC) ha dei
registri ISER (Interrupt Service Enable Register) per abilitare il servizio della routine
corrispondente, nel vettore delle interruzioni ho delle posizioni relative in cui a ogni
posizione corrisponde una interruzione come si può notare dalla figura X, per abilitare il
servizio di interruzione nel core della routine alla posizione x devo porre un uno nel registro
NVIC->ISER alla posizione x. Ora dato che le posizioni nel vettore sono 92 e l’architettura
del core è a 32 bit avremo 3 registri ISER uno che ricopre le posizioni da 0 a 31, il secondo
34
per le posizioni da 32 a 63 e l’ultimo le restanti. Dopo aver abilitato il servizio nel caso arrivi
una richiesta di interruzione il processore salva il contesto corrente in uno stack, procede a
servire l’interruzione saltando con il Program Counter alla relativa ISR terminata la quale
riprende dallo stack il suo stato precedente e continua la sua esecuzione.
2.4.1 Extended interrupts and event controller (EXTI)
EXTI gestisce eventi\interruzioni asincroni interni ed esterni, genera una richiesta di evento
alla CPU\Controller delle interruzioni e una richiesta di risveglio al Power Manager. EXTI
permette di manipolare 28 linee esterne e 8 linee interne, per le linee esterne il fronte attivo
per l’interruzione può essere scelto in modo indipendente fra quello di salita, discesa oppure
entrambi, mentre per le linee interne il fronte attivo è sempre quello di salita. Per la
generazione di una interruzione nel caso di una linea esterna dobbiamo configurare la linea,
dobbiamo scegliere il fronte che attiverà l’interruzione settando il bit relativo nel registro
RTSR (Registro per la selezione del trigger sul fronte di salita) oppure FTSR (Duale del
primo per quanto riguarda il fronte di discesa) oppure dobbiamo settare entrambi se
vogliamo un’interruzione sia sul fronte di salita che su quello di discesa, poi bisogna
abilitare la richiesta di interruzione nel registro IMR (Interrupt Mask Register) in quanto
l’interruzione può essere anche mascherata e ovviamente abilitare il servizio nel core tramite
l’NVIC come visto in precedenza. A questo punto quando si verifica il fronte selezionato
viene generata una richiesta e viene settato un bit relativo a quella linea nel registro PR
Registro di pending, quando serviamo la richiesta tale bit viene resettato scrivendoci un uno.
Inoltre per quanto riguarda le richieste di interruzioni esterne possono essere emulate anche
tramite software basta settare il bit relativo alla linea nel registro SWIER (Software Interrupt
Event Register) infatti l’hardware di queste linee è multiplexato con i bit di quest’ultimo
registro. La figura di seguito riporta il diagramma a blocchi di EXTI.
35
Figura 16
I PIN GPIO sono connessi su 16 linee esterne da EXTI0 a EXTI15 come di seguito:
36
Ogni PIN può essere selezionato configurando nel modo opportuno il registro EXTICR del
SYSCFG.
2.4.2 Configurazione Interruzione esterna
Per questo progetto è stato utilizzato il pulsante User della board per cambiare la forma
d’onda generata. Dal datasheet tale pulsante è collegato al PIN 0 della porta A della board,
e quando viene premuto porta tale pin al valore logico alto quando invece viene rilasciato
lo porta al valore logico basso. Pertanto è stato abilitato il servizio di interruzione nel core
della linea EXTI0, poi è stata smascherata la relativa linea nel registro IMR e selezionato il
fronte di salita come fronte attivo.
37
Capitolo 3: Codice
Di seguito si riporta il codice prodotto, opportunamente commentato e alcune foto relative
a prove effettuate in laboratorio con uso dell’oscilloscopio.
In questa prima parte di codice dapprima abbiamo trasformato il valore dell’ampiezza del
segnale espresso in Volt nella corrispondente parola codice esprimibile con il DAC (riga
12), poi è stato trasformato il valore di frequenza inserito nel corrispondente periodo del
segnale espresso in ms (riga 13). Inoltre abbiamo calcolato la costante di tempo del segnale
esponenziale tau (riga 15) e il tempo di campionamento ossia il tempo che intercorre fra la
generazione di un campione e quello successivo (riga 16). Poi è stato scelto di creare tre
distinte LUT look-up table per i tre tipi di segnale che andremo a generare in ognuna delle
quali vengono memorizzati i campioni del segnale relativi ad un singolo periodo, le righe
20-21 rappresentano il codice per la creazione della LUT relativa al segnale sinusoidale
38
(memorizzata nel vettore inputSIN), le righe da 25-29 si riferiscono al segnale triangolare
(LUT memorizzata nel vettore inputTRIANGOLO), le righe 33-35 invece sono quelle
relative al segnale esponenziale (LUT memorizzata nel vettore inputSIN)
In questa seconda parte di codice dapprima è stato abilitato il clock delle varie periferiche
utilizzate possiamo notare alle righe 39-40 che tramite i due registri dell’RCC AHBENR e
APB1ENR è stato abilitato il clock della porta A (di cui utilizzeremo PA0 come fonte di
interruzione esterna in quanto è collegato al tasto USER e PA4 sul quale è mappato l’uscita
del DAC canale 1), il clock del DMA2 (infatti abbiamo utilizzato il canale 3 del DMA2 per
scrivere i dati nel DHR del DAC), il clock del DAC (periferica utilizzata per effettuare la
conversione), il clock di TIM2 (abbiamo utilizzato Timer2 per generare i campioni con il
DAC in modo da rispettare i vincoli di frequenza del segnale da generare. Alla riga 41 invece
abbiamo impostato PA4 (uscita del DAC) come analogico tramite l’utilizzo del registro
MODER. Poi è stato configurato il canale 3 del DMA2 che come abbiamo già detto è stato
utilizzato per inviare i dati al DAC, in particolare alla riga 45 è stato impostato il registro
CPAR con l’indirizzo del DHR 12 bit allineamento a destra del DAC canale 1, invece alla
riga 46 è stato configurato tale canale tramite il registro CCR, in particolare sono state
impostate le dimensioni del dato a 16 bit, incremento della memoria ad ogni transazione e
lettura dei dati dalla memoria, in seguito abbiamo impostato il DAC canale 1 (riga 51)
tramite il registro CR è stato abilitato il servizio DMA, il funzionamento con trigger e in
39
particolare con il trigger generato dall’update di TIM2. Poi è stata eseguita l’impostazione
del Timer 2 (righe 55-58), tale Timer è stato utilizzato come trigger per generare i campioni
con il DAC e quindi è stato impostato in modo da misurare il tempo fra la generazione di
un campione e il successivo rispettando il vincolo della frequenza del segnale da generare.
In particolare è stato impostato il registro ARR con il valore del periodo/numero di
campioni, poi è stato impostato il registro PSC paria a zero in quanto non è stata effettuata
nessuna divisione del clock, poi tramite il registro CR2 è stato utilizzato l’evento di update
come sorgente di trigger. Per ultimo è stata configurata l’interruzione esterna riguardante la
pressione del tasto user (righe 62-66), notiamo che prima è stato abilitato il clock del
SYSCFG tramite il registro APB2ENR dell’RCC, poi abbiamo impostato PA0 come fonte
di interruzione esterna tramite il registro EXTICR[0] del SYSCFG (infatti il tasto user è
collegato alla porta PA0), inoltre abbiamo smascherato l’interruzione sulla linea 0 tramite il
registro IMR e poi abilitato l’interruzione sul fronte di salita tramite il registro RTSR, in
ultimo abbiamo abilitato l’interruzione nell’NVIC tramite il registro ISER.
In questa terza parte abbiamo invece la gestione dell’interruzione legata alla pressione del
tasto user, possiamo notare che appena entriamo nella routine per prima cosa puliamo il bit
di pending (riga 74). Notiamo che ad ogni pressione del tasto fermiamo il flusso da parte
40
del controller DMA (riga 78), poi in base al valore della variabile scelta terminiamo
l’impostazione del canale DMA settando il registro CMAR che contiene l’indirizzo della
prima cella di memoria del vettore in cui sono memorizzati i campioni da inviare al DAC.
In particolare possiamo notare che quando scelta è uguale a 1 carichiamo CMAR con
l’indirizzo della prima cella di memoria del vettore inputSIN, quando è pari a 2 con la prima
cella di memoria del vettore inputTRIANGOLO, quando è pari a 3 con la prima cella di
memoria di inputEXP. Poi impostiamo il registro CNDTR del canale 3 del DMA 2 con il
numero di transazioni da eseguire che è pari al numero di campioni e abilitiamo il canale
DMA (righe 102-103). A questo punto il codice del generatore è terminato, di seguito si
riportano le misurazione eseguite in laboratorio con l’oscilloscopio nel caso di generazione
del segnale con ampiezza pari a 3V e frequenza pari a 1KHz.
Segnale Sinusoidale
41
Segnale Triangolare
Segnale Esponenziale
42
Conclusioni
Scopo di questo lavoro di tesi è stato la realizzazione di un generatore di forme d’onda
arbitrarie basato su microcontrollore STM32F303, in particolare si è deciso di realizzare tre
segnali periodici uno sinusoidale, uno triangolare e uno esponenziale di cui si può impostare
ampiezza e frequenza. Per poter realizzare ciò si è pensato di costruire tre LUT (Look-UP
Table) per contenere i campioni di un singolo periodo dei tre segnali, poi si è ottenuto il
segnale desiderato tramite un DAC presente sulla board che ha trasformato tali campioni in
segnali analogici. Ovviamente generando continuamente i campioni si è ottenuto il segnale
sinusoidale; per far ciò è stato sfruttato l’utilizzo di un controller DMA anch’esso presente
sulla board. Quindi siamo riusciti ad ottenere un generatore di segnali tramite l’utilizzo di
un microcontrollore a basso costo e soprattutto con buone caratteristiche, infatti dal
Datasheet della board fra le caratteristiche del DAC possiamo notare che ha un valore di
INL (Integral non Linearity) ossia la differenza tra il valore misurato al codice I e il valore
al codice I disegnato su una linea che congiunge il codice 0 e l’ultimo codice generabile con
il DAC, tale differenza risulta essere ±4 LSB per un codice in ingresso a 12 bit. In
conclusione i microcontrollori hanno avuto un grosso successo grazie alle numerose
periferiche che incorporano, alla facilità di programmazione e soprattutto grazie al loro
basso costo accoppiato alle elevate prestazioni. I microcontrollori sono presenti in svariati
campi industriali, noi stessi li utilizziamo tutti i giorni senza nemmeno rendercene conto.
43
Bibliografia
[1]
A. Liccardo, Appunti del corso di Misure per l’Automazione e la Produzione
Industriale, 2015
[2]
STMicroelectronics, RM0316 Reference Manual
[3]
STMicroelectronics, STM32F302xx/STM32F303xx Datasheet
[4]
STMicroelectronics, UM1570 User Manual
44