-

hey viewer, we're moving!

We are currently transitioning to a new web system, so we are not updating this wikisite anymore.

The public part of the new web system is available at http://www.ira.disco.unimib.it


INFIND2011/12 Digital compass and accelerometer board

From Irawiki

Jump to: navigation, search

Students working on this project:

L'obiettivo del progetto è quello di configurare e leggere i dati dall'integrato : LSM303DHLC interfacciando il microcontrollore con il sensore digitale utilizzando il bus I2C. E' prevista anche una lettura dei gradi del Nord magnetico.

Nel nostro componente abbiamo un accelerometro e un magnetometro a 3 assi

Contents

Relazione

Sensori/attuatori utilizzati

Accelerometro:

Un accelerometro è uno strumento di misura in grado di rilevare e/o misurare l'accelerazione. Nella maggior parte degli accelerometri, il principio di funzionamento è il medesimo: si basa sulla rilevazione dell'inerzia di una massa quando viene sottoposta ad un'accelerazione. La massa viene sospesa ad un elemento elastico, mentre un qualche tipo di sensore ne rileva lo spostamento rispetto alla struttura fissa del dispositivo. In presenza di un'accelerazione, la massa (che è dotata di una propria inerzia) si sposta dalla propria posizione di riposo in modo proporzionale all'accelerazione rilevata. Il sensore trasforma questo spostamento in un segnale elettrico acquisibile dai moderni sistemi di misura.

Magnetometro:

Le bussole funzionano mediante il rilevamento dei campi magnetici prodotti dalla nucleo al centro della terra. La forza del campo magnetico terrestre è di circa 0,5-0,6 gauss e ha una componente parallela alla superficie della terra che punta sempre verso il polo nord magnetico. Le bussole tradizionali utilizzano questi campi per far ruotare un'asta di metallo ferroso, in un piccolo contenitore. I campi magnetici allineano l'asta di metallo lungo l'asse che punta al nord magnetico. I magnetometri comunque non ci forniscono una direzione , ma un modo per misurare il magnetismo con il quale possiamo andare a calcolare una direzione.


Ma come possiamo calcolare l'angolo del compasso? Di seguito viene riportata la figura e la formula per calcolare ciò che stiamo cercando:


2n1ccna.png

In questo determinato caso il Pitch e il Roll sono a 0 quindi avremo la seguente formula:

34qr7np.png

Questo perchè supponiamo che la bussola sia tenuta orizzontalmente. Di fatti se si dovesse tenere una bussola ad angolo retto essa non funziona più, e se si cercasse di inclinarla di 45° la lettura sarà più imprecisa quanto più la bussola è inclinata. Questo problema avviene perchè il puntatore della bussola non consente la rotazione su più assi. In questo caso dovremmo integrare anche la misurazione dell'asse Z in modo da ottenere un risultato coerente anche avendo una diversa inclinazione. Per far ciò utilizzeremo anche l'accelerometro a tre assi per ottenere dei risultati corretti.


30tlaie.jpg

Per ottenere un risultato corretto andremo ad utilizzare le seguenti formule:

5cbp93.png

dove Xm Ym e Zm sono i valori degli assi del magnetometro.


Periferiche utilizzate

I2C, Inter Integrated Circuit, è un sistema di comunicazione seriale bifilare utilizzato tra circuiti integrati. Il protocollo hardware del I2C richiede due linee seriali di comunicazione: SDA (serial data line) per i dati, che corrisponde al pin3 SCL (serial clock line) per il clock, che corrispionde al pin2 Per quanto riguarda l'alimentazione il pin è il 14. Per quest'ultima bisogna sapere che essa non è fissa ma varia da 2,5V ad un massimo di 3,8V.

Per capire meglio come devono essere collegati i seguenti piedini guardare la seguente immagine:

anc180.png

Nel nostro caso:

SCL = filo bianco collegato al pin PB6

SDA = filo giallo collegato al pin PB7

Alimentazione= filo rosso collegato alla 3V3

Nero= massa GND


I2C è composto da un master e uno slave, nel nostro caso LSM303DLHC è un I2C slave, ovvero è presente una porta I2C configurata per essere utilizzata in modalità "slave". Questo comporta che noi con la scheda stm32f10xxx dobbiamo configurarci come "master" per poter comunicare.

Sulla nostra basetta stm32f10x sono presenti due I2C ovvero:

I2C1

I2C2

collegati sul bus APB1, quello che andremo ad utilizzare è I2C1 (n.b. La scelta di utilizzare soltanto I2C1 e non il 2 è stata una scelta nostra.)

Il DMA (Direct Memory Access, "accesso diretto alla memoria") è un meccanismo che permette ad alcuni sottosistemi hardware di un computer (periferiche) di accedere direttamente alla memoria di sistema per scambiarsi dati, oppure leggere o scrivere, senza chiamare in causa la CPU per ogni byte trasferito tramite il meccanismo usuale dell'interrupt e la successiva richiesta di operazione desiderata, ma generando un singolo interrupt per blocco trasferito (rif. http://it.wikipedia.org/wiki/Direct_Memory_Access)

Nel nostro caso il DMA (in particolare il DMA1 canale 4) sarà utilizzato in combinazione con la USART per inviare un buffer di 16bit alla volta.

Oltre queste due periferiche utilizziamo anche la USART (in particolare la USART1) per inviare i dati dalla board al computer.

Nel capitolo sucessivo si spiegherà nel dettaglio la configurazione, la lettura e la scrittura utilizzando le periferiche I2C1,USART1 e DMA.

Struttura del firmware

Per quanto riguarda il codice abbiamo deciso di strutturarlo in 3 file diversi ovvero il LSM303DLHC.h, LSM303DLHC.c, main.c Di seguito descriveremo il codice contenuto nei file sopra elencati.


LSM303DLHC.h

Il seguente file contiene:

le librerie che bisognerà utilizzare:

stm32f10x_i2c.h

stm32f10x.h

la definizione degli indirizzi del sensore:

  1. define LSM303DLHC_Accelerometer_Write_Address 0x32
  2. define LSM303DLHC_Accelerometer_Read_Address 0x33
  3. define LSM303DLHC_Magnetometer_Write_Address 0x3C
  4. define LSM303DLHC_Magnetometer_Read_Address 0x3D
  5. define LSM303DLHC_Accelerometer_Slave_Address 0x19 //25 in decimale
  6. define LSM303DLHC_CTRL_REG1_A_Address 0x20
  7. define LSM303DLHC_CTRL_REG4_A_Address 0x23
  8. define LSM303DLHC_OUT_X_L_A_Address 0x28
  9. define LSM303DLHC_OUT_X_H_A_Address 0x29
  10. define LSM303DLHC_OUT_Y_L_A_Address 0x2A
  11. define LSM303DLHC_OUT_Y_H_A_Address 0x2B
  12. define LSM303DLHC_OUT_Z_L_A_Address 0x2C
  13. define LSM303DLHC_OUT_Z_H_A_Address 0x2D
  14. define LSM303DLHC_CRA_REG_M_Address 0x00
  15. define LSM303DLHC_CRB_REG_M_Address 0x01
  16. define LSM303DLHC_MR_REG_M_Address 0x02
  17. define LSM303DLHC_OUT_X_L_M_Address 0x04
  18. define LSM303DLHC_OUT_X_H_M_Address 0x03
  19. define LSM303DLHC_OUT_Y_L_M_Address 0x08
  20. define LSM303DLHC_OUT_Y_H_M_Address 0x07
  21. define LSM303DLHC_OUT_Z_L_M_Address 0x06
  22. define LSM303DLHC_OUT_Z_H_M_Address 0x05

Accelerometro:

2ufgig4.png

(tabella 14 pagina 20 DM00027543.pdf)

Magnetometro:

mueu4n.png

(tabella 15 pagina 21 DM00027543.pdf)

Indirizzi di X Y Z e gli altri elencati:

2nrd4zk.png

(tabella 17 pagina 22 DM00027543.pdf)


t9k1w6.png

(tabella 17 pagina 23 DM00027543.pdf)

definizione prototipi delle funzioni:

  1. configurazione iniziale I2C
  2. Write e Read dell'I2C
  3. Configurazione Accelerometro e Magnetometo
  4. Write e Read sia per l'accelerometro sia per il magnetometro


(le funzioni verranno descritte meglio nel capitolo LSM303DLHC.c)



LSM303DLHC.C

Il seguente file contine la definizione di tutti i metodi elencati nel capito precedentemente. Ora spiegheremo ognuno dei metodi elencati per capirne la funzionalità.

void LSM303DLHC_I2C_InitialConfig(I2C_TypeDef* I2CPort)

Nel metodo in questione troveremo come configurare l'I2C. Come prima cosa andiamo a settare la velocità di clock a 100KHz nella modalità Normal Mode, setteremo SMBus a 0 per utilizzare la I2C pura come interessa a noi dopodichè setteremo il DutyCycle a 2 ovvero il tempo in cui un segnale digitale rimane a livello alto rispetto al tempo totale, abiliteremo l'acknowledge e setteremo l'ack a 7bit come richiesto dal LSM303DLHC ed infine abilitiamo l'I2C1.

uint8_t LSM303DLHC_I2C_Read(I2C_TypeDef* I2CPort,u8 slaveAddressRead,u8 slaveAddressWrite, u8 readAddress)

Per quanto riguarda questo metodo la seguente tabella qui riportata descrive in dettaglio i passaggi che vengono eseguiti:

2sb9zqw.png

(tabella 13 pagina 19 DM00027543.pdf)

  1. Mando lo Start al sensore
  2. Aspetto l'evento di selezione della modalità master
  3. Invio l'istruzione per dire che voglio scrivere
  4. Aspetto l'evento di selezione della modalità di trasmissione per il master
  5. Invio l'indirizzo del sensore interno che voglio leggere
  6. Aspetto che arrivi l'evento che mi dica che ha trasmesso l'indirizzo
  7. Genero la condizione di start per la seconda volta
  8. Aspetto nuovamente l'evento di selezione della modalità master
  9. Invio l'istruzione per dire che voglio leggere
  10. Aspetto l'evento di selezione della modalità di ricezione per il master
  11. Disabilito l'Acknowledgement
  12. Aspetto che i dati siano pronti (finché ci sono)
  13. Leggo il byte ricevuto
  14. Mando un segnale di stop
  15. Riabilito Acknowledgement per leggere altri dati in futuro
  16. Ritorno il dato letto


void LSM303DLHC_I2C_Write(I2C_TypeDef* I2CPort,u8 slaveAddress, u8 writeAddress,u8 dataWrite)

Per quanto riguarda il metodo Write possiamo osservare la tabella qui sotto riportata per capirne meglio il funzionamento:


f1e109.png

(tabella 11 pagina 19 DM00027543.pdf)

  1. Mando lo Start al sensore
  2. Aspetto l'evento di selezione della modalità master
  3. Invio l'istruzione per dire che voglio scrivere
  4. Aspetto l'evento di selezione della modalità di trasmissione per il master
  5. Invio l'indirizzo del sensore interno che voglio scrivere
  6. Aspetto che arrivi l'evento che mi dica che ha trasmesso l'indirizzo
  7. Invio i dati che voglio scrivere nel registro del sensore
  8. Aspetto che il dato sia stato trasmesso
  9. Mando il segnale di stop


void LSM303DLHC_I2C_Accelerometer_Config(I2C_TypeDef* I2CPort)

Configurazione dei registri dell'Accelerometro. Come elencati nel capitolo precedente vado a settare i seguenti registri: CTRL_REG1_A=0x47; //ODR set to Normal - 50Hz. Per abilitare X, Y e Z CTRL_REG4_A=0x48; //per settare l'High Resolution (per avere meno scostamento nella lettura dei valori)

dopodichè richiamo il metodo write per settare i due registri:

LSM303DLHC_I2C_Write(I2CPort,LSM303DLHC_Accelerometer_Read_Address,LSM303DLHC_CTRL_REG1_A_Address,CTRL_REG1_A);

LSM303DLHC_I2C_Write(I2CPort,LSM303DLHC_Accelerometer_Read_Address,LSM303DLHC_CTRL_REG4_A_Address,CTRL_REG4_A);

void LSM303DLHC_I2C_Magnetometer_Config(I2C_TypeDef* I2CPort)

configurazione dei registri del Magnetometro. CRA_REG_M=0x90, MR_REG_M=0x00; CRB_REG_M=0xE0; ±8.1 Sensor input field range [Gauss] 230 Gain X, Y and Z [LSB/Gauss] 205 Gain Z [LSB/Gauss]

dopodichè richiamo il metodo write per settare i due registri:

LSM303DLHC_I2C_Write(I2CPort,LSM303DLHC_Magnetometer_Read_Address,LSM303DLHC_CRA_REG_M_Address,CRA_REG_M);

LSM303DLHC_I2C_Write(I2CPort,LSM303DLHC_Magnetometer_Read_Address,LSM303DLHC_CRB_REG_M_Address,CRB_REG_M);

LSM303DLHC_I2C_Write(I2CPort,LSM303DLHC_Magnetometer_Read_Address,LSM303DLHC_MR_REG_M_Address,MR_REG_M);

Tutti gli altri metodi elencati precedentementi servono per leggere il low e l'height di ogni asse ovvero X Y Z


Main.c

Ora descriviamo in dettaglio il file main con le relative chiamate.

Come prima cosa attiviamo i bus e le periferiche che ci serviranno:

  1. USART1, GPIOA, GPIOB e AFIO clock.
  2. Attiviamo il clock I2C1 richiesto dal progetto
  3. Attiviamo il clock del DMA1
  4. Settiamo i valori massimi e minimi dell'accelerometro e del magnetometro
  5. Richiamiamo la funzione I2C_DeInit presa dalla libreria ufficiale per deinizializzare tutto ciò che riguarda la I2C1 e tutti i registri.
  6. Configurazione iniziale del I2C
  7. Abilitiamo il pb6 (I2C1_SCL) e pb7(I2C1_SDA) nella modalità"Alternate function output push-pull"
  8. Invochiamo i metodi per la configurazione dell'accelerometro e magnetometro
  9. Invio del delay
  10. Creiamo un buffer di 16 visto che i dati che andremo ad ottenere sono 2 per ogni asse il quale avrà a sua volta il valore di low e l'height come descritto nel capitolo precedente ed i due valori dei gradi.
  11. La DMA che utilizziamo è sul canale numero 4 quindi la configuriamo di conseguenza
  12. Diamo l'indirizzo per trasmettere con usart1
  13. Diamo l'indirizzo del buffer dove trasmettere i dati al DMA.
  14. Settiamo quanti dati trasferiremo (16) al DMA
  15. Resettiamo tutti i registri USART1 CR1, CR2, CR3.
  16. Attiviamo USART1
  17. Configuriamo la lunghezza della parola a 8bit, ovvero impostiamo l'USART a 8 bit e non di più, i dati poi verranno assemblati dal client
  18. Settiamo 1 bit di stop quando finisce la trasmissione
  19. Abilitiamo il TX DMA request, permette di utilizzare le richeste del DMA per l' USART
  20. Configuriamo il registro bound rate a 115200bps
  21. Abilitiamo USART RX in ricezione senza utilizzo di DMA
  22. Aspettiamo il carattere
  23. Una volta arrivato leggeremo il dato per far capire che il client è pronto
  24. Da qui inizieremo a fare le varie letture memorizzandole nel buffer (12 letture) chiamando le relative funzioni (*)
  25. Aggiusto i dati dell'accelerometro secondo la notazione 12-bit left-justified big endian (**)
  26. Aggiusto i dati del Magnetometro secondo la notazione 12-bit right-justified little endian
  27. Normalizzo i dati utilizzando i massimi ed i minimi, i risultati vanno da -1 a +1.
  28. Calcolo pitch e roll del piano orizzontale
  29. Utilizzo le formule per calcolare l'angolo in base all'inclinazione
  30. Calcolo l'angolo sfruttando l'accelerometro
  31. Calcolo l'angolo considerando pitch e roll uguali a zero
  32. Condizioni per avere valori da 0 a 360 e non da -180 a +180
  33. Inseriamo i valori aggiustati utilizzando le notazioni precedenti nel buffer da inviare
  34. Inseriamo nel buffer i valori dell'angolo e dell'angolo con piano orizzontale nullo
  35. Alla fine della lettura abilitiamo il DMA1 canale 4
  36. Abilito la USART1 TX in trasmissione
  37. I delay servono a noi per vedere i dati se no si aggiornerebbero troppo velocemente
  38. Aspetto che finisca il trasferimento
  39. Una volta finito disabilito il DMA
  40. E come ultima cosa reimposto il numero dei dati da trasferire visto che ogni volta che manda un dato, il contatore decrementa fino ad arrivare a 0.
  41. Riparto dalla lettura dei valori dell'accelerometro e magnetometo.

(*) le letture si fanno combinando due byte utilizzando il seguente modo: (byte1 <<8 | byte2) per l'accelerometro (big endian) (byte2 <<8 | byte1) per il magnetometro (little endian)

(**) per poter far ciò è necessario shiftare di 4 oppure dividere per 16 i dati aggreggati dell'accelerometro.


Protocollo di comunicazione seriale

I dati vengono inviati sulla porta seriale in modalità binaria.

Il protocollo di comunicazione è unidirezionale (trasmissione dalla scheda al computer) e consiste in una continua tramissione di 16bit.

Unica eccezione nel fatto che per cominicare a trasmettere in modalità continua è necessario inviare un carattere casuale da 8bit alla board tramite porta seriale per indicare di essere pronti a ricevere.

I 16bit contengono i seguenti dati concatenati (senza caratteri di separazione): 2 bit Asse X Accelerometro, 2 bit Asse Y Accelerometro, 2 bit Asse Z Accelerometro, 2 bit Asse X Magnetometro, 2 bit Asse Y Magnetometro, 2 bit Asse Z Magnetometro, 2 bit Angolo Normalizzato e 2 bit Angolo non normalizzato.

I 2 bit di ogni valore sono in formato little-endian (cioè il secondo bit è quello più significativo), un metodo per combinare i due bit è eseguire questa operazione: (byte2 * 256) + byte1)).


Prove sperimentali

Per quanto riguarda i valori dell'acceleromento abbiamo preso il sensore e per ogni suo asse X, Y e Z l'abbiamo messo perpendicolare sull'asse terrestre e abbiamo potuto constatare che i valori si avvicinava molto a 980, forza di gravità terrestre.

Per quanto riguarda il magnetometro abbiamo applicato le formule matematiche per poter verificare se il nostre sensore puntasse a Nord e così è stato, i valori che abbiamo ottenuto combaciavano con quelli che ci aspettavamo.

Di seguiti si possono vedere due immagini che mostrano l'interfaccia creata in VisualStudio per poter visualizzare i valori del sensore:


nz6vd.png

2uz54kn.png

I primi valori riportato sono gli assi X, Y e Z dell'accelerometro mentre quelli sotto sono gli assi del magnetometro.

Gli altri due valori

ANorm

ANull

sono i gradi ottenuti sia tenendo conto dei dati forniti dall'acceleromento (ANorm) sia quelli senza tener conto dell'accelerometro (ANull) vedi paragrafo "Sensori/attuatori utilizzati"

Risultati e conclusioni

I risultati ottenuti dal sensore sia per quanto riguarda l'acceleromento sia per il magnetometro sono molto buoni.

Arrivare ad ottenere dei risultati sensati però non è stato così semplice, infatti ci sono stati molti problemi sia per quanto riguarda la configurazione del I2C che per i dati dell'accelerometro e magnetometro con le relative configurazioni left-justified big endian, right-justified little endian.

Ogni volta che viene data l'alimentazione alla board parte in automatico il programma scritto sulla flash, questo causa un problema: se vi erano presenti errori di programmazione questi bloccavano il sensore e di conseguenza la comunicazione con I2C anche nel caso in cui la configurazione fosse stata corretta. Questo comportava una grande difficoltà nel riuscire a configurare correttamente la porta.

Per quanto riguarda l'accelerometro ed il magnetometro il problema principale è la mancanza di informazioni sul numero di bit e sull'allineamento dei dati. Nel caso dell'acceleromentro abbiamo constatato che i bit sono 12 allineati da sinistra ovvero in modalità left-justified mentre nel caso del magnetometro sono sempre 12 bit ma allineati da destra ovvero in modalità right-justified.

Un altro problema è che per quanto riguarda l'accelerometro è possibile configurare se i 2 byte di uscita fossero big endian o little endian invece per il magnetometro la configurazione non è prevista ed è solamente little endian.

Possono sembrare delle cose banali ma complicano notevolmente il lavoro.

Manuale utente

Utilizzare la board per leggere i dati sensoriali è molto semplice, basta avere a disposizione un computer qualsiasi e collegare l'USB che in realtà emulerà la porta seriale.

Per leggere i dati vi sono poi due modalità:

  1. Creare un programma con il proprio linguaggio preferito che legga i dati trasmessi sulla porta seriale emulata in modalità binaria seguendo lo schema descritto nel protocollo e visualizzarli.
  2. Utilizzare il programma allegato scritto in C# che permette di visualizzare i valori dei tre assi dell'accelerometro e magnetometro ed anche i valori dell'angolo normalizzato e non in gradi (il programma è configurato per funzionare sulla porta seriale COM4).

Collegamenti hardware

I collegamenti da fare per far funzionare correttamente la board sono i seguenti:

La porta SCL del sensore collegata al pin PB6 della board, nel nostro caso il filo bianco.

La porta SDA del sensore collegata al pin PB7 della board, nel nostro caso il filo giallo.

La porta di alimentazione collegata al pin 3V3 della board, nel nostro caso il filo rosso.

La massa collegata al pin GND, nel nostro il filo nero.

Di seguito po' di immagini esplicative dei collegamenti:


I collegamenti sulla board:

vxojrs.jpg

262uzb9.jpg


I collegamenti sul sensore

nzmv49.jpg

2118igl.jpg


I collegamenti su board e sensore insieme:

2vjq0bm.jpg

Procedura di accensione

La procedura di accensione è semplicissima: basta collegare la board ad una porta USB qualsiasi (attenzione che il cavo lato board deve essere collegato in USB e non USB1), aspettare per sicurezza qualche secondo ed utilizzare il programma C# messo a disposizione. Il programma all'interno della board si autoavvia appena viene alimentata.

Allegati

Codice sorgente del Firmware

http://irawiki.disco.unimib.it/irawiki/images/b/b5/Stm32_gigi.zip

Codice sorgente di eventuali applicazioni lato PC

http://irawiki.disco.unimib.it/irawiki/images/b/b9/InformaticaIndustrialeTest.zip

Materiale utile

LSM303DLHC manual: http://irawiki.disco.unimib.it/irawiki/images/c/cf/DM00027543.pdf

Using LSM303DLH for a tilt compensated electronic compass: http://irawiki.disco.unimib.it/irawiki/images/a/a0/LSM303DLH-compass-app-note.pdf

Altre informazioni sul sensore: http://www.pololu.com/catalog/product/1250

STM32F103xx reference manual: http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/REFERENCE_MANUAL/CD00171190.pdf

Personal tools