M5Unified
MPU6886_Class.cpp
Go to the documentation of this file.
1 // Copyright (c) M5Stack. All rights reserved.
2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 
4 #if defined (ESP_PLATFORM)
5 
6 #include "MPU6886_Class.hpp"
7 #include <freertos/FreeRTOS.h>
8 #include <freertos/task.h>
9 
10 namespace m5
11 {
13  MPU6886_Class::MPU6886_Class(std::uint8_t i2c_addr, std::uint32_t freq, I2C_Class* i2c)
14  : IMU_Base ( i2c_addr, freq, i2c )
15  {}
16 
17  IMU_Base::imu_spec_t MPU6886_Class::begin(I2C_Class* i2c)
18  {
19  if (i2c)
20  {
21  _i2c = i2c;
22  }
23 
24  // WHO_AM_I : IMU Check
25  auto id = readRegister8(0x75);
26  _device_id = id;
27  if (id != DEV_ID_MPU6886
28  && id != DEV_ID_MPU6050
29  && id != DEV_ID_MPU9250)
30  {
31  return imu_spec_none;
32  }
33  writeRegister8(REG_PWR_MGMT_1, 0x80);
34 
35  static constexpr std::uint8_t init_cmd[] =
36  { REG_PWR_MGMT_1 , 0x01
37  , REG_ACCEL_CONFIG , 0x10 // ACCEL_CONFIG(0x1C) : +-8G
38  , REG_GYRO_CONFIG , 0x18 // GYRO_CONFIG(0x1B) : +-2000dps
39  , REG_CONFIG , 0x01 // CONFIG(0x1A)
40  , REG_SMPLRT_DIV , 0x03 // SMPLRT_DIV(0x19)
41  , REG_INT_ENABLE , 0x00 // INT_ENABLE(0x38)
42  , REG_ACCEL_CONFIG2 , 0x00 // ACCEL_CONFIG 2(0x1D)
43  , REG_USER_CTRL , 0x00 // USER_CTRL(0x6A)
44  , REG_FIFO_EN , 0x00 // FIFO_EN(0x23)
45  , 0xFF, 0xFF // EOF
46  };
47 
48  for (int idx = -1;;)
49  {
50  std::uint8_t reg = init_cmd[++idx];
51  std::uint8_t val = init_cmd[++idx];
52  if ((reg & val) == 0xFF) { break; }
53  uint32_t retry_count = 16;
54  do {
55  writeRegister8(reg, val);
56  } while (readRegister8(reg) != val && --retry_count);
57  }
58 
59  setGyroFsr(Gscale::GFS_2000DPS);
60  setAccelFsr(Ascale::AFS_8G);
61 
62  _init = true;
63  _fifo_en = false;
64 
65 // enableFIFO(Fodr::ODR_500Hz);
66 
67  return (imu_spec_t)(imu_spec_accel | imu_spec_gyro);
68  }
69 
70  bool MPU6886_Class::setGyroAdcOffset(std::int16_t gx, std::int16_t gy, std::int16_t gz)
71  {
72  uint8_t buffer[6] =
73  { (uint8_t)(gx >> 8), (uint8_t)gx
74  , (uint8_t)(gy >> 8), (uint8_t)gy
75  , (uint8_t)(gz >> 8), (uint8_t)gz
76  };
77  return writeRegister(0x13, buffer, 6);
78  }
79 
80  void MPU6886_Class::enableFIFO(Fodr output_data_rate)
81  {
82  auto regdata = readRegister8(REG_GYRO_CONFIG);
83  regdata &= 0x1C; // Clear bits 7:5 and 0:1 of FCHOICE_B to enable sample
84  // rate divider and DLPF setting
85  writeRegister8(REG_GYRO_CONFIG, regdata);
86  vTaskDelay(10);
87 
88  regdata = output_data_rate & 0xFF; // Set sample rate clock divider based on passed
89  // value for sample rate desired
90  writeRegister8(REG_SMPLRT_DIV, regdata);
91  vTaskDelay(10);
92 
93  regdata = readRegister8(REG_CONFIG);
94  regdata |= 0x01; // Set DLPF_CFG to 176Hz DLPF filtering (highest value
95  // where sample rate clock divider still works)
96  regdata &= 0xBF; // Clear bit 6 to allow overflow writes to the FIFO - Use
97  // it, or lose it!
98  writeRegister8(REG_CONFIG, regdata);
99  vTaskDelay(10);
100 
101 // MPU9250: 0x78(TEMP OUT + GYRO XOUT,YOUT,ZOUT + ACCEL)
102  regdata = 0xF8; // Set GYRO_FIFO_EN and ACCEL_FIFO_EN bits to one in FIFO
103  // Enable register to enable FIFO on ALL sensor data
104  writeRegister8(REG_FIFO_EN, regdata);
105  vTaskDelay(10);
106 
107  regdata = readRegister8(REG_INT_ENABLE);
108  regdata |= 0x10; // Set bit 4 to turn on interrupts on FIFO overflow events
109  writeRegister8(REG_INT_ENABLE, regdata);
110  vTaskDelay(10);
111 
112  regdata = 0x44; // Set FIFO_EN and FIFO_RST bits to one in User Control
113  // register to enable FIFO mode
114  writeRegister8(REG_USER_CTRL, regdata);
115  vTaskDelay(10);
116 
117  _fifo_en = true;
118  }
119 /*
120  void MPU6886_Class::disableFIFO(void)
121  {
122  _fifo_en = false;
123  unsigned char regdata;
124  regdata = 0x00; // Clear GYRO_FIFO_EN and ACCEL_FIFO_EN bits to zero in
125  // FIFO Enable register
126  writeRegister8(REG_FIFO_EN, regdata);
127  vTaskDelay(10);
128 
129  writeRegister8(REG_INT_ENABLE, regdata);
130  regdata &=
131  0xEF; // Clear bit 4 to turn off interrupts on FIFO overflow events
132  writeRegister8(REG_INT_ENABLE, regdata);
133  vTaskDelay(10);
134 
135  regdata = 0x00; // Set FIFO_EN bit to zero in User Control register to
136  // dsiable FIFO mode
137  writeRegister8(REG_USER_CTRL, regdata);
138  vTaskDelay(10);
139  }
140 //*/
141  void MPU6886_Class::setGyroFsr(Gscale scale)
142  {
143  scale = (Gscale)(scale & 3);
144  _gscale = scale;
145  writeRegister8(REG_GYRO_CONFIG, scale << 3);
146  vTaskDelay(10);
147  static constexpr const float table[] =
148  { 250.0f / 32768.0f // GFS_250DPS
149  , 500.0f / 32768.0f // GFS_500DPS
150  , 1000.0f / 32768.0f // GFS_1000DPS
151  , 2000.0f / 32768.0f // GFS_2000DPS
152  };
153  _gRes = table[scale];
154  }
155 
156  void MPU6886_Class::setAccelFsr(Ascale scale)
157  {
158  scale = (Ascale)(scale & 3);
159  _ascale = scale;
160  writeRegister8(REG_ACCEL_CONFIG, scale << 3);
161  vTaskDelay(10);
162  static constexpr const float table[] =
163  { 2.0f / 32768.0f // AFS_2G
164  , 4.0f / 32768.0f // AFS_4G
165  , 8.0f / 32768.0f // AFS_8G
166  , 16.0f / 32768.0f // AFS_16G
167  };
168  _aRes = table[scale];
169  }
170 
171  bool MPU6886_Class::setINTPinActiveLogic(bool level)
172  {
173  // MPU6886_INT_PIN_CFG = 0x37
174  std::uint8_t tmp = readRegister8(REG_INT_PIN_CFG) & 0x7F;
175  tmp |= level ? 0x00 : 0x80;
176  return writeRegister8(REG_INT_PIN_CFG, tmp);
177  }
178 /*
179  bool MPU6886_Class::getAccelAdc(std::int16_t* ax, std::int16_t* ay, std::int16_t* az) const
180  {
181  std::uint8_t buf[6];
182  bool res = readRegister(0x3B, buf, 6);
183  *ax = (buf[0] << 8) + buf[1];
184  *ay = (buf[2] << 8) + buf[3];
185  *az = (buf[4] << 8) + buf[5];
186  return res;
187  }
188 
189  bool MPU6886_Class::getGyroAdc(std::int16_t* gx, std::int16_t* gy, std::int16_t* gz) const
190  {
191  std::uint8_t buf[6];
192  bool res = readRegister(0x43, buf, 6);
193  *gx = (buf[0] << 8) + buf[1];
194  *gy = (buf[2] << 8) + buf[3];
195  *gz = (buf[4] << 8) + buf[5];
196  return res;
197  }
198 
199  bool MPU6886_Class::getAccel(float* ax, float* ay, float* az) const
200  {
201  std::uint8_t buf[6];
202  bool res = readRegister(0x3B, buf, 6);
203  auto aRes = _aRes;
204  *ax = (std::int16_t)((buf[0] << 8) + buf[1]) * aRes;
205  *ay = (std::int16_t)((buf[2] << 8) + buf[3]) * aRes;
206  *az = (std::int16_t)((buf[4] << 8) + buf[5]) * aRes;
207  return res;
208  }
209 
210  bool MPU6886_Class::getGyro(float* gx, float* gy, float* gz) const
211  {
212  std::uint8_t buf[6];
213  bool res = readRegister(0x43, buf, 6);
214  auto gRes = _gRes;
215  *gx = (std::int16_t)((buf[0] << 8) + buf[1]) * gRes;
216  *gy = (std::int16_t)((buf[2] << 8) + buf[3]) * gRes;
217  *gz = (std::int16_t)((buf[4] << 8) + buf[5]) * gRes;
218  return res;
219  }
220 
221  bool MPU6886_Class::getTemp(float *t) const
222  {
223  std::uint8_t buf[2];
224  bool res = readRegister(0x41, buf, 2);
225  *t = 25.0f + ((buf[0] << 8) + buf[1]) / 326.8f;
226  return res;
227  }
228 //*/
229  IMU_Base::imu_spec_t MPU6886_Class::getImuRawData(imu_raw_data_t* data) const
230  {
231  std::uint8_t raw_buf[16];
232  auto buf = &raw_buf[1];
233 
234  if (_fifo_en)
235  {
236  if (!readRegister(REG_FIFO_COUNTH, buf, 2) || (buf[0] + buf[1] == 0))
237  {
238  return imu_spec_none;
239  }
240  if (!readRegister(REG_FIFO_R_W, buf, 14) || (buf[0] == 0x7F && buf[1] == 0x7F))
241  {
242  return imu_spec_none;
243  }
244  }
245  else
246  {
247  if (!readRegister(0x3A, raw_buf, 15) || ((raw_buf[0] & 1) == 0))
248  {
249  return imu_spec_none;
250  }
251  }
252 
253  data->accel.x = (std::int16_t)((buf[0] << 8) + buf[1]);
254  data->accel.y = (std::int16_t)((buf[2] << 8) + buf[3]);
255  data->accel.z = (std::int16_t)((buf[4] << 8) + buf[5]);
256  // data->temp = (std::int16_t)((buf[6] << 8) + buf[7]);
257 
258  data->gyro.x = (std::int16_t)((buf[ 8] << 8) + buf[ 9]);
259  data->gyro.y = (std::int16_t)((buf[10] << 8) + buf[11]);
260  data->gyro.z = (std::int16_t)((buf[12] << 8) + buf[13]);
261  return (imu_spec_t)(imu_spec_accel | imu_spec_gyro);
262  }
263 
264  void MPU6886_Class::getConvertParam(imu_convert_param_t* param) const
265  {
266  param->accel_res = _aRes;
267  param->gyro_res = _gRes;
268  param->temp_res = 1.0f / 326.8f;
269  param->temp_offset = 25.0f;
270  }
271 
272  bool MPU6886_Class::getTempAdc(int16_t* t) const
273  {
274  std::uint8_t buf[2];
275  bool res = readRegister(0x41, buf, 2);
276  if (res) { *t = (buf[0] << 8) + buf[1]; }
277  return res;
278  }
279 }
280 #endif
virtual ~MPU6886_Class()
MPU6886_Class(std::uint8_t i2c_addr=DEFAULT_ADDRESS, std::uint32_t freq=400000, I2C_Class *i2c=&In_I2C)
Definition: M5Unified.cpp:48