Ten post chciałem poświęcić na programowanie układu LSM6DS3. Jest to trzyosiowy akcelerometr oraz żyroskop. Do komunikacji wykorzystam interfejs I2C.
[Źródło: https://learn.sparkfun.com/tutorials/lsm6ds3-breakout-hookup-guide]
Układ pozwala na pomiar przyśpieszenia oraz prędkości kątowej.
Specyfikacja układu:
- Napięcie zasilania od 1.8V do 3.6V;
- Pobór prądu około 1mA;
- Rozdzielczość: 16 bitów na każdej z osi;
- Zakresy pomiarowe: +/-2g, +/-4g, +/-8g, +/-16g (akcelerometr);
- Zakresy pomiarowe: +/-125, +/-245,+/-500,+/-1000,+/-2000 st/s;
- Wbudowana kolejka Fifo 8 kB;
Programowanie:
Proces programowania należy rozpocząć od interfesu I2C. Poniżej będą znajdowały się pliki .h oraz .c interfejsu I2C.
Cały kod załączony poniżej jest do pobrania pod tym linkiem.
Plik h:
- #ifndef I2C_INIT_H_
- #define I2C_INIT_H_
- #include "main.h"
- void I2CSetTransmissionSpeed(void);
- void I2CStart(void);
- void I2CStop(void);
- void I2C_Send(unsigned char c);
- void I2C_SendByteWitAddress(unsigned char c,unsigned char addr);
- unsigned char I2C_Read(void);
- unsigned char I2C_ReadOneByte(void);
- #endif /* I2C_INIT_H_ */
Plik c:
- #include "i2c_init.h"
- //-------------------------------------------------------------------
- void I2CSetTransmissionSpeed(void)
- {
- /* Set transmission speed */
- TWBR=0x48;
- }
- //-------------------------------------------------------------------
- void I2CStart(void)
- {
- /* Set TWIN flag for 1 to unblock TWI interupt */
- /* Set TWSTA activates generate Master transmission start */
- /* For unblock I2C set TWEN bit */
- TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
- /* Wait until TWINT flag is set */
- while (!(TWCR & (1<<TWINT)));
- }
- //-------------------------------------------------------------------
- void I2CStop(void)
- {
- /*
- * Unblock interrupt
- * set TWSTO bit for generating hardware I2C Stop
- */
- TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
- }
- //-------------------------------------------------------------------
- void I2C_Send(unsigned char c)
- {
- /* Write byte to send to TWDR byte */
- TWDR = c;
- /* unblock interrupt */
- TWCR = (1<<TWINT)|(1<<TWEN);
- /* Wait for data transmitt */
- while (!(TWCR & (1<<TWINT)));
- }
- //-------------------------------------------------------------------
- unsigned char I2C_Read(void)
- {
- /*
- * if read more than 1 data then TWEA need to be 1, else it could be zero,
- * it says to slave device to disconnect from master, read one byte is done
- * in I2C_ReadOneByte function
- */
- TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
- /* wait for end of reading */
- while (!(TWCR & (1<<TWINT)));
- /* read data from register */
- return TWDR;
- }
- //-------------------------------------------------------------------
- void I2C_SendByteWitAddress(unsigned char c,unsigned char addr)
- {
- /* Start transmission */
- I2CStart();
- /* Adress with register to write */
- I2C_Send(addr);
- /* Bajt to write into register */
- I2C_Send(c);
- /* Stop data transmission */
- I2CStop();
- }
- //-------------------------------------------------------------------
- unsigned char I2C_ReadOneByte(void)
- {
- /* read only one byte of data */
- TWCR = (1<<TWINT)|(1<<TWEN);
- while (!(TWCR & (1<<TWINT)));
- return TWDR;
- }
Teraz pliki od układu LSM6DS3:
Plik h.
- #ifndef LSM6DS3_H_
- #define LSM6DS3_H_
- //-----------------------------------------
- #include <stdint.h>
- #include <avr/io.h>
- //-----------------------------------------
- #define LSM6DS3_GYRO_CTRL1_XL 0x10
- #define LSM6DS3_GYRO_CTRL3_C 0x12
- #define LSM6DS3_GYRO_FIFO_CTRL5 0x0A
- #define LSM6DS3_GYRO_CTRL9_XL 0x18
- //-----------------------------------------
- #define LSM6DS3_GYRO_IF_INC_DISABLED 0x00
- #define LSM6DS3_GYRO_IF_INC_ENABLED 0x04
- #define LSM6DS3_GYRO_IF_INC_MASK 0x04
- //-----------------------------------------
- #define LSM6DS3_GYRO_BDU_CONTINUOS 0x00
- #define LSM6DS3_GYRO_BDU_BLOCK_UPDATE 0x40
- #define LSM6DS3_GYRO_BDU_MASK 0x40
- //-----------------------------------------
- #define LSM6DS3_GYRO_FIFO_MODE_BYPASS 0x00
- #define LSM6DS3_GYRO_FIFO_MODE_FIFO 0x01
- #define LSM6DS3_GYRO_FIFO_MODE_STREAM 0x02
- #define LSM6DS3_GYRO_FIFO_MODE_STF 0x03
- #define LSM6DS3_GYRO_FIFO_MODE_BTS 0x04
- #define LSM6DS3_GYRO_FIFO_MODE_DYN_STREAM 0x05
- #define LSM6DS3_GYRO_FIFO_MODE_DYN_STREAM_2 0x06
- #define LSM6DS3_GYRO_FIFO_MODE_BTF 0x07
- #define LSM6DS3_GYRO_FIFO_MODE_MASK 0x07
- //-----------------------------------------
- #define LSM6DS3_GYRO_ODR_XL_POWER_DOWN 0x00
- #define LSM6DS3_GYRO_ODR_XL_13Hz 0x10
- #define LSM6DS3_GYRO_ODR_XL_26Hz 0x20
- #define LSM6DS3_GYRO_ODR_XL_52Hz 0x30
- #define LSM6DS3_GYRO_ODR_XL_104Hz 0x40
- #define LSM6DS3_GYRO_ODR_XL_208Hz 0x50
- #define LSM6DS3_GYRO_ODR_XL_416Hz 0x60
- #define LSM6DS3_GYRO_ODR_XL_833Hz 0x70
- #define LSM6DS3_GYRO_ODR_XL_1660Hz 0x80
- #define LSM6DS3_GYRO_ODR_XL_3330Hz 0x90
- #define LSM6DS3_GYRO_ODR_XL_6660Hz 0xA0
- #define LSM6DS3_GYRO_ODR_XL_13330Hz 0xB0
- #define LSM6DS3_GYRO_ODR_XL_MASK 0xF0
- //-----------------------------------------
- #define LSM6DS3_GYRO_FS_XL_2g 0x00
- #define LSM6DS3_GYRO_FS_XL_16g 0x04
- #define LSM6DS3_GYRO_FS_XL_4g 0x08
- #define LSM6DS3_GYRO_FS_XL_8g 0x0C
- #define LSM6DS3_GYRO_FS_XL_MASK 0x0C
- //-----------------------------------------
- #define LSM6DS3_GYRO_XEN_XL_MASK 0x08
- #define LSM6DS3_GYRO_YEN_XL_MASK 0x10
- #define LSM6DS3_GYRO_ZEN_XL_MASK 0x20
- #define LSM6DS3_GYRO_XEN_XL_ENABLED 0x08
- #define LSM6DS3_GYRO_YEN_XL_ENABLED 0x10
- #define LSM6DS3_GYRO_ZEN_XL_ENABLED 0x20
- //-----------------------------------------
- #define LSM6DS3_GYRO_OUTX_L_XL 0x28
- #define LSM6DS3_GYRO_OUTX_H_XL 0x29
- #define LSM6DS3_GYRO_OUTY_L_XL 0x2A
- #define LSM6DS3_GYRO_OUTY_H_XL 0x2B
- #define LSM6DS3_GYRO_OUTZ_L_XL 0x2C
- #define LSM6DS3_GYRO_OUTZ_H_XL 0x2D
- //-----------------------------------------
- #define LSM6DS3_WHO_AM_I_ADDRESS 0x0F
- #define LSM6DS3_ADDRESS_LOW 0xD4
- #define LSM6DS3_ADDRESS_HIGH 0xD6
- #define LSM6DS3_WHO_AM_I_ID ((uint8_t)0x69)
- //-----------------------------------------
- typedef struct lsm6ds3_struct{
- uint8_t readBuffer[10];
- uint8_t dataBuffer[14];
- }lsm6ds3_s;
- uint8_t LSM6DS3_Initialization(void);
- void LSM6DS3_PrepareAxisData(void);
- #endif /* LSM6DS3_H_ */
Plik c.
- #include "lsm6ds3.h"
- #include "stdint.h"
- lsm6ds3_s LSM6DS3_S_Data = {
- .readBuffer = {0},
- .dataBuffer = {0}
- };
- static void ErrorHandler(void);
- static void LSM6DS3_ReadID(uint8_t *readDataBuffer);
- static void LSM6DS3_WriteData(uint8_t Addres, uint8_t Register, uint8_t dataToSend);
- static void LSM6DS3_ReadData(uint8_t Addres, uint8_t Register, uint8_t loop, uint8_t * buffer);
- static void LSM6DS3_SetSensorParam(void);
- static void LSM6DS3_ReadXYZ(int16_t* pData);
- //----------------------------------------------------
- /* @brief initialization LSM6DS3, in function there is read ID and it is check
- if it wrong, then it generate errorhandler
- */
- uint8_t LSM6DS3_Initialization(void)
- {
- I2CSetTransmissionSpeed();
- _delay_ms(500);
- Lsm6ds3_ReadID(&LSM6DS3_S_Data.readBuffer);
- if(*(LSM6DS3_S_Data.readBuffer) != LSM6DS3_WHO_AM_I_ID) {
- ErrorHandler();
- return 0;
- }
- LSM6DS3_SetSensorParam();
- return 1;
- }
- //----------------------------------------------------
- void LSM6DS3_PrepareAxisData(void)
- {
- int16_t dataBuffer[3]={0,0,0};
- int16_t xAxisValue = 0;
- int16_t yAxisValue = 0;
- int16_t zAxisValue = 0;
- LSM6DS3_ReadXYZ(dataBuffer);
- xAxisValue=dataBuffer[0];
- yAxisValue=dataBuffer[1];
- zAxisValue=dataBuffer[2];
- LSM6DS3_S_Data.dataBuffer[0]=0x11;
- LSM6DS3_S_Data.dataBuffer[1]=0x55;
- LSM6DS3_S_Data.dataBuffer[2]=(uint8_t)(xAxisValue>>8);
- LSM6DS3_S_Data.dataBuffer[3]=(uint8_t)xAxisValue;
- LSM6DS3_S_Data.dataBuffer[4]=(uint8_t)(yAxisValue>>8);
- LSM6DS3_S_Data.dataBuffer[5]=(uint8_t)yAxisValue;
- LSM6DS3_S_Data.dataBuffer[6]=(uint8_t)(zAxisValue>>8);
- LSM6DS3_S_Data.dataBuffer[7]=(uint8_t)zAxisValue;
- _delay_ms(50);
- }
- /* @brief static functions */
- //----------------------------------------------------
- /* @brief: init error handler function, it simply goes into infinite loop */
- static void ErrorHandler(void)
- {
- /* Error */
- while(1) {
- /* Send som info thru uart, or turn on led etc */;
- }
- }
- //----------------------------------------------------
- /* Read ID of connected device */
- static void LSM6DS3_ReadID(uint8_t *readDataBuffer)
- {
- I2Cx_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_WHO_AM_I_ADDRESS,1,readDataBuffer);
- }
- //----------------------------------------------------
- /* Read data from device */
- static void LSM6DS3_ReadData(uint8_t Addres, uint8_t Register, uint8_t loop, uint8_t * buffer)
- {
- uint8_t i=loop;
- uint8_t n=0;
- I2CStart();
- I2C_Send(Addres);
- I2C_Send(Register);
- I2CStart();
- I2C_Send(Addres|0x01);
- for(uint16_t j = 0; j<2000; j++)
- {
- if(i==1){
- break;
- }
- buffer[n]=I2C_Read();
- i--;
- n++;
- }
- buffer[loop-1]=I2C_ReadOneByte();
- I2CStop();
- }
- //----------------------------------------------------
- /* @brief: write full data into LSM6DS3 */
- static void LSM6DS3_WriteData(uint8_t Addres, uint8_t Register, uint8_t dataToSend){
- I2CStart();
- I2C_Send(Addres);
- I2C_Send(Register);
- I2C_Send(dataToSend);
- I2CStop();
- }
- //----------------------------------------------------
- /* @brief: set parameters for sensor initialization */
- static void LSM6DS3_SetSensorParam(void)
- {
- /* Enable register address automatically incremented during a multile byte access with a
- serial interface */
- LSM6DS3_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL3_C,1,LSM6DS3_S_Data.readBuffer);
- LSM6DS3_S_Data.readBuffer[0] &=~ LSM6DS3_GYRO_IF_INC_MASK;
- LSM6DS3_S_Data.readBuffer[0] |= LSM6DS3_GYRO_IF_INC_ENABLED;
- LSM6DS3_WriteData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL3_C,LSM6DS3_S_Data.readBuffer[0]);
- /* Set BDU Bit */
- LSM6DS3_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL3_C,1,LSM6DS3_S_Data.readBuffer);
- LSM6DS3_S_Data.readBuffer[0] &=~ LSM6DS3_GYRO_BDU_MASK;
- LSM6DS3_S_Data.readBuffer[0] |= LSM6DS3_GYRO_BDU_BLOCK_UPDATE;
- LSM6DS3_WriteData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL3_C,LSM6DS3_S_Data.readBuffer[0]);
- /* select FIFO ODR */
- LSM6DS3_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_FIFO_CTRL5,1,LSM6DS3_S_Data.readBuffer);
- LSM6DS3_S_Data.readBuffer[0] &=~ LSM6DS3_GYRO_FIFO_MODE_MASK;
- LSM6DS3_S_Data.readBuffer[0] |= LSM6DS3_GYRO_FIFO_MODE_BYPASS;
- LSM6DS3_WriteData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_FIFO_CTRL5,LSM6DS3_S_Data.readBuffer[0]);
- /* accelerometr register data, set power down */
- LSM6DS3_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL1_XL,1,LSM6DS3_S_Data.readBuffer);
- LSM6DS3_S_Data.readBuffer[0] &=~ LSM6DS3_GYRO_ODR_XL_MASK;
- LSM6DS3_S_Data.readBuffer[0] |= LSM6DS3_GYRO_ODR_XL_POWER_DOWN;
- LSM6DS3_WriteData(0xD4,LSM6DS3_GYRO_CTRL1_XL,LSM6DS3_S_Data.readBuffer[0]);
- /* set selection for 245 dps */
- LSM6DS3_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL1_XL,1,LSM6DS3_S_Data.readBuffer);
- LSM6DS3_S_Data.readBuffer[0] &=~ LSM6DS3_GYRO_FS_XL_MASK;
- LSM6DS3_S_Data.readBuffer[0] |= LSM6DS3_GYRO_FS_XL_2g;
- LSM6DS3_WriteData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL1_XL,LSM6DS3_S_Data.readBuffer[0]);
- /* set all axis */
- LSM6DS3_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL9_XL,1,LSM6DS3_S_Data.readBuffer);
- LSM6DS3_S_Data.readBuffer[0] &=~ (LSM6DS3_GYRO_XEN_XL_MASK|LSM6DS3_GYRO_YEN_XL_MASK|LSM6DS3_GYRO_ZEN_XL_MASK);
- LSM6DS3_S_Data.readBuffer[0] |= (LSM6DS3_GYRO_XEN_XL_ENABLED|LSM6DS3_GYRO_YEN_XL_ENABLED|LSM6DS3_GYRO_ZEN_XL_ENABLED);
- LSM6DS3_WriteData(0xD4,LSM6DS3_GYRO_CTRL9_XL,LSM6DS3_S_Data.readBuffer[0]);
- /* set data rate for 104 hz */
- LSM6DS3_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL1_XL,1,LSM6DS3_S_Data.readBuffer);
- LSM6DS3_S_Data.readBuffer[0] &=~ LSM6DS3_GYRO_ODR_XL_MASK;
- LSM6DS3_S_Data.readBuffer[0] |= LSM6DS3_GYRO_ODR_XL_104Hz;
- LSM6DS3_WriteData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL1_XL,LSM6DS3_S_Data.readBuffer[0]);
- }
- //----------------------------------------------------
- /* @buffer: read data for axis x,y and z */
- static void LSM6DS3_ReadXYZ(int16_t* pData)
- {
- uint8_t dataBuffer[6];
- LSM6DS3_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_OUTX_L_XL,6,dataBuffer);
- for(uint8_t i=0;i<3;i++)
- {
- *(pData + i)=((int16_t)((uint16_t)*(dataBuffer+(2*i+1))<<8)+*(dataBuffer + (2*i)));
- }
- }