Programmazione di microcontrollori STM32: Protocollo SPI e ... · 4 Introduzione L’utilizzo di...

33
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: Protocollo SPI e comunicazione con sensore Anno Accademico 2014/2015 Candidato: Antonio Pagano matr. N46001239

Transcript of Programmazione di microcontrollori STM32: Protocollo SPI e ... · 4 Introduzione L’utilizzo di...

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: Protocollo SPI e comunicazione con sensore

Anno Accademico 2014/2015 Candidato: Antonio Pagano matr. N46001239

“ Alla nonna Lucia e alla zia Carolina, le quali hanno sempre creduto nelle mie capacità ”

III

Indice

Indice .................................................................................................................................................. III

Introduzione ......................................................................................................................................... 4 Capitolo 1: Serial Peripheral Interface (SPI) ....................................................................................... 5

1.1 Interfaccia ................................................................................................................................... 6

1.2 Configurazione master-slave ...................................................................................................... 7

1.3 Struttura interna.......................................................................................................................... 8

1.4 Comunicazione sul bus ............................................................................................................ 10

1.5 Modalità Half-duplex ................................................................................................................... 12

Capitolo 2: SPI (STM32F4xx) ........................................................................................................... 13 2.1 Caratteristiche principali .......................................................................................................... 13

2.2 Registri SPI .............................................................................................................................. 15

2.3 Gestione della trasmissione e della ricezione .............................................................................. 22 Capitolo 3: Comunicazione con il sensore (il Giroscopio) ................................................................ 23

3.1 Attivazione PIN e settaggio della modalità .............................................................................. 24

3.2 Trasmissione tra SPI1 e sensore di Giroscopio ........................................................................ 25

Capitolo 4: Esempio di utilizzo del protocollo SPI e comunicazione con il sensore sul

microcontrollore STM32F4xx ........................................................................................................... 27

Bibliografia ........................................................................................................................................ 33

4

Introduzione

L’utilizzo di microcontrollori è sempre più consistente nella società moderna. Tale

successo lo si deve principalmente all’enorme utilizzo che tale componente prevede in

molti dispositivi, anche di uso comune, come ad esempio una lavatrice o un caricabatterie.

I microcontrollori della famiglia STM32 sono tra i più diffusi e utilizzati sul mercato. Tali

dispositivi sono prodotti dalla STMicroelectronics, una società franco-italiana, tra i più

grandi produttori di componenti elettronici al mondo.

In questo elaborato verrà adoperato proprio un microcontrollore STM32 per studiare e

mostrare l’utilizzo di uno dei principali protocolli di comunicazione tra dispositivi: il

protocollo Serial Peripheral Interface (SPI).

In particolare, la trattazione sarà suddivisa in livelli: si mostreranno le caratteristiche

tecniche e teoriche riguardanti il protocollo SPI, per giungere successivamente alla sua

applicazione nei microcontrollori STM32. In particolar modo sarà poi mostrata come

effettuare la comunicazione tra il microcontrollore e il sensore interno di giroscopio

digitale. Viene infine fornito il codice sorgente da caricare sul microcontrollore che

consente di ottenere i valori degli assi di rotazione x, y e z.

5

Capitolo 1: Serial Peripherl Interface (SPI)

SPI (Serial Peripheral Interface) è un bus di comunicazione seriale sincrono sviluppato da

Motorola e utilizzato per comunicazioni tra dispositivi a brevi distanze: tra un

microcontrollore e altri circuiti integrati tra più microcontrollori.

La trasmissione avviene tra un dispositivo detto master e uno o più slave (letteralmente

dall’inglese padrone e schiavo). Il master controlla il bus, cioè ne prende possesso così da

evitare che altri dispositivi possano utilizzarlo mentre questo è occupato. Di seguito,

emette il segnale di clock e decide quando iniziare e terminare la comunicazione, inviando

frames di scrittura/lettura al dispositivo slave. Il protocollo SPI prevede un’architettura

single-master multi-slave.

Per quanto riguarda la velocità di scambio dei dati, essa dipende fortemente dalla scelta

della frequenza di clock, cioè dal numero di impulsi che il segnale di clock genera in un

secondo. Ad ogni impulso generato, si effettua la trasmissione di un bit. Risulta evidente

quindi che tanto più questi impulsi sono frequenti, tanto più velocemente sarà passato il

dato. La frequenza di clock viene settata dal dispositivo master. Non vi è un limite di

velocità minimo, in quanto i dispositivi sono statici: se alimentati possono mantenere uno

stato logico per un tempo indefinito. Vi è tuttavia un limite massimo che va determinato

dai datasheet [1] dei singoli dispositivi connessi.

Il bus SPI di definisce full-duplex in quanto il “colloquio” può avvenire

contemporaneamente sia in trasmissione che in ricezione.

1 Documentazione che riassume le caratteristiche di un componente, un apparato, un software o anche un composto

chimico. Di solito si presenta in formato PDF.

6

1.1 Interfaccia

Il generico dispositivo SPI prevede 4 canali:

SCLK (SCK): Serial Clock;

MOSI: Master Output Slave Input;

MISO: Master Input Slave Output;

CS (SS): Chip Select (Slave Select);

Essendo a 4 canali, il sistema è genericamente detto a 4 fili. Va però tenuto conto che

deve esserci una connessione di riferimento (Vref) e che quindi fisicamente i fili sono

cinque.

Figura 1.1

Nel dettaglio:

SCLK (SCK) è il canale del clock, il quale scandisce gli istanti in cui master e

slave possono trasmettere e ricevere i bit sul bus. Tale canale è gestito dal master,

il quale dunque richiede la trasmissione, di volta in volta, di una “parola”;

MOSI è il canale adoperato per trasmettere il dato dal dispositivo master a quello

slave;

MISO è il canale adoperato per trasmettere il dato dal dispositivo slave a quello

master;

CS (SS) è il canale attraverso cui il master sceglie con quale dispositivo slave

comunicare. Per abilitare la comunicazione è necessario settare il pin SS ad un

livello logico basso (come si nota dalla Figura 1.1, il pin SS è negato, dunque nel

caso sia settato al livello logico alto esso diventa di livello logico basso,

disabilitando la comunicazione).

7

1.2 Configurazioni master-slave

Si mostrano di seguito due configurazioni possibili per il collegamento tra master e slave:

Dispositivi slave controllati singolarmente

Ogni dispositivo slave è

collegato ad un pin con il

segnale SS del dispositivo

master. Il dispositivo master

dovrà avere un numero di pin

SS pari al numero di

dispositivi slaves collegati.

Dunque abilitando un

determinato pin SSi, verrà

attivato lo slave corrispondente a tale pin.

In definitiva ogni slave si collega al dispositivo master indipendentemente dagli altri

slaves.

Il numero di dispositivi slaves che si possono connettere al bus è limitato esclusivamente

dal numero massimo di linee gestibili dal master.

Il vantaggio di tale soluzione è la velocità di comunicazione tra il master e i singoli slave.

Di contro, lo svantaggio è l’eccessivo numero di pin SS richiesti per tale architettura.

Figura 1.2

8

Dispositivi slaves connessi in catena (daisy chain)

Il dispositivo master possiede un unico pin SS in uscita ed il segnale che esso pilota è

inviato a tutti i dispositivi slave

sui relativi pin SS. I dispositivi

slave vengono quindi attivati tutti

contemporaneamente, ma

lavorano in catena: il dispositivo

master invia il dato effettivamente

solo al primo dispositivo slave,

attraverso il canale MOSI.

Successivamente, i dispositivi

slave comunicano tra loro in cascata, utilizzando i canali MISO e MOSI: lo slave i-1 invia

il dato attraverso il suo canale MISO, mentre lo slave i riceve il dato sul suo canale MOSI.

Tale catena si ripete fino all’ultimo slave, il quale avrà il proprio canale MISO collegato a

quello del master.

Il vantaggio di tale soluzione è l’abolizione di un numero elevato di pin SS a favore di un

unico pin SS che gestisce tutti gli slave. Di contro lo svantaggio è la minore velocità di

aggiornamento dei singoli slaves.

1.3 Struttura interna

Figura 1.4

Ogni dispositivo SPI possiede un registro a scorrimento utilizzato per inviare e ricevere i

dati serializzati. Un registro a scorrimento è un componente molto utilizzato in elettronica

Figura 1.3

9

digitale: esso è costituito da una serie di flip-flop[2] di tipo D, collegati tra loro in modo

tale che l’uscita del precedente sia l’ingresso del successivo. Un flip-flop di tipo D è

dotato di un ingresso per il dato (D), di un ingresso per la sincronizzazione (clock) e di

un’uscita (Q). Quando riceve il segnale di clock, trasferisce l’ingresso in uscita e lo

mantiene finché non cambia l’ingresso.

Nella sua versione più semplice il registro a scorrimento ha il seguente funzionamento: ad

ogni colpo di clock, ogni flip-flop passa il proprio valore al successivo ed il primo flip-

flop della catena assume il valore del segnale di ingresso al registro. Il valore

precedentemente memorizzato nell'ultimo flip-flop viene assegnato al segnale di uscita del

registro a scorrimento. Lo scorrimento può avvenire dal bit più significativo verso quello

meno significativo, o viceversa.

In SPI, usualmente tale registro ha una dimensione di 8 bit, ma in generale potrebbe avere

dimensione arbitraria, a patto che siano di uguali dimensioni il registro del dispositivo

master e quello slave. Se si suppone un trasferimento da parte del master verso lo slave, il

dato contenuto nell'ultimo flip-flop verrà trasmesso sul canale MOSI. Nel dispositivo

slave, a sua volta, il canale MOSI sarà collegato al primo flip-flop del suo registro a

scorrimento. I dati avanzano nei due registri a scorrimento utilizzando la sincronizzazione

del segnale SCLK inviato dal dispositivo master. L'ultimo flip-flop del registro a

scorrimento del dispositivo slave, a sua volta, è collegato al segnale in uscita MISO. I dati

pervenuti nel dispositivo master e provenienti dal dispositivo slave, sul segnale MISO,

saranno caricati a loro volta nel primo flip-flop del registro a scorrimento del master.

L'architettura interna composta dai registri a scorrimento, unita alla configurazione delle

interconnessioni dei segnali MISO e MOSI, consentono di realizzare un anello chiuso.

2 Circuito elettronico sequenziale utilizzato in elettronica digitale come cella di memoria elementare

10

Proprio tale architettura ad anello permette ai dispositivi SPI di effettuare una

comunicazione di tipo full-duplex.

Nei dispositivi commerciali è possibile configurare la direzione dei dati trasmessi dal

registro a scorrimento: in un caso si ha che il primo bit ad essere trasmesso è quello più

significativo, viceversa si ha quello meno significativo.

1.4 Comunicazione sul bus

La comunicazione tra master e slave avviene seguendo nell’ordine le seguenti operazioni:

1. Il dispositivo master, nel caso in cui il dispositivo slave sia controllato

singolarmente, seleziona lo slave con cui comunicare settando il segnale SS

corrispondente al livello logico basso (logica 0-Attiva). Nel caso di un’architettura

di tipo slaves in catena, il master setta il suo unico segnale SS al livello logico

basso;

2. Il master invia il segnale di clock, configurandolo ad una frequenza tale che tutti i

dispositivi possano supportarlo;

3. Ad ogni ciclo di clock avviene la comunicazione: il master invia il primo bit del

dato attraverso il canale MOSI, insieme al segnale di clock;

4. Il dispositivo slave riceverà il segnale di clock e il primo bit sul canale MOSI,

interpretandolo come l’inizio della comunicazione. In contemporanea invierà un

altro dato sul canale MISO.

Notiamo come la comunicazione tra i due dispositivi sia effettivamente seriale, in quanto

sia sul canale MISO che su quello MOSI sarà trasmesso un solo bit alla volta. Tuttavia, i

dispositivi compiono effettivamente un tipo di comunicazione in parallelo, in quanto

verranno passati due bit in contemporanea: uno sul canale MOSI, uno sul canale MISO.

Questo implica che ogni dispositivo invierà il suo bit più significativo (o meno

significativo in base alla direzione dello scorrimento del registro) e riceverà in

contemporanea un bit che verrà posto come bit meno significativo (o più significativo) sul

registro.

11

Si è detto che il dispositivo master setta la frequenza del segnale di clock. Esso deve

inoltre configurare la sua polarità, ovvero il valore logico su cui si porta il segnale di

clock quando questo è inattivo, e la sua fase, ovvero il fronte di clock in cui il ricevente

campiona il segnale in ingresso. Tali attributi sono settabili attraverso due parametri:

CPOL per la polarità, CPHA per la fase.

Le possibili combinazioni sono le seguenti:

1. CPOL = 0, CPHA = 0: Il dato è catturato sul fronte di salita e propagato sul fronte

di discesa del clock

2. CPOL = 0, CPHA = 1: Il dato è catturato sul fronte di discesa e propagato sul

fronte di salita del clock

3. CPOL = 1, CPHA = 0: Il dato è catturato sul fronte di discesa e propagato sul

fronte di salita del clock

4. CPOL = 1, CPHA = 1: Il dato è catturato sul fronte di salita e propagato sul fronte

di discesa del clock

Figura 1.5

12

1.5 Modalità Half-duplex

Come si è detto, il protocollo SPI implementa implicitamente la modalità full-duplex.

Tuttavia alcune implementazioni dei dispositivi supportano la modalità half-duplex: il

dispositivo master e il dispositivo slave comunicano tra loro su un unico canale detto SISO

(Slave input Slave output), il quale può essere bidirezionale in presenza di un dispositivo

slave che trasmette dati verso il master oppure no.

13

Capitolo 2: SPI (STM32F4xx)

I SoC[3] della famiglia STM32F4xx, prodotti da ST Microelectronics, supportano e

implementano il bus SPI. Essi posseggono 3 periferiche per l’utilizzo di SPI: SPI1, SPI2,

SPI3. Il dispositivo indicato con SPI1 è connesso al bus APB2 a 84MHz, mentre gli altri

due (SPI2 e SPI3) sono connessi al bus APB1 a 42MHz. Tramite l’interfaccia di tali

dispositivi è possibile la trasmissione seriale sincrona dei dati verso i dispositivi esterni al

System-on-a-Chip. Oltre alla modalità full-duplex, è supportata anche la modalità half-

duplex.

2.1 Caratteristiche principali

Attraverso l’interfaccia SPI dei dispositivi forniti dalla famiglia STM32F4xx, è possibile

settare le seguenti caratteristiche:

Modalità full-duplex per la trasmissione dei dati utilizzando tre canali (SCK,

MISO e MOSI);

Modalità half-duplex per la trasmissione monodirezionale o bidirezionale su due

canali;

Lunghezza delle frame di 8-bit o 16-bit;

Modalità operative master o slave;

8 prescaler per la regolazione del baud rate (fPCLK/2 max);

Selezione del dispositivo slave in hardware o software (NSS);

Configurazione in software dei parametri CPOL e CPHA;

3 System-on-a-chip (sistema su circuito integrato), è un circuito integrato in cui un solo chip contiene un intero sistema.

14

Configurazione in software della direzione di trasferimenti dei dati (prima il bit più

significativo, o prima quello meno significativo);

Flag nei registri di stati dedicati alle interruzioni;

Generazione e controllo in hardware del CRC[4];

Controllo degli errori con flag e interruzioni (master mode fault, overrun e CRC).

L'interfaccia possiede 4 canali principali:

1. MOSI: Linea dati per la trasmissione dei dati dal dispositivo master a quello slave;

2. MISO: Linea dati per la trasmissione dei dati dal dispositivo slave a quello master;

3. SCK: Serial clock inviato dal dispositivo master a quello slave;

4. NSS: Linea di controllo utilizzata per la selezione del dispositivo slave.

La struttura di SPI su STM32F4xx è fornito dal seguente diagramma a blocchi:

Figura 2.1

4 Cyclic redundancy check (controllo a ridondanza ciclica), metodo per il calcolo delle somme di controllo (checksum).

Utilizzato per il controllo sulla trasmissione dei dati.

15

2.2 Registri SPI

Nel seguito saranno mostrati come settare i registri del microcontrollore STM32F4xx

riguardanti SPI, per configurare le varie caratteristiche.

In particolare verranno utilizzati i seguenti registri:

SPI_CR1

SPI_CR2

SPI_SR

Selezione del dispositivo in modalità master o slave

Il dispositivo seleziona la sua modalità di master o di slave attraverso la configurazione

del bit MSTR del registro SPI_CR1. Settando tale bit al livello logico 1, il dispositivo

opererà in modalità master; settato al livello logico 0, il dispositivo sarà configurato in

modalità slave.

Gestione della selezione dello slave (NSS)

La selezione del dispositivo slave può avvenire sia in hardware che in software. Tale scelta

si effettua configurando il bit SSM (Software Slave Management) nel registro SPI_CR1:

se il bit viene settato al valore logico 1, la selezione dello slave è fatta in software, se

settato a 0, la selezione è fatta in hardware. Se la selezione è fatta in software, il valore del

bit SSI (Internal Slave Select) viene forzato sul pin NSS, ignorando il valore che

quest’ultimo possedeva: in questo modo, dunque, il dispositivo (che opererà in modalità

16

slave) verrà selezionato in base alla configurazione software presente nel bit SSI.

Ricordiamo che per essere attivo, lo slave deve avere livello logico basso su SS, per cui il

bit SSI deve essere settato a 0 per attivarlo. Il valore del bit SSI viene ignorato nel caso in

cui il bit SSM non sia stato settato.

Se la selezione è fatta in hardware, invece, il pin NSS può essere configurato come input o

output, a seconda che si tratti rispettivamente di un dispositivo slave o master. Se

configurato come output (dunque per la modalità master), la periferica piloterà

opportunamente questo segnale al livello logico basso (logica 0-attiva) quando è

necessario selezionare il dispositivo slave a cui è collegato. A questo punto il dispositivo

master è pronto per il trasferimento dei dati e il dispositivo slave agirà da tale, a valle della

rilevazione del passaggio del livello logico alto -> basso del segnale NSS. Il segnale NSS

dovrà essere al livello logico basso durante tutta la durata della trasmissione della frame.

Configurazione baud rate

E’ prevista la possibilità di selezionare 8 possibili configurazioni di baud rate attraverso

l’interfaccia SPI. Tanto più alto sarà il baud rate, cioè la velocità con cui viaggiano i dati,

tanto meno tempo sarà impiegato per la comunicazione.

Il baud rate è definito come: fPCLK / 2 max

dove fPCLK è la frequenza del segnale di clock (SCK), e max equivale a 2i, con i che varia

nell’intervallo [1, 8].

Sono messi a disposizione 3 bit, corrispondenti a BR[2:0], del registro SPI_CR1 (i bit 3, 4

e 5), per selezionare il baud rate desiderato. Le possibili configurazioni sono:

17

Configurazione parametri CPOL e CPHA (clock polarity e clock phase)

Al fine di determinare gli istanti temporali di propagazione e cattura del dato sui canali

MISO e MOSI, è possibile configurare la polarità e la fase del clock dando luogo a quattro

possibili modalità operative differenti, così come visto precedentemente. I due parametri

CPOL e CPHA sono configurabili nel registro SPI_CR1, attraverso i bit CPOL e CPHA.

Dal settaggio di tali bit, si determinano, dunque, se la lettura del dato deve avvenire sul

fronte di salita o discesa e se il livello logico idle del segnale di clock deve essere quello

basso oppure alto.

Si noti inoltre che siccome il segnale SCK è mappato su un pin in uscita per il master

(entrata nel caso dello slave) mediante GPIO, è necessario configurare una resistenza di

pull-up nel caso in cui CPOL=1 o una resistenza di pull-down nel caso in cui CPOL=0. Il

dispositivo master e quello slave devono configurare questi due parametri allo stesso

modo.

Lunghezza della frame e direzione

L'interfaccia può lavorare con frame di dimensione differenti. È possibile configurare la

lunghezza del frame (singola trasmissione) usando il bit DFF del registro SPI_CR1: se

impostato a 0, la frame di trasmissione/ricezione sarà di 8-bit, viceversa di 16-bit. La

direzione di trasferimento (prima il bit più significativo o prima quello meno significativo)

è configurabile, invece, utilizzando il bit LSBFIRST nel registro SPI_CR1: se settato a 0

la trasmissione inizia dal bit più significativo, se settato a 1 dal bit meno significativo.

Modalità half-duplex

L’interfaccia SPI in STM32F4xx prevede la possibilità di utilizzare la modalità half-

duplex. Con tale modalità è possibile utilizzare un unico canale per la trasmissione delle

informazioni. Tale trasmissione può essere bidirezionale, cioè i dati possono essere

18

trasferiti dal master allo slave e viceversa, o monodirezionale, ovvero i dati possono essere

trasferiti esclusivamente dal master allo slave.

Nella modalità half-duplex, inoltre, i canali vengono ridotti da 4 a 3, in quanto si userà un

unico canale per la trasmissione: il MOSI se si tratta del dispositivo master, il MISO se si

tratta di quello slave. L’interfaccia sarà costituita allora dai canali SCK, MOSI/MISO,

NSS.

Si mostrano quindi i bit da configurare per la modalità half-duplex di tipo:

Bidirezionale: si setta a 1 il bit BIDIMODE del registro SPI_CR1. Si può inoltre

configurare la direzione del trasferimento attraverso il bit BIDIOE, sempre del

registro SPI_CR1; se posto a 1, la direzione sarà di output per quella periferica

(uscente), se posto a 0 sarà di input (entrante).

Monodirezionale: si setta il bit BIDIMODE a 0. La direzione del trasferimento

viene impostata dal bit RXONLY del registro SPI_CR1; se posto a 0, la

trasmissione sarà dal master allo slave, se posto a 1, la trasmissione sarà di sola

ricezione, quindi il master sarà in grado esclusivamente di ricevere i dati dallo

slave. Si noti che, anche nel caso in cui il master sia in modalità di sola ricezione,

lo slave, prima di cominciare la trasmissione, dovrà comunque attendere la

selezione sul segnale NSS e rilevare il cambiamento di fronte sul segnale SCK.

Data Register (DR)

Il registro SPI_DR mantiene i dati ricevuti o da trasmettere durante la comunicazione

attraverso SPI. Tale registro è suddiviso in due buffer: uno dedicato alla trasmissione,

Trasmission buffer (Tx buffer), e uno dedicato alla ricezione, Receive buffer (Rx buffer).

In caso di scrittura su SPI_DR, il dato sarà scritto sul Tx buffer; in caso di lettura su

SPI_DR, sarà letto il dato tenuto sul Rx buffer.

19

Tale struttura è chiarita dal particolare dello schema a blocchi di figura 2.1:

Figura 2.2

Si ricordi inoltre che SPI prevede la selezione di due formati diversi di frame: 8-bit o 16-

bit. Nel caso in cui la lunghezza della frame sia di 8-bit, i buffers saranno di soli 8-bit,

corrispondenti agli 8 bit meno significativi del registro SPI_DR, e solo tali bit saranno

utilizzati per la ricezione/trasmissione.

Generazione e controllo del CRC

Per garantire trasferimenti affidabili, l'interfaccia SPI nei SoC della

famiglia STM32F4xx implementa in hardware il calcolo e la verifica del CRC.

Il calcolo avviene serialmente su ogni bit, attraverso l’utilizzo di un polinomio di grado n-

1, dove n è il numero di bit della frame da verificare. E’ possibile settare il polinomio

generatore del codice CRC nel registro SPI_CRCPR. Ricordiamo che le frames possono

essere di 8 o 16 bit, dunque il polinomio sarà al massimo di grado 15.

La generazione e il controllo del CRC è abilitata settando il bit CRCEN nel registro

SPI_CR1. Durante una trasmissione, il codice CRC viene calcolato serialmente e riposto

20

nel registro SPI_TXCRCR. Quindi ad ogni bit trasmesso, si calcolerà il corrispettivo CRC,

il quale verrà memorizzato nell’apposita locazione del registro SPI_TXCRCR.

Quando si è in procinto di trasferire l'ultimo byte della sequenza dei dati, se i trasferimenti

sono gestiti dalla CPU e non da un dispositivo DMA, il software dovrà settare il bit

CRCNEXT sul registro SPI_CR1 e, in hardware, verrà caricato lo shift-register (registro a

scorrimento) con il codice CRC calcolato fino ad allora e riposto nel registro

SPI_TXCRCR. In questo modo, dunque, il codice CRC viene trasmesso come ultimo byte

(se il formato della frame è su 8-bit) dopo aver trasmesso i dati. In maniera del tutto

analoga avviene la fase di ricezione e controllo del CRC: alla ricezione dell'ultimo byte, se

la ricezione è gestita dalla CPU e non da un dispositivo DMA, sarà necessario settare in

software il bit CRCNEXT. Dopodiché l'hardware controllerà se il codice CRC ricevuto

come ultimo byte è uguale a quello generato in ricezione e riposto nel registro

SPI_RXCRCR.

Eventuali errori scaturiti dal fallimento del controllo, ricezioni o trasferimenti errati del

CRC verranno indicati dall'hardware attraverso il flag CRCERR del registro SPI_SR.

Opzionalmente è possibile abilitare un'interruzione nel caso si manifestino errori settando

il bit ERRIE nel registro SPI_CR2.

21

Interruzioni

L'interfaccia SPI presenta sette eventi interrompenti, ognuno indicato da appositi flag del

registro SPI_SR. Gli eventi interrompenti sono i seguenti:

TXE: il buffer in trasmissione (Tx buffer) è stato svuotato ed è possibile caricare

altri dati;

RXNE: il buffer in ricezione (Rx buffer) è stato caricato con un nuovo dato e può

essere letto;

MODF: master mode fault event. Può accadere quando il dispositivo è impostato

come master e il segnale NSS viene settato a 0 (in modalità di selezione dello slave

in hardware) o quando il bit SSI è settato a 0 (in modalità di selezione dello slave

in software);

OVR: errore di overrun. Può accadere quando sono stati ricevuti nuovi dati e il flag

RXNE è ancora alto, ovvero il buffer in ricezione non è stato ancora letto dal

software mediante il registro SPI_DR;

CRCERR: errore di controllo o ricezione/trasferimento errato del codice CRC;

BSY: busy flag. Si verifica quando il bus SPI è occupato oppure se il buffer Tx

(buffer di trasmissione) non è vuoto;

FRE: frame format error. Errore scatenato da un formato di frame non supportato.

Si noti che i bit UDR e CHSIDE del registro SPI_SR non sono utilizzati dal SPI.

22

2.3 Gestione della trasmissione e della ricezione

Di seguito si mostrano gli eventi caratterizzanti la trasmissione e la ricezione attraverso

SPI.

Trasmissione:

1. Il dato è caricato (in parallelo) dal bus APB al Tx buffer interno;

2. Il bit più significativo del Tx buffer (o quello meno significativo) è posto

sul segnale in uscita;

3. La trasmissione comincia appena il dispositivo slave ha ricevuto la

variazione del segnale SCK;

4. I restanti 7 bits (se la frame è impostata su 8-bit) o 15 bits (se la frame è

impostata su 16-bit) vengono caricati nello shift-register e inviati uno per

volta sul segnale in uscita;

5. Quando i dati dal Tx buffer vengono caricati nello shift-register, viene

settato il flag TXE nel registro SPI_SR ad indicare che il buffer è vuoto ed

è possibile caricare altri bit nel buffer per la trasmissione successiva;

6. Opzionalmente, se settato il bit TXEIE nel registro SPI_CR2, verrà lanciata

la relativa interruzione

Ricezione:

1. Quando il trasferimento è completo, i dati vengono trasferiti dallo shift-

register al Rx buffer;

2. Dopo l'ultimo bit ricevuto, viene settato il flag RXNE nel

registro SPI_SR ad indicare che il buffer in ricezione non è vuoto;

3. Opzionalmente, se settato il bit RXNEIE nel registro SPI_CR2, verrà

lanciata la relativa interruzione;

4. I dati ricevuti possono essere letti dalla periferica con un'operazione di

lettura sul registro SPI_DR. Ciò provocherà, in hardware, il reset del flag

RXNE.

23

Capitolo 3: Comunicazione con il sensore (il Giroscopio)

Un giroscopio è un dispositivo che usa la gravità terrestre per determinare l’orientamento.

Esso è costituito da un disco a forma toroidale, chiamato rotore, libero di ruotare intorno

ad un asse di simmetria che lo attraversa

centralmente e che termina con due punte che

fungono da perni di rotazione. Tali perni sono

inseriti in due fori presenti in un giunto

cardanico[5]. Tramite un sistema di giunti

cardanici, vengono collegati all’asse di rotazione

3 anelli metallici, disposti perpendicolarmente tra

loro. Tali giunti permettono al giroscopio di

effettuare qualsiasi movimento, mantenendo però

fisso il baricentro.

Il principio su cui si basa il funzionamento di un giroscopio è quello secondo il quale, in

assenza di momenti di forze esterne, il vettore momento angolare[6] si conserva[7] e ciò

comporta che l’orientamento nello spazio dell’asse di rotazione rimanga invariato. Tale

comportamento prende nome di inerzia giroscopica.

Se il dispositivo è messo in rapida rotazione con una cordicella, avvolta lungo l’asse di

rotazione, si osserva che tale asse mantiene invariata la direzione per la notevole inerzia

5 Il giunto cardanico o giunto di Cardano è un quadrilatero articolato spaziale. Esso permette di trasmettere il moto tra

due assi in rotazione i cui prolungamenti sono incidenti in un punto. 6 Grandezza di tipo vettoriale, legata alle rotazioni spaziali. 7 Principio fisico che afferma che il momento angolare è costante nel tempo se è nullo il momento delle forze esterne

che agiscono su esso.

24

del giroscopio. Inoltre, se si sollecita un giroscopio in rotazione con una forza, il suo asse

non si muove nella direzione della forza, ma tende a muoversi in una direzione ad essa

perpendicolare.

Per tali motivi, il giroscopio è utilizzato per misurare e mantenere l’orientamento.

Applicazioni tecnologiche del giroscopio si riscontrano nelle bussole giroscopiche

(girobussole) presenti a bordo di aerei o di navi, attraverso le quali si riescono a

stabilizzare i mezzi sui quali si trovano quando questi cambiano direzione. Sono alla base

inoltre dei modellini radiocomandati (ad esempio droni), in cui prevedono l’uso di un

giroscopio montato nella ruota motrice, così da poter mantenere l’equilibrio. Inoltre è

spesso presente negli smartphone, i quali sfruttano la sua capacità di captare ogni minimo

movimento del dispositivo per svariate applicazioni (sicurezza, giochi, etc…).

I microcontrollori della famiglia STM32F4xx, prevedono un sensore interno di giroscopio

digitale, capace di fornire le misurazioni delle rotazioni rispetto all’asse x, y e z. La

comunicazione tra il microcontrollore del SoC con tale sensore viene effettuata attraverso

il protocollo SPI.

3.1 Attivazione PIN e settaggio della modalità

Si è detto che i microcontrollori STM32F4xx prevedono 3 bus SPI: SPI1, SPI2, SPI3.

Supponiamo da ora in poi di utilizzare SPI1.

In generale SPI necessita la configurazione di 4 PIN, uno per ogni canale (SCK, MISO,

MOSI, NSS). Nel caso specifico in cui la comunicazione deve avvenire tra il

microcontrollore e il sensore di giroscopio, si setta come master il microcontrollore

stesso, mentre si setta come slave il sensore. La comunicazione tra microcontrollore e

sensore avverrà attraverso il PIN PE3, settato in modalità di output. Tale PIN fungerà da

NSS: infatti settandolo a 0 si abiliterà la trasmissione (logica 0-attiva), settandolo a 1 si

disabiliterà.

Inoltre, è necessario settare i PIN di SPI1 così da avere un canale MISO, un canale MOSI

e un canale SCK.

25

In particolare è necessario settare i PIN PA5, PA6, PA7 nella modalità alternativa AF05,

così come mostrato nella seguente tabella:

Figura 3.1

3.2 Trasmissione tra SPI1 e sensore di Giroscopio

La trasmissione tra SPI1 e Giroscopio funziona nel seguente modo:

1- Abilito il canale di comunicazione attraverso il pin P3 per avviare la trasmissione;

2- SPI1 aspetta che possa mandare la richiesta. Invia quindi la richiesta del registro del

Giroscopio da cui vuole ricevere i dati;

3- Il giroscopio invia un messaggio di conferma;

4- SPI1 riceve tale messaggio e risponde con un altro messaggio di conferma;

5- Il giroscopio manda il dato effettivo;

6- SPI1 riceve il dato, il quale viene salvato in un’apposita variabile;

7- Si termina la comunicazione bloccando il canale di comunicazione.

Tale processo deve essere effettuato due volte per ogni asse. Il sensore del giroscopio,

infatti, memorizza ogni asse in due registri: ad esempio la rotazione sull’asse x è

memorizzata nei registri OUT_X_L e OUT_X_H. Questo implica che per ottenere i valori

degli assi x, y e z sarà necessario effettuare i passi da 1 a 7 per sei volte.

26

I registri a cui accedere per ottenere i valori degli assi sono mostrati nella seguente tabella:

Figura 3.2

Si noti inoltre che la modalità con cui si deve accedere ai registri deve essere in lettura; per

ottenere ciò è necessario effettuare una or tra il registro a cui si accedere e il valore

esadecimale 0x80.

27

Capitolo 4: Esempio di utilizzo del protocollo SPI e

comunicazione con il sensore sul microcontrollore STM32F4xx

Di seguito è mostrato il codice sorgente riguardante la programmazione del

microcontrollore STM32F4xx con il quale si utilizza il protocollo SPI per ottenere i valori

degli assi di rotazione x, y e z, attraverso la comunicazione con il sensore del giroscopio.

#include "stm32f4xx.h"

short int data;

short int cont = 8;

short x;

short y;

short z;

#define N 1000

#define CS_LO (uint16_t) 0x8

//Definizione abilitazioni

#define GPIOACKEN (uint32_t) 0x1

#define GPIOECKEN (uint32_t) (1<<4)

#define SPI1CKEN (uint32_t) (1<<12)

// Definizione porte GPIOA

#define PA7_AF (uint32_t) (1<<15)

#define PA6_AF (uint32_t) (1<<13)

#define PA5_AF (uint32_t) (1<<11)

28

#define PA5_SCK (uint32_t) (5<<20)

#define PA6_MOSI (uint32_t) (5<<24)

#define PA7_MISO (uint32_t) (5<<28)

#define PA5_50MHZ (uint32_t) (1<<15)

#define PA6_50MHZ (uint32_t) (1<<13)

#define PA7_50MHZ (uint32_t) (1<<11)

#define PA5_PD (uint32_t) (1<<15)

#define PA6_PD (uint32_t) (1<<13)

#define PA7_PD (uint32_t) (1<<11)

// Definizione porte GPIOE

#define PE3_DO (uint32_t) (1<<6)

int main (void){

// Abilitazione periferiche

RCC->AHB1ENR |= (GPIOACKEN|GPIOECKEN); //attiva porta A e porta E

RCC->APB2RSTR |= SPI1CKEN; //il registro APB2RSTR è un registro di

reset. Si setta a 1 il bit di SPI1 per resettarlo

RCC->APB2RSTR &= !((uint32_t)SPI1CKEN); //abbassa il bit dell'SPI1 a 0 così

non avverrà più il reset

RCC->APB2ENR |= SPI1CKEN; //attiva l'ISP1

// Configurazione GPIOA

GPIOA->MODER |= (PA5_AF|PA6_AF|PA7_AF); //setta i PIN PA5 PA6 PA7 in

modalità alternata

GPIOA->AFR[0] |= (PA5_SCK|PA6_MOSI|PA7_MISO); //setta la configurazione

delle funzioni alternate. AFR[0] corrisponde al registro AFRL. Setta per ogni PIN i

corrispondenti bit a 0101, impostando la configurazione AF05. Importando la

configurazione AF05 per ogni PIN si imposta la modalità da usare sull'SPI, come si

può verificare dal DataSheet

GPIOA->OSPEEDR |= (PA5_50MHZ|PA6_50MHZ|PA7_50MHZ); //setta la

velocità di ogni PIN a 50MH

29

GPIOA->PUPDR |= (PA5_PD|PA6_PD|PA7_PD); //setta i PIN in Pull-

Down

// Configurazione GPIOE

GPIOE->MODER |= PE3_DO; //seleziona il PIN PE3 come

output

// Configurazione SPI1

SPI1->CR1 |=1<<9; //SSM=1; si abilita la selezione dello slave via

software

SPI1->CR1 |=1<<8; //setta a 1 il bit SSI (se si imposta SSM=1, SSI deve

essere settato a 1)

SPI1->CR1 |= 0x18; //si imposta il baud rate a 1/16 (più è alto il baud rate

più velocemente riceve/trasmette)

SPI1->CR1 |=1<<2; //si abilita il bit MSTR, in pratica si imposta il

microcontrollore in modalità master

SPI1->CR1 |= 1<<6; //SPI attivo

while(1){

//lettura di X

GPIOE->ODR &= !(CS_LO); // setta a 0 il CH SELECT

while(((SPI1->SR)&0x2)==0); //attende che il buffer di

trasmissione sia vuoto

SPI1->DR = (uint16_t) (0x80|0x28); //"punta" il registro

OUT_X_L del giroscopio in modalità lettura;

while(((SPI1->SR)&0x1)==0); //attende che il buffer di

ricezione sia vuoto

data = SPI1->DR; //legge il dato ricevuto. Il dato letto non ha

rilevanza, ma è necessario eseguire tale istruzione altrimenti il buffer di

ricezione non si libera

while(((SPI1->SR)&0x2)==0); //attende che il buffer di

trasmissione sia vuoto

30

SPI1->DR = (uint16_t) 0x1; //invia un dummy

while(((SPI1->SR)&0x1)==0); //attende che il buffer di ricezione sia

vuoto

data = SPI1->DR; //riceve il valore X_L

GPIOE->ODR |= CS_LO; //setta a 1 il CH SELECT

x =( uint16_t)data; //copia il dato letto da X_L sui bit da 0

a 7 della variabile x

GPIOE->ODR &= !(CS_LO);

while(((SPI1->SR)&0x2)==0);

SPI1->DR = (uint16_t) (0x80|0x29); //"punta" il registro

OUT_X_H del giroscopio in modalità lettura;

while(((SPI1->SR)&0x1)==0);

data = SPI1->DR;

while(((SPI1->SR)&0x2)==0);

SPI1->DR = (uint16_t) 0x1;

while(((SPI1->SR)&0x1)==0);

data = SPI1->DR; //riceve il valore X_H

GPIOE->ODR |= CS_LO;

x|=(uint16_t)data<<8; //copia il dato letto da X_H sui bit da 8 a 15

della variabile x

//lettura di Y

GPIOE->ODR &= !(CS_LO);

while(((SPI1->SR)&0x2)==0);

SPI1->DR = (uint16_t) (0x80|0x2A); //"punta" il registro

OUT_Y_L del giroscopio in modalità lettura;

while(((SPI1->SR)&0x1)==0);

31

data = SPI1->DR;

while(((SPI1->SR)&0x2)==0);

SPI1->DR = (uint16_t) 0x1;

while(((SPI1->SR)&0x1)==0);

data = SPI1->DR; //riceve il valore Y_L

GPIOE->ODR |= CS_LO;

y=(uint16_t)data;

GPIOE->ODR &= !(CS_LO);

while(((SPI1->SR)&0x2)==0);

SPI1->DR = (uint16_t) (0x80|0x2B); //"punta" il registro

OUT_Y_H del giroscopio in modalità lettura;

while(((SPI1->SR)&0x1)==0);

data = SPI1->DR;

while(((SPI1->SR)&0x2)==0);

SPI1->DR = (uint16_t) 0x1;

while(((SPI1->SR)&0x1)==0);

data = SPI1->DR; //riceve il valore Y_H

GPIOE->ODR |= CS_LO;

y|=(uint16_t)data<<8;

//lettura di Z

GPIOE->ODR &= !(CS_LO);

while(((SPI1->SR)&0x2)==0);

SPI1->DR = (uint16_t) (0x80|0x2C); //"punta" il registro OUT_Z_L

del giroscopio in modalità lettura;

while(((SPI1->SR)&0x1)==0);

data = SPI1->DR;

32

while(((SPI1->SR)&0x2)==0);

SPI1->DR = (uint16_t) 0x1;

while(((SPI1->SR)&0x1)==0);

data = SPI1->DR; //riceve il valore Z_L

GPIOE->ODR |= CS_LO;

z=(uint16_t)data;

GPIOE->ODR &= !(CS_LO);

while(((SPI1->SR)&0x2)==0);

SPI1->DR = (uint16_t) (0x80|0x2D); //"punta" il registro OUT_Z_H

del giroscopio in modalità lettura;

while(((SPI1->SR)&0x1)==0);

data = SPI1->DR;

while(((SPI1->SR)&0x2)==0);

SPI1->DR = (uint16_t) 0x1;

while(((SPI1->SR)&0x1)==0);

data = SPI1->DR; //riceve il valore Z_H

GPIOE->ODR |= CS_LO;

z|=(uint16_t)data<<8;

}

}

33

Bibliografia

[1] STMicroelectronics group, RM0368 Reference manual, 835, 2014

[2] STMicroelectronics group, PM0214 Programming manual, 245, 2014

[3] STMicroelectronics group, MEMS motion sensor: three-axis digital output

gyroscope, 44, 2012