AP_InertialSensor_BMI160.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /*
  2. * Copyright (C) 2016 Intel Corporation. All rights reserved.
  3. *
  4. * This file is free software: you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License as published by the
  6. * Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This file is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. * See the GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <utility>
  18. #include <AP_HAL/AP_HAL.h>
  19. #if CONFIG_HAL_BOARD == HAL_BOARD_LINUX
  20. #include <AP_HAL/utility/sparse-endian.h>
  21. #include <AP_HAL_Linux/GPIO.h>
  22. #include <AP_Math/AP_Math.h>
  23. #include "AP_InertialSensor_BMI160.h"
  24. /* Registers and bits definitions. The indented ones are the bits for the upper
  25. * register. */
  26. #define BMI160_REG_CHIPID 0x00
  27. #define BMI160_CHIPID 0xD1
  28. #define BMI160_REG_ERR_REG 0x02
  29. #define BMI160_REG_FIFO_LENGTH 0x22
  30. #define BMI160_REG_FIFO_DATA 0x24
  31. #define BMI160_REG_ACC_CONF 0x40
  32. #define BMI160_REG_ACC_RANGE 0x41
  33. /* For convenience, use log2(range) - 1 instead of bits defined in
  34. * the datasheet. See _configure_accel(). */
  35. #define BMI160_ACC_RANGE_16G 3
  36. #define BMI160_REG_GYR_CONF 0x42
  37. #define BMI160_REG_GYR_RANGE 0x43
  38. #define BMI160_GYR_RANGE_2000DPS 0x00
  39. #define BMI160_REG_FIFO_CONFIG_0 0x46
  40. #define BMI160_REG_FIFO_CONFIG_1 0x47
  41. #define BMI160_FIFO_ACC_EN 0x40
  42. #define BMI160_FIFO_GYR_EN 0x80
  43. #define BMI160_REG_INT_EN_1 0x51
  44. #define BMI160_INT_FWM_EN 0x40
  45. #define BMI160_REG_INT_OUT_CTRL 0x53
  46. #define BMI160_INT1_LVL 0x02
  47. #define BMI160_INT1_OUTPUT_EN 0x08
  48. #define BMI160_REG_INT_MAP_1 0x56
  49. #define BMI160_INT_MAP_INT1_FWM 0x40
  50. #define BMI160_REG_CMD 0x7E
  51. #define BMI160_CMD_ACCEL_NORMAL_POWER_MODE 0x11
  52. #define BMI160_CMD_GYRO_NORMAL_POWER_MODE 0x15
  53. #define BMI160_CMD_FIFO_FLUSH 0xB0
  54. #define BMI160_CMD_SOFTRESET 0xB6
  55. #define BMI160_OSR_NORMAL 0x20
  56. #define BMI160_ODR_1600HZ 0x0C
  57. /* Datasheet says that the device powers up in less than 10ms, so waiting for
  58. * 10 ms before initialization is enough. */
  59. #define BMI160_POWERUP_DELAY_MSEC 10
  60. /* TODO: Investigate this. The delay below is way too high and with that
  61. * there's still at least 1% of failures on initialization. Lower values
  62. * increase that percentage. */
  63. #define BMI160_SOFTRESET_DELAY_MSEC 100
  64. /* Define a little bit more than the maximum value in the datasheet's timing
  65. * table. The datasheet recommends adding 300 us to the time for startup
  66. * occasions. */
  67. #define BMI160_ACCEL_NORMAL_POWER_MODE_DELAY_MSEC 4
  68. #define BMI160_GYRO_NORMAL_POWER_MODE_DELAY_MSEC 81
  69. #define BMI160_OSR BMI160_OSR_NORMAL
  70. #define BMI160_ODR BMI160_ODR_1600HZ
  71. #define BMI160_ACC_RANGE BMI160_ACC_RANGE_16G
  72. #define BMI160_GYR_RANGE BMI160_GYR_RANGE_2000DPS
  73. /* By looking at the datasheet, the accel range i (as defined by the macros
  74. * BMI160_ACC_RANGE_*G) maps to the range bits by the function f defined:
  75. * f(0) = 3; f(i) = f(i - 1) + i + 1
  76. * Which can be written as the closed formula:
  77. * f(i) = (i * (i + 3)) / 2 + 3 */
  78. #define BMI160_ACC_RANGE_BITS \
  79. (BMI160_ACC_RANGE * (BMI160_ACC_RANGE + 3) / 2 + 3)
  80. /* The rate in Hz based on the ODR bits can be calculated with
  81. * 100 / (2 ^ (8 - odr) */
  82. #define BMI160_ODR_TO_HZ(odr_) \
  83. (uint16_t)(odr_ > 8 ? 100 << (odr_ - 8) : 100 >> (8 - odr_))
  84. /* This number of samples should provide only one read burst operation on the
  85. * FIFO most of the time (99.99%). */
  86. #define BMI160_MAX_FIFO_SAMPLES 8
  87. #define BMI160_READ_FLAG 0x80
  88. #define BMI160_HARDWARE_INIT_MAX_TRIES 5
  89. #if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_AERO
  90. # define BMI160_INT1_GPIO AERO_GPIO_BMI160_INT1
  91. #else
  92. # define BMI160_INT1_GPIO -1
  93. #endif
  94. extern const AP_HAL::HAL& hal;
  95. struct PACKED RawData {
  96. struct {
  97. le16_t x;
  98. le16_t y;
  99. le16_t z;
  100. } gyro;
  101. struct {
  102. le16_t x;
  103. le16_t y;
  104. le16_t z;
  105. } accel;
  106. };
  107. AP_InertialSensor_BMI160::AP_InertialSensor_BMI160(AP_InertialSensor &imu,
  108. AP_HAL::OwnPtr<AP_HAL::Device> dev)
  109. : AP_InertialSensor_Backend(imu)
  110. , _dev(std::move(dev))
  111. {
  112. }
  113. AP_InertialSensor_Backend *
  114. AP_InertialSensor_BMI160::probe(AP_InertialSensor &imu,
  115. AP_HAL::OwnPtr<AP_HAL::SPIDevice> dev)
  116. {
  117. if (!dev) {
  118. return nullptr;
  119. }
  120. auto sensor = new AP_InertialSensor_BMI160(imu, std::move(dev));
  121. if (!sensor) {
  122. return nullptr;
  123. }
  124. if (!sensor->_init()) {
  125. delete sensor;
  126. return nullptr;
  127. }
  128. return sensor;
  129. }
  130. void AP_InertialSensor_BMI160::start()
  131. {
  132. bool r;
  133. if (!_dev->get_semaphore()->take(HAL_SEMAPHORE_BLOCK_FOREVER)) {
  134. return;
  135. }
  136. r = _configure_accel();
  137. if (!r) {
  138. AP_HAL::panic("BMI160: Unable to configure accelerometer");
  139. }
  140. r = _configure_gyro();
  141. if (!r) {
  142. AP_HAL::panic("BMI160: Unable to configure gyroscope");
  143. }
  144. r = _configure_fifo();
  145. if (!r) {
  146. AP_HAL::panic("BMI160: Unable to configure FIFO");
  147. }
  148. if (BMI160_INT1_GPIO >= 0) {
  149. r = _configure_int1_pin();
  150. if (!r) {
  151. AP_HAL::panic("BMI160: unable to configure INT1 pin");
  152. }
  153. }
  154. _dev->get_semaphore()->give();
  155. _accel_instance = _imu.register_accel(BMI160_ODR_TO_HZ(BMI160_ODR), _dev->get_bus_id_devtype(DEVTYPE_BMI160));
  156. _gyro_instance = _imu.register_gyro(BMI160_ODR_TO_HZ(BMI160_ODR), _dev->get_bus_id_devtype(DEVTYPE_BMI160));
  157. /* Call _poll_data() at 1kHz */
  158. _dev->register_periodic_callback(1000,
  159. FUNCTOR_BIND_MEMBER(&AP_InertialSensor_BMI160::_poll_data, void));
  160. }
  161. bool AP_InertialSensor_BMI160::update()
  162. {
  163. update_accel(_accel_instance);
  164. update_gyro(_gyro_instance);
  165. return true;
  166. }
  167. void AP_InertialSensor_BMI160::_check_err_reg()
  168. {
  169. #ifdef BMI160_DEBUG
  170. uint8_t v;
  171. bool r;
  172. r = _dev->read_registers(BMI160_REG_ERR_REG, &v, 1);
  173. if (!r) {
  174. AP_HAL::panic("BMI160: couldn't read ERR_REG\n");
  175. }
  176. if (v) {
  177. AP_HAL::panic("BMI160: error detected on ERR_REG\n");
  178. }
  179. #endif
  180. }
  181. bool AP_InertialSensor_BMI160::_configure_accel()
  182. {
  183. bool r;
  184. r = _dev->write_register(BMI160_REG_ACC_CONF, BMI160_OSR | BMI160_ODR);
  185. if (!r) {
  186. return false;
  187. }
  188. hal.scheduler->delay(1);
  189. _check_err_reg();
  190. r = _dev->write_register(BMI160_REG_ACC_RANGE, BMI160_ACC_RANGE_BITS);
  191. if (!r) {
  192. return false;
  193. }
  194. hal.scheduler->delay(1);
  195. /* The sensitivity in LSb/g for an accel range i (as defined by the macros
  196. * BMI160_ACC_RANGE_*G) can be calculated with:
  197. * 2 ^ 16 / (2 * 2 ^ (i + 1)) = 2 ^(14 - i)
  198. * That matches the typical values in the datasheet. */
  199. _accel_scale = GRAVITY_MSS / (1 << (14 - BMI160_ACC_RANGE));
  200. return true;
  201. }
  202. bool AP_InertialSensor_BMI160::_configure_gyro()
  203. {
  204. bool r;
  205. r = _dev->write_register(BMI160_REG_GYR_CONF, BMI160_OSR | BMI160_ODR);
  206. if (!r) {
  207. return false;
  208. }
  209. hal.scheduler->delay(1);
  210. _check_err_reg();
  211. r = _dev->write_register(BMI160_REG_GYR_RANGE, BMI160_GYR_RANGE);
  212. if (!r) {
  213. return false;
  214. }
  215. hal.scheduler->delay(1);
  216. /* The sensitivity in LSb/degrees/s a gyro range i can be calculated with:
  217. * 2 ^ 16 / (2 * 2000 / 2 ^ i) = 2 ^ (14 + i) / 1000
  218. * The scale is the inverse of that. */
  219. _gyro_scale = radians(1000.f / (1 << (14 + BMI160_GYR_RANGE)));
  220. return true;
  221. }
  222. bool AP_InertialSensor_BMI160::_configure_int1_pin()
  223. {
  224. bool r;
  225. r = _dev->write_register(BMI160_REG_INT_EN_1, BMI160_INT_FWM_EN);
  226. if (!r) {
  227. hal.console->printf("BMI160: Unable to enable FIFO watermark interrupt engine\n");
  228. return false;
  229. }
  230. hal.scheduler->delay(1);
  231. r = _dev->write_register(BMI160_REG_INT_MAP_1, BMI160_INT_MAP_INT1_FWM);
  232. if (!r) {
  233. hal.console->printf("BMI160: Unable to configure interrupt mapping\n");
  234. return false;
  235. }
  236. hal.scheduler->delay(1);
  237. r = _dev->write_register(BMI160_REG_INT_OUT_CTRL,
  238. BMI160_INT1_OUTPUT_EN | BMI160_INT1_LVL);
  239. if (!r) {
  240. hal.console->printf("BMI160: Unable to configure interrupt output\n");
  241. return false;
  242. }
  243. hal.scheduler->delay(1);
  244. _int1_pin = hal.gpio->channel(BMI160_INT1_GPIO);
  245. if (_int1_pin == nullptr) {
  246. hal.console->printf("BMI160: Couldn't request data ready GPIO channel\n");
  247. return false;
  248. }
  249. _int1_pin->mode(HAL_GPIO_INPUT);
  250. return true;
  251. }
  252. bool AP_InertialSensor_BMI160::_configure_fifo()
  253. {
  254. bool r;
  255. /* The unit for the FIFO watermark is 4 bytes. */
  256. r = _dev->write_register(BMI160_REG_FIFO_CONFIG_0,
  257. sizeof(struct RawData) / 4);
  258. if (!r) {
  259. hal.console->printf("BMI160: Unable to configure FIFO watermark level\n");
  260. return false;
  261. }
  262. hal.scheduler->delay(1);
  263. r = _dev->write_register(BMI160_REG_FIFO_CONFIG_1,
  264. BMI160_FIFO_ACC_EN | BMI160_FIFO_GYR_EN);
  265. if (!r) {
  266. hal.console->printf("BMI160: Unable to enable FIFO\n");
  267. return false;
  268. }
  269. hal.scheduler->delay(1);
  270. _check_err_reg();
  271. r = _dev->write_register(BMI160_REG_CMD, BMI160_CMD_FIFO_FLUSH);
  272. if (!r) {
  273. hal.console->printf("BMI160: Unable to flush FIFO\n");
  274. return false;
  275. }
  276. return true;
  277. }
  278. void AP_InertialSensor_BMI160::_read_fifo()
  279. {
  280. struct RawData raw_data[BMI160_MAX_FIFO_SAMPLES];
  281. uint16_t num_bytes;
  282. uint16_t excess;
  283. uint8_t num_samples = 0;
  284. bool r = true;
  285. static_assert(sizeof(raw_data) <= 100, "Too big to keep on stack");
  286. /* If FIFO watermark not surpassed. */
  287. if (_int1_pin && _int1_pin->read() == 0) {
  288. goto read_fifo_end;
  289. }
  290. r = _dev->read_registers(BMI160_REG_FIFO_LENGTH,
  291. (uint8_t *)&num_bytes,
  292. sizeof(num_bytes));
  293. if (!r) {
  294. goto read_fifo_end;
  295. }
  296. num_bytes = le16toh(num_bytes);
  297. if (!num_bytes) {
  298. goto read_fifo_end;
  299. }
  300. read_fifo_read_data:
  301. if (num_bytes > sizeof(raw_data)) {
  302. excess = num_bytes - sizeof(raw_data);
  303. num_bytes = sizeof(raw_data);
  304. } else {
  305. excess = 0;
  306. }
  307. r = _dev->read_registers(BMI160_REG_FIFO_DATA,
  308. (uint8_t *)raw_data,
  309. num_bytes);
  310. if (!r) {
  311. goto read_fifo_end;
  312. }
  313. /* Read again just once */
  314. if (excess && num_samples) {
  315. hal.console->printf("BMI160: dropping %u samples from fifo\n",
  316. (uint8_t)(excess / sizeof(struct RawData)));
  317. _dev->write_register(BMI160_REG_CMD, BMI160_CMD_FIFO_FLUSH);
  318. excess = 0;
  319. }
  320. num_samples = num_bytes / sizeof(struct RawData);
  321. for (uint8_t i = 0; i < num_samples; i++) {
  322. Vector3f accel{(float)(int16_t)le16toh(raw_data[i].accel.x),
  323. (float)(int16_t)le16toh(raw_data[i].accel.y),
  324. (float)(int16_t)le16toh(raw_data[i].accel.z)};
  325. Vector3f gyro{(float)(int16_t)le16toh(raw_data[i].gyro.x),
  326. (float)(int16_t)le16toh(raw_data[i].gyro.y),
  327. (float)(int16_t)le16toh(raw_data[i].gyro.z)};
  328. #if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_AERO
  329. accel.rotate(ROTATION_ROLL_180);
  330. gyro.rotate(ROTATION_ROLL_180);
  331. #endif
  332. accel *= _accel_scale;
  333. gyro *= _gyro_scale;
  334. _rotate_and_correct_accel(_accel_instance, accel);
  335. _rotate_and_correct_gyro(_gyro_instance, gyro);
  336. _notify_new_accel_raw_sample(_accel_instance, accel);
  337. _notify_new_gyro_raw_sample(_gyro_instance, gyro);
  338. }
  339. if (excess) {
  340. num_bytes = excess;
  341. goto read_fifo_read_data;
  342. }
  343. read_fifo_end:
  344. if (!r) {
  345. hal.console->printf("BMI160: error on reading FIFO\n");
  346. }
  347. }
  348. void AP_InertialSensor_BMI160::_poll_data()
  349. {
  350. _read_fifo();
  351. }
  352. bool AP_InertialSensor_BMI160::_hardware_init()
  353. {
  354. bool ret = false;
  355. hal.scheduler->delay(BMI160_POWERUP_DELAY_MSEC);
  356. if (!_dev->get_semaphore()->take(HAL_SEMAPHORE_BLOCK_FOREVER)) {
  357. return false;
  358. }
  359. _dev->set_speed(AP_HAL::Device::SPEED_LOW);
  360. for (unsigned i = 0; i < BMI160_HARDWARE_INIT_MAX_TRIES; i++) {
  361. uint8_t v;
  362. ret = _dev->write_register(BMI160_REG_CMD,
  363. BMI160_CMD_SOFTRESET);
  364. if (!ret) {
  365. continue;
  366. }
  367. hal.scheduler->delay(BMI160_SOFTRESET_DELAY_MSEC);
  368. /* The datasheet recommends doing a read operation on the register 0x7F
  369. * in order to guarantee the sensor works using the SPI protocol. This
  370. * shouldn't have side effects for I2C. */
  371. ret = _dev->read_registers(0x7F, &v, 1);
  372. if (!ret) {
  373. continue;
  374. }
  375. ret = _dev->read_registers(BMI160_REG_CHIPID, &v, 1);
  376. if (!ret) {
  377. continue;
  378. }
  379. if (v != BMI160_CHIPID) {
  380. ret = false;
  381. continue;
  382. }
  383. ret = _dev->write_register(BMI160_REG_CMD,
  384. BMI160_CMD_ACCEL_NORMAL_POWER_MODE);
  385. if (!ret) {
  386. continue;
  387. }
  388. hal.scheduler->delay(BMI160_ACCEL_NORMAL_POWER_MODE_DELAY_MSEC);
  389. ret = _dev->write_register(BMI160_REG_CMD,
  390. BMI160_CMD_GYRO_NORMAL_POWER_MODE);
  391. if (!ret) {
  392. continue;
  393. }
  394. hal.scheduler->delay(BMI160_GYRO_NORMAL_POWER_MODE_DELAY_MSEC);
  395. break;
  396. }
  397. _dev->set_speed(AP_HAL::Device::SPEED_HIGH);
  398. _dev->get_semaphore()->give();
  399. return ret;
  400. }
  401. bool AP_InertialSensor_BMI160::_init()
  402. {
  403. bool ret = false;
  404. _dev->set_read_flag(BMI160_READ_FLAG);
  405. ret = _hardware_init();
  406. if (!ret) {
  407. hal.console->printf("BMI160: failed to init\n");
  408. }
  409. return ret;
  410. }
  411. #endif