wtorek, 5 września 2017

[10] Atmega - Akcelerometr LSM6DS3

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:

  1. #ifndef I2C_INIT_H_
  2. #define I2C_INIT_H_
  3. #include "main.h"
  4. void I2CSetTransmissionSpeed(void);
  5. void I2CStart(void);
  6. void I2CStop(void);
  7. void I2C_Send(unsigned char c);
  8. void I2C_SendByteWitAddress(unsigned char c,unsigned char addr);
  9. unsigned char I2C_Read(void);
  10. unsigned char I2C_ReadOneByte(void);
  11. #endif /* I2C_INIT_H_ */

Plik c:

  1. #include "i2c_init.h"
  2. //-------------------------------------------------------------------
  3. void I2CSetTransmissionSpeed(void)
  4. {
  5.     /* Set transmission speed */
  6.     TWBR=0x48;
  7. }
  8. //-------------------------------------------------------------------
  9. void I2CStart(void)
  10. {
  11.     /* Set TWIN flag for 1 to unblock TWI interupt */
  12.     /* Set TWSTA activates generate Master transmission start */
  13.     /* For unblock I2C set TWEN bit */
  14.     TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
  15.    
  16.     /* Wait until TWINT flag is set */
  17.     while (!(TWCR & (1<<TWINT)));
  18. }
  19. //-------------------------------------------------------------------
  20. void I2CStop(void)
  21. {
  22.     /*
  23.      * Unblock interrupt
  24.      * set TWSTO bit for generating hardware I2C Stop
  25.      */
  26.     TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
  27. }
  28. //-------------------------------------------------------------------
  29. void I2C_Send(unsigned char c)
  30. {
  31.     /* Write byte to send to TWDR byte */
  32.     TWDR = c;
  33.     /* unblock interrupt */
  34.     TWCR = (1<<TWINT)|(1<<TWEN);
  35.     /* Wait for data transmitt */
  36.     while (!(TWCR & (1<<TWINT)));
  37. }
  38. //-------------------------------------------------------------------
  39. unsigned char I2C_Read(void)
  40. {
  41.     /*
  42.      * if read more than 1 data then TWEA need to be 1, else it could be zero,
  43.      * it says to slave device to disconnect from master, read one byte is done
  44.      * in I2C_ReadOneByte function
  45.     */
  46.     TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
  47.     /* wait for end of reading */
  48.     while (!(TWCR & (1<<TWINT)));
  49.     /* read data from register */
  50.     return TWDR;
  51. }
  52. //-------------------------------------------------------------------
  53. void I2C_SendByteWitAddress(unsigned char c,unsigned char addr)
  54. {
  55.     /* Start transmission */
  56.     I2CStart();
  57.     /* Adress with register to write */
  58.     I2C_Send(addr);
  59.     /* Bajt to write into register */
  60.     I2C_Send(c);
  61.     /* Stop data transmission */
  62.     I2CStop();
  63. }
  64. //-------------------------------------------------------------------
  65. unsigned char I2C_ReadOneByte(void)
  66. {
  67.     /* read only one byte of data */
  68.     TWCR = (1<<TWINT)|(1<<TWEN);
  69.     while (!(TWCR & (1<<TWINT)));
  70.     return TWDR;
  71. }

Teraz pliki od układu LSM6DS3:

Plik h.

  1. #ifndef LSM6DS3_H_
  2. #define LSM6DS3_H_
  3. //-----------------------------------------
  4. #include <stdint.h>
  5. #include <avr/io.h>
  6. //-----------------------------------------
  7. #define LSM6DS3_GYRO_CTRL1_XL               0x10
  8. #define LSM6DS3_GYRO_CTRL3_C                0x12
  9. #define LSM6DS3_GYRO_FIFO_CTRL5             0x0A
  10. #define LSM6DS3_GYRO_CTRL9_XL               0x18
  11. //-----------------------------------------
  12. #define LSM6DS3_GYRO_IF_INC_DISABLED        0x00
  13. #define LSM6DS3_GYRO_IF_INC_ENABLED         0x04
  14. #define LSM6DS3_GYRO_IF_INC_MASK            0x04
  15. //-----------------------------------------
  16. #define LSM6DS3_GYRO_BDU_CONTINUOS      0x00
  17. #define LSM6DS3_GYRO_BDU_BLOCK_UPDATE   0x40
  18. #define LSM6DS3_GYRO_BDU_MASK           0x40
  19. //-----------------------------------------
  20. #define LSM6DS3_GYRO_FIFO_MODE_BYPASS       0x00
  21. #define LSM6DS3_GYRO_FIFO_MODE_FIFO         0x01
  22. #define LSM6DS3_GYRO_FIFO_MODE_STREAM       0x02
  23. #define LSM6DS3_GYRO_FIFO_MODE_STF          0x03
  24. #define LSM6DS3_GYRO_FIFO_MODE_BTS          0x04
  25. #define LSM6DS3_GYRO_FIFO_MODE_DYN_STREAM   0x05
  26. #define LSM6DS3_GYRO_FIFO_MODE_DYN_STREAM_2 0x06
  27. #define LSM6DS3_GYRO_FIFO_MODE_BTF          0x07
  28. #define LSM6DS3_GYRO_FIFO_MODE_MASK         0x07
  29. //-----------------------------------------
  30. #define LSM6DS3_GYRO_ODR_XL_POWER_DOWN      0x00
  31. #define LSM6DS3_GYRO_ODR_XL_13Hz            0x10
  32. #define LSM6DS3_GYRO_ODR_XL_26Hz            0x20
  33. #define LSM6DS3_GYRO_ODR_XL_52Hz            0x30
  34. #define LSM6DS3_GYRO_ODR_XL_104Hz           0x40
  35. #define LSM6DS3_GYRO_ODR_XL_208Hz           0x50
  36. #define LSM6DS3_GYRO_ODR_XL_416Hz           0x60
  37. #define LSM6DS3_GYRO_ODR_XL_833Hz           0x70
  38. #define LSM6DS3_GYRO_ODR_XL_1660Hz          0x80
  39. #define LSM6DS3_GYRO_ODR_XL_3330Hz          0x90
  40. #define LSM6DS3_GYRO_ODR_XL_6660Hz          0xA0
  41. #define LSM6DS3_GYRO_ODR_XL_13330Hz         0xB0
  42. #define LSM6DS3_GYRO_ODR_XL_MASK            0xF0
  43. //-----------------------------------------
  44. #define LSM6DS3_GYRO_FS_XL_2g               0x00
  45. #define LSM6DS3_GYRO_FS_XL_16g              0x04
  46. #define LSM6DS3_GYRO_FS_XL_4g               0x08
  47. #define LSM6DS3_GYRO_FS_XL_8g               0x0C
  48. #define LSM6DS3_GYRO_FS_XL_MASK             0x0C
  49. //-----------------------------------------
  50. #define LSM6DS3_GYRO_XEN_XL_MASK            0x08
  51. #define LSM6DS3_GYRO_YEN_XL_MASK            0x10
  52. #define LSM6DS3_GYRO_ZEN_XL_MASK            0x20
  53. #define LSM6DS3_GYRO_XEN_XL_ENABLED         0x08
  54. #define LSM6DS3_GYRO_YEN_XL_ENABLED         0x10
  55. #define LSM6DS3_GYRO_ZEN_XL_ENABLED         0x20
  56. //-----------------------------------------
  57. #define LSM6DS3_GYRO_OUTX_L_XL              0x28
  58. #define LSM6DS3_GYRO_OUTX_H_XL              0x29
  59. #define LSM6DS3_GYRO_OUTY_L_XL              0x2A
  60. #define LSM6DS3_GYRO_OUTY_H_XL              0x2B
  61. #define LSM6DS3_GYRO_OUTZ_L_XL              0x2C
  62. #define LSM6DS3_GYRO_OUTZ_H_XL              0x2D
  63. //-----------------------------------------
  64. #define LSM6DS3_WHO_AM_I_ADDRESS                0x0F
  65. #define LSM6DS3_ADDRESS_LOW                     0xD4    
  66. #define LSM6DS3_ADDRESS_HIGH                    0xD6
  67. #define LSM6DS3_WHO_AM_I_ID                     ((uint8_t)0x69)
  68. //-----------------------------------------
  69. typedef struct lsm6ds3_struct{
  70.     uint8_t readBuffer[10];
  71.     uint8_t dataBuffer[14];
  72. }lsm6ds3_s;
  73. uint8_t LSM6DS3_Initialization(void);
  74. void LSM6DS3_PrepareAxisData(void);
  75. #endif /* LSM6DS3_H_ */

Plik c.

  1. #include "lsm6ds3.h"
  2. #include "stdint.h"
  3. lsm6ds3_s LSM6DS3_S_Data = {
  4.         .readBuffer = {0},
  5.         .dataBuffer = {0}
  6. };
  7. static void ErrorHandler(void);
  8. static void LSM6DS3_ReadID(uint8_t *readDataBuffer);
  9. static void LSM6DS3_WriteData(uint8_t Addres, uint8_t Register, uint8_t dataToSend);
  10. static void LSM6DS3_ReadData(uint8_t Addres, uint8_t Register, uint8_t loop, uint8_t * buffer);
  11. static void LSM6DS3_SetSensorParam(void);
  12. static void LSM6DS3_ReadXYZ(int16_t* pData);
  13. //----------------------------------------------------
  14. /* @brief initialization LSM6DS3, in function there is read ID and it is check
  15.             if it wrong, then it generate errorhandler
  16. */
  17. uint8_t LSM6DS3_Initialization(void)
  18. {
  19.     I2CSetTransmissionSpeed();
  20.    
  21.     _delay_ms(500);
  22.    
  23.     Lsm6ds3_ReadID(&LSM6DS3_S_Data.readBuffer);
  24.    
  25.     if(*(LSM6DS3_S_Data.readBuffer) != LSM6DS3_WHO_AM_I_ID) {
  26.         ErrorHandler();
  27.         return 0;
  28.     }      
  29.    
  30.     LSM6DS3_SetSensorParam();
  31.    
  32.     return 1;
  33. }
  34. //----------------------------------------------------
  35. void LSM6DS3_PrepareAxisData(void)
  36. {
  37.     int16_t dataBuffer[3]={0,0,0};
  38.     int16_t xAxisValue = 0;
  39.     int16_t yAxisValue = 0;
  40.     int16_t zAxisValue = 0;
  41.    
  42.     LSM6DS3_ReadXYZ(dataBuffer);
  43.    
  44.     xAxisValue=dataBuffer[0];
  45.     yAxisValue=dataBuffer[1];
  46.     zAxisValue=dataBuffer[2];
  47.    
  48.     LSM6DS3_S_Data.dataBuffer[0]=0x11;
  49.     LSM6DS3_S_Data.dataBuffer[1]=0x55;
  50.     LSM6DS3_S_Data.dataBuffer[2]=(uint8_t)(xAxisValue>>8);
  51.     LSM6DS3_S_Data.dataBuffer[3]=(uint8_t)xAxisValue;
  52.     LSM6DS3_S_Data.dataBuffer[4]=(uint8_t)(yAxisValue>>8);
  53.     LSM6DS3_S_Data.dataBuffer[5]=(uint8_t)yAxisValue;
  54.     LSM6DS3_S_Data.dataBuffer[6]=(uint8_t)(zAxisValue>>8);
  55.     LSM6DS3_S_Data.dataBuffer[7]=(uint8_t)zAxisValue;
  56.    
  57.     _delay_ms(50);
  58. }
  59. /* @brief static functions */
  60. //----------------------------------------------------
  61. /* @brief: init error handler function, it simply goes into infinite loop */
  62. static void ErrorHandler(void)
  63. {
  64.     /* Error */
  65.     while(1) {
  66.         /* Send som info thru uart, or turn on led etc */;
  67.     }
  68. }
  69. //----------------------------------------------------
  70. /* Read ID of connected device */
  71. static void LSM6DS3_ReadID(uint8_t *readDataBuffer)
  72. {
  73.     I2Cx_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_WHO_AM_I_ADDRESS,1,readDataBuffer);
  74. }
  75. //----------------------------------------------------
  76. /* Read data from device */
  77. static void LSM6DS3_ReadData(uint8_t Addres, uint8_t Register, uint8_t loop, uint8_t * buffer)
  78. {
  79.     uint8_t i=loop;
  80.     uint8_t n=0;
  81.    
  82.     I2CStart();
  83.     I2C_Send(Addres);
  84.     I2C_Send(Register);
  85.     I2CStart();
  86.     I2C_Send(Addres|0x01);
  87.    
  88.     for(uint16_t j = 0; j<2000; j++)
  89.     {
  90.         if(i==1){
  91.             break;
  92.         }
  93.         buffer[n]=I2C_Read();
  94.         i--;
  95.         n++;
  96.     }
  97.     buffer[loop-1]=I2C_ReadOneByte();
  98.     I2CStop();
  99. }
  100. //----------------------------------------------------
  101. /* @brief: write full data into LSM6DS3 */
  102. static void LSM6DS3_WriteData(uint8_t Addres, uint8_t Register, uint8_t dataToSend){
  103.     I2CStart();
  104.     I2C_Send(Addres);
  105.     I2C_Send(Register);
  106.     I2C_Send(dataToSend);
  107.     I2CStop();
  108. }
  109. //----------------------------------------------------
  110. /* @brief: set parameters for sensor initialization */
  111. static void LSM6DS3_SetSensorParam(void)
  112. {
  113.     /* Enable register address automatically incremented during a multile byte access with a
  114.         serial interface */
  115.     LSM6DS3_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL3_C,1,LSM6DS3_S_Data.readBuffer);
  116.     LSM6DS3_S_Data.readBuffer[0] &=~ LSM6DS3_GYRO_IF_INC_MASK;
  117.     LSM6DS3_S_Data.readBuffer[0] |= LSM6DS3_GYRO_IF_INC_ENABLED;
  118.     LSM6DS3_WriteData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL3_C,LSM6DS3_S_Data.readBuffer[0]);
  119.    
  120.     /* Set BDU Bit */
  121.     LSM6DS3_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL3_C,1,LSM6DS3_S_Data.readBuffer);
  122.     LSM6DS3_S_Data.readBuffer[0] &=~ LSM6DS3_GYRO_BDU_MASK;
  123.     LSM6DS3_S_Data.readBuffer[0] |= LSM6DS3_GYRO_BDU_BLOCK_UPDATE;
  124.     LSM6DS3_WriteData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL3_C,LSM6DS3_S_Data.readBuffer[0]);
  125.    
  126.     /* select FIFO ODR */
  127.     LSM6DS3_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_FIFO_CTRL5,1,LSM6DS3_S_Data.readBuffer);
  128.     LSM6DS3_S_Data.readBuffer[0] &=~ LSM6DS3_GYRO_FIFO_MODE_MASK;
  129.     LSM6DS3_S_Data.readBuffer[0] |= LSM6DS3_GYRO_FIFO_MODE_BYPASS;
  130.     LSM6DS3_WriteData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_FIFO_CTRL5,LSM6DS3_S_Data.readBuffer[0]);
  131.    
  132.     /* accelerometr register data, set power down */
  133.     LSM6DS3_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL1_XL,1,LSM6DS3_S_Data.readBuffer);
  134.     LSM6DS3_S_Data.readBuffer[0] &=~ LSM6DS3_GYRO_ODR_XL_MASK;
  135.     LSM6DS3_S_Data.readBuffer[0] |= LSM6DS3_GYRO_ODR_XL_POWER_DOWN;
  136.     LSM6DS3_WriteData(0xD4,LSM6DS3_GYRO_CTRL1_XL,LSM6DS3_S_Data.readBuffer[0]);
  137.    
  138.     /* set selection for 245 dps */
  139.     LSM6DS3_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL1_XL,1,LSM6DS3_S_Data.readBuffer);
  140.     LSM6DS3_S_Data.readBuffer[0] &=~ LSM6DS3_GYRO_FS_XL_MASK;
  141.     LSM6DS3_S_Data.readBuffer[0] |= LSM6DS3_GYRO_FS_XL_2g;
  142.     LSM6DS3_WriteData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL1_XL,LSM6DS3_S_Data.readBuffer[0]);
  143.    
  144.     /* set all axis */
  145.     LSM6DS3_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL9_XL,1,LSM6DS3_S_Data.readBuffer);
  146.     LSM6DS3_S_Data.readBuffer[0] &=(LSM6DS3_GYRO_XEN_XL_MASK|LSM6DS3_GYRO_YEN_XL_MASK|LSM6DS3_GYRO_ZEN_XL_MASK);
  147.     LSM6DS3_S_Data.readBuffer[0] |= (LSM6DS3_GYRO_XEN_XL_ENABLED|LSM6DS3_GYRO_YEN_XL_ENABLED|LSM6DS3_GYRO_ZEN_XL_ENABLED);
  148.     LSM6DS3_WriteData(0xD4,LSM6DS3_GYRO_CTRL9_XL,LSM6DS3_S_Data.readBuffer[0]);
  149.    
  150.     /* set data rate for 104 hz */
  151.     LSM6DS3_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL1_XL,1,LSM6DS3_S_Data.readBuffer);
  152.     LSM6DS3_S_Data.readBuffer[0] &=~ LSM6DS3_GYRO_ODR_XL_MASK;
  153.     LSM6DS3_S_Data.readBuffer[0] |= LSM6DS3_GYRO_ODR_XL_104Hz;
  154.     LSM6DS3_WriteData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_CTRL1_XL,LSM6DS3_S_Data.readBuffer[0]);
  155. }
  156. //----------------------------------------------------
  157. /* @buffer: read data for axis x,y and z */
  158. static void LSM6DS3_ReadXYZ(int16_t* pData)
  159. {
  160.     uint8_t dataBuffer[6];
  161.    
  162.     LSM6DS3_ReadData(LSM6DS3_ADDRESS_LOW,LSM6DS3_GYRO_OUTX_L_XL,6,dataBuffer);
  163.    
  164.     for(uint8_t i=0;i<3;i++)
  165.     {
  166.         *(pData + i)=((int16_t)((uint16_t)*(dataBuffer+(2*i+1))<<8)+*(dataBuffer + (2*i)));
  167.     }
  168. }