#include "stm32f30x.h"
int config[3]={0x47,0x00,0x00};
int configData[3]={0};
int accData[6]={0};
int x=0;
int y=0;
int z=0;
void main()
{
RCC->AHBENR |= RCC_AHBENR_GPIOBEN; //Abilito GPIOB
GPIOB->MODER |= GPIO_MODER_MODER6_1|GPIO_MODER_MODER7_1; //PB6 ==I2C1_SCL e PB7==I2C1_SDA in Alternate mode p. 41 - STM32F3Datasheet.pdf
GPIOB->AFR[0] |= 4 <<24 |4<<28; //Associo l'alternate function AF4 a PA6 e PA7, perchè p. 44 - STM32F3Datasheet.pdf, p. 148 - STM32F3RefMan.pdf
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; //Abilito segnale di clock per I2C
//Configurazione TIMNGR Table 84. Examples of timings settings for fI2CCLK = 8 MHz - 100kz p. 684 - STM32F3RefMan.pdf
I2C1->TIMINGR |= 0x10420F13;
I2C1->CR1 |= I2C_CR1_PE; //Abilitazione periferica I2C
/*[ Master in Trasmissione (scrittura)] - Configurazione dei registri dell'Accelerometro*/
/*In particolare voglio configurare il seguenti registri:
[+] CTRL_REG1_A (20h) == 0b01000111 == 0x47 --> ODR a 50Hz Normal Mode
[+] CTRL_REG2_A (21h) == 0b00000000 == 0x00 --> Nessun filtro
[+] CTRL_REG3_A (22h) == 0b00000000 == 0x00 --> Nessuna interruzione
NOTA: Per non ripetere sempre le stesse istruzioni attiviamo l'autoincrement:
Basta prendere l'indirizzo di partenza 0x20 nel nostro caso e aggiungere un uno nel MSB
0x20 == 00100000;
0x80 == 10000000;
faccio 0x20|0x80 = 0xA0
*/
while((I2C1->ISR & I2C_ISR_BUSY)==I2C_ISR_BUSY); //Mi assicuro che la periferica non sia nello stato Busy
I2C1->CR2 &=~I2C_CR2_NBYTES; //Pulisco il sottoregistro NBYTES di CR2 potrebbe essere stato sporcato da operazioni precedenti
I2C1->CR2 |= 4 << 16; //Specifico il numero di byte da trasferire compreso il SUBADD (indirizzo del sottoregistro) in questo caso 4
I2C1->CR2 |= (uint8_t)0x19 <<1; //Specifico l'indirizzo dello Slave/Accelerometro 0b0011001==0x19 <<1 perchè il bit 0 è don't care
I2C1->CR2 &=~I2C_CR2_RD_WRN; //Specifico di voler effettuare un'operazione di scrittura (WRN==0)
I2C1->CR2 |= I2C_CR2_START; //Do il comando di Start
while((I2C1->ISR & I2C_ISR_TXE)!=I2C_ISR_TXE); //Mi assicuro che il Transmit data register sia vuoto
I2C1->TXDR = (0x20|0x80); //Trasmetto l'indirizzo del sottoregistro (SUBADD) con autoincremento
//Trasmetto i 3 Dati
for(int j=0;j<3;j++)
{
while((I2C1->ISR & I2C_ISR_TXE)!= I2C_ISR_TXE); //Mi assicuro che il Transmit data register sia vuoto
I2C1->TXDR = config[j]; //Trasmetto il dato
}
while(( I2C1->ISR & I2C_ISR_TC)!=I2C_ISR_TC); //Attendo il Transfer Complete
I2C1->CR2 |= I2C_CR2_STOP; //Do lo Stop
while((I2C1->ISR & I2C_ISR_STOPF)!=I2C_ISR_STOPF); //Attendo lo Stop flag
I2C1->ICR |= I2C_ICR_STOPCF; //Pulisco il Stop flag
/* Master in ricezione(lettura)] Voglio leggere le componenti dell'accelerazione lungo gli assi.
Devo leggere i seguenti valori dai seguenti sottoregistri. (Versione Con STOP START (no restart))
[+] OUT_X_L_A (28h), OUT_X_H_A (29h)
[+] OUT_Y_L_A (2Ah), OUT_Y_H_A (2Bh)
[+] OUT_Z_L_A (2Ch), OUT_Z_H_A (2Dh)*/
while(1)//Aggiorno continuamente i valori
{
while((I2C1->ISR & I2C_ISR_BUSY)==I2C_ISR_BUSY); //Mi assicuro che la periferica non sia nello stato Busy
I2C1->CR2 &=~I2C_CR2_NBYTES; //Pulisco il sottoregistro NBYTES di CR2 potrebbe essere stato sporcato da operazioni precedenti
I2C1->CR2 |= 1 <<16; //Specifico il numero di byte da trasferire compreso il SUBADD (indirizzo del sottoregistro) in questo caso 1
I2C1->CR2 |= (0x19 <<1); //Specifico l'indirizzo dello Slave/Accelerometro 0b0011001==0x19 <<1 perchè il bit 0 è don't care
I2C1->CR2 &=~I2C_CR2_RD_WRN; //Specifico di voler effettuare un'operazione di scrittura (WRN==0)
I2C1->CR2 |= I2C_CR2_START; //Do il comando di Start
while((I2C1->ISR & I2C_ISR_TXE)!=I2C_ISR_TXE); //Mi assicuro che il Transmit data register sia vuoto
I2C1->TXDR = (0x28|0x80); //Trasmetto l'indirizzo del sottoregistro (SUBADD) da cui voglio leggere con autoincremento
while(( I2C1->ISR & I2C_ISR_TC)!=I2C_ISR_TC); //Attendo direttamente il Transfer Complete perchè sto inviando un solo byte
I2C1->CR2 |= I2C_CR2_STOP; //Do lo Stop
while((I2C1->ISR & I2C_ISR_STOPF)!=I2C_ISR_STOPF); //Attendo lo Stop flag
I2C1->ICR |= I2C_ICR_STOPCF; //Pulisco il Stop flag
I2C1->CR2 |= (0x19 <<1); //Rispecifico l'indirizzo dello Slave/Accelerometro 0b0011001==0x19 <<1 perchè il bit 0 è don't care
I2C1->CR2 |=I2C_CR2_RD_WRN; //Specifico di voler effettuare un'operazione di lettura (WRN==1)
I2C1->CR2 &=~I2C_CR2_NBYTES; //Pulisco il sottoregistro NBYTES di CR2 potrebbe essere stato sporcato da operazioni precedenti
I2C1->CR2 |= 6 << 16; //Specifico il numero di byte da leggere caso 6 perchè voglio leggere i 6 sottoregistri dell'accelerometro
I2C1->CR2 |= I2C_CR2_START; //Do il comando di Start
while((I2C1->ISR & I2C_ISR_TXE)!=I2C_ISR_TXE); //Mi assicuro che il Transmit data register sia vuoto
//Leggo i 6 dati
for(int j=0;j<6;j++)
{
while(( I2C1->ISR & I2C_ISR_RXNE)!=I2C_ISR_RXNE); //Mi assicuro che il Receive data register non sia vuoto (sia pieno)
accData[j]=I2C1->RXDR; //Prelevo il dato
}
I2C1->CR2 |= I2C_CR2_STOP; //Do lo Stop
while((I2C1->ISR & I2C_ISR_STOPF)!=I2C_ISR_STOPF); //Attendo lo Stop flag
I2C1->ICR |= I2C_ICR_STOPCF; //Pulisco il Stop flag
/*Dobbiamo convertire il dato ricevuto nell'informazione accelerazione
Prima la parte alta e poi la parte bassa.
1)Facciamo prima uno shift a sx della parte alta (es. OUT_X_H_A) di 8 facendo un cast a 16 bit (uint16_t) per non perdere bit
2)Sommiamo la seconda componente parte bassa (es. OUT_X_L_A)
3)Il risulato che ottengo lo divido per 16 perchè in realta' di questi 16 bit solo 12 me ne servono e sono allineati a sx. Dividendo per 16 sposto di 4 a sinistra (potrei mettere lo shift di 4 .. stessa cosa)
4)In realtà questo non e' unsigned perchè puo' andare sia per positivi che per negativi (operazione che viene gestita automaticamente)
5)Se voglio guadagnere un po di risoluzione faccio un cast a float*/
x=((int16_t)((uint16_t)accData[1]<<8)+accData[0])/16;
y=((int16_t)((uint16_t)accData[3]<<8)+accData[2])/16;
z=((int16_t)((uint16_t)accData[5]<<8)+accData[4])/16;
}
//return 0;
}