motion_driver_example.c.old 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092
  1. /**
  2. * @defgroup eMPL
  3. * @brief Embedded Motion Processing Library
  4. *
  5. * @{
  6. * @file main.c
  7. * @brief Test app for eMPL using the Motion Driver DMP image.
  8. */
  9. /* Includes ------------------------------------------------------------------*/
  10. #include <rtthread.h>
  11. #include <finsh.h>
  12. #include "stdio.h"
  13. #include "MD_Ported_to_RTT.h"
  14. #include "motion_driver_example.h"
  15. #include "inv_mpu.h"
  16. #include "inv_mpu_dmp_motion_driver.h"
  17. #include "invensense.h"
  18. // #include "invensense_adv.h"
  19. #include "eMPL_outputs.h"
  20. #include "mltypes.h"
  21. #include "mpu.h"
  22. #include "log.h"
  23. #include "packet.h"
  24. /* Private typedef -----------------------------------------------------------*/
  25. /* The bus name of the mpu. */
  26. #define RT_MPU_DEVICE_NAME "i2c2"
  27. /* Data read from MPL. */
  28. #define PRINT_ACCEL (0x01)
  29. #define PRINT_GYRO (0x02)
  30. #define PRINT_QUAT (0x04)
  31. #define PRINT_COMPASS (0x08)
  32. #define PRINT_EULER (0x10)
  33. #define PRINT_ROT_MAT (0x20)
  34. #define PRINT_HEADING (0x40)
  35. #define PRINT_PEDO (0x80)
  36. #define PRINT_LINEAR_ACCEL (0x100)
  37. #define PRINT_GRAVITY_VECTOR (0x200)
  38. volatile uint32_t hal_timestamp = 0;
  39. #define ACCEL_ON (0x01)
  40. #define GYRO_ON (0x02)
  41. #define COMPASS_ON (0x04)
  42. #define MOTION (0)
  43. #define NO_MOTION (1)
  44. /* Starting sampling rate. */
  45. #define DEFAULT_MPU_HZ (20)
  46. // #define FLASH_SIZE (512)
  47. // #define FLASH_MEM_START ((void*)0x1800)
  48. #define PEDO_READ_MS (1000)
  49. #define TEMP_READ_MS (500)
  50. #define COMPASS_READ_MS (100)
  51. struct rt_mpu_device *mpu_dev;
  52. struct rx_s {
  53. unsigned char header[3];
  54. unsigned char cmd;
  55. };
  56. struct hal_s {
  57. unsigned char lp_accel_mode;
  58. unsigned char sensors;
  59. unsigned char dmp_on;
  60. unsigned char wait_for_tap;
  61. volatile unsigned char new_gyro;
  62. unsigned char motion_int_mode;
  63. unsigned long no_dmp_hz;
  64. unsigned long next_pedo_ms;
  65. unsigned long next_temp_ms;
  66. unsigned long next_compass_ms;
  67. unsigned int report;
  68. unsigned short dmp_features;
  69. struct rx_s rx;
  70. };
  71. static struct hal_s hal = {0};
  72. /* USB RX binary semaphore. Actually, it's just a flag. Not included in struct
  73. * because it's declared extern elsewhere.
  74. */
  75. volatile unsigned char rx_new;
  76. unsigned char *mpl_key = (unsigned char*)"eMPL 5.1";
  77. /* Platform-specific information. Kinda like a boardfile. */
  78. struct platform_data_s {
  79. signed char orientation[9];
  80. };
  81. /* The sensors can be mounted onto the board in any orientation. The mounting
  82. * matrix seen below tells the MPL how to rotate the raw data from the
  83. * driver(s).
  84. * TODO: The following matrices refer to the configuration on internal test
  85. * boards at Invensense. If needed, please modify the matrices to match the
  86. * chip-to-body matrix for your particular set up.
  87. */
  88. static struct platform_data_s gyro_pdata = {
  89. .orientation = { 1, 0, 0,
  90. 0, 1, 0,
  91. 0, 0, 1}
  92. };
  93. #if defined MPU9150 || defined MPU9250
  94. static struct platform_data_s compass_pdata = {
  95. .orientation = { 0, 1, 0,
  96. 1, 0, 0,
  97. 0, 0, -1}
  98. };
  99. #define COMPASS_ENABLED 1
  100. #elif defined AK8975_SECONDARY
  101. static struct platform_data_s compass_pdata = {
  102. .orientation = {-1, 0, 0,
  103. 0, 1, 0,
  104. 0, 0,-1}
  105. };
  106. #define COMPASS_ENABLED 1
  107. #elif defined AK8963_SECONDARY
  108. static struct platform_data_s compass_pdata = {
  109. .orientation = {-1, 0, 0,
  110. 0,-1, 0,
  111. 0, 0, 1}
  112. };
  113. #define COMPASS_ENABLED 1
  114. #endif
  115. /* Private define ------------------------------------------------------------*/
  116. /* Private macro -------------------------------------------------------------*/
  117. /* Private variables ---------------------------------------------------------*/
  118. /* Private function prototypes -----------------------------------------------*/
  119. /* ---------------------------------------------------------------------------*/
  120. /* Get data from MPL.
  121. * TODO: Add return values to the inv_get_sensor_type_xxx APIs to differentiate
  122. * between new and stale data.
  123. */
  124. static void read_from_mpl(void)
  125. {
  126. long msg, data[9];
  127. int8_t accuracy;
  128. unsigned long timestamp;
  129. float float_data[3] = {0};
  130. if (inv_get_sensor_type_quat(data, &accuracy, (inv_time_t*)&timestamp)) {
  131. /* Sends a quaternion packet to the PC. Since this is used by the Python
  132. * test app to visually represent a 3D quaternion, it's sent each time
  133. * the MPL has new data.
  134. */
  135. eMPL_send_quat(data);
  136. /* Specific data packets can be sent or suppressed using USB commands. */
  137. if (hal.report & PRINT_QUAT)
  138. eMPL_send_data(PACKET_DATA_QUAT, data);
  139. }
  140. if (hal.report & PRINT_ACCEL) {
  141. if (inv_get_sensor_type_accel(data, &accuracy,
  142. (inv_time_t*)&timestamp))
  143. eMPL_send_data(PACKET_DATA_ACCEL, data);
  144. }
  145. if (hal.report & PRINT_GYRO) {
  146. if (inv_get_sensor_type_gyro(data, &accuracy,
  147. (inv_time_t*)&timestamp))
  148. eMPL_send_data(PACKET_DATA_GYRO, data);
  149. }
  150. #ifdef COMPASS_ENABLED
  151. if (hal.report & PRINT_COMPASS) {
  152. if (inv_get_sensor_type_compass(data, &accuracy,
  153. (inv_time_t*)&timestamp))
  154. eMPL_send_data(PACKET_DATA_COMPASS, data);
  155. }
  156. #endif
  157. if (hal.report & PRINT_EULER) {
  158. if (inv_get_sensor_type_euler(data, &accuracy,
  159. (inv_time_t*)&timestamp))
  160. eMPL_send_data(PACKET_DATA_EULER, data);
  161. }
  162. if (hal.report & PRINT_ROT_MAT) {
  163. if (inv_get_sensor_type_rot_mat(data, &accuracy,
  164. (inv_time_t*)&timestamp))
  165. eMPL_send_data(PACKET_DATA_ROT, data);
  166. }
  167. if (hal.report & PRINT_HEADING) {
  168. if (inv_get_sensor_type_heading(data, &accuracy,
  169. (inv_time_t*)&timestamp))
  170. eMPL_send_data(PACKET_DATA_HEADING, data);
  171. }
  172. if (hal.report & PRINT_LINEAR_ACCEL) {
  173. if (inv_get_sensor_type_linear_acceleration(float_data, &accuracy, (inv_time_t*)&timestamp)) {
  174. MPL_LOGI("Linear Accel: %7.5f %7.5f %7.5f\r\n",
  175. float_data[0], float_data[1], float_data[2]);
  176. }
  177. }
  178. if (hal.report & PRINT_GRAVITY_VECTOR) {
  179. if (inv_get_sensor_type_gravity(float_data, &accuracy,
  180. (inv_time_t*)&timestamp))
  181. MPL_LOGI("Gravity Vector: %7.5f %7.5f %7.5f\r\n",
  182. float_data[0], float_data[1], float_data[2]);
  183. }
  184. if (hal.report & PRINT_PEDO) {
  185. unsigned long timestamp;
  186. get_tick_count(&timestamp);
  187. if (timestamp > hal.next_pedo_ms) {
  188. hal.next_pedo_ms = timestamp + PEDO_READ_MS;
  189. unsigned long step_count, walk_time;
  190. dmp_get_pedometer_step_count(&step_count);
  191. dmp_get_pedometer_walk_time(&walk_time);
  192. MPL_LOGI("Walked %ld steps over %ld milliseconds..\n", step_count,
  193. walk_time);
  194. }
  195. }
  196. /* Whenever the MPL detects a change in motion state, the application can
  197. * be notified. For this example, we use an LED to represent the current
  198. * motion state.
  199. */
  200. msg = inv_get_message_level_0(INV_MSG_MOTION_EVENT |
  201. INV_MSG_NO_MOTION_EVENT);
  202. if (msg) {
  203. if (msg & INV_MSG_MOTION_EVENT) {
  204. MPL_LOGI("Motion!\n");
  205. } else if (msg & INV_MSG_NO_MOTION_EVENT) {
  206. MPL_LOGI("No motion!\n");
  207. }
  208. }
  209. }
  210. #ifdef COMPASS_ENABLED
  211. void send_status_compass() {
  212. long data[3] = { 0 };
  213. int8_t accuracy = { 0 };
  214. unsigned long timestamp;
  215. inv_get_compass_set(data, &accuracy, (inv_time_t*) &timestamp);
  216. MPL_LOGI("Compass: %7.4f %7.4f %7.4f ",
  217. data[0]/65536.f, data[1]/65536.f, data[2]/65536.f);
  218. MPL_LOGI("Accuracy= %d\r\n", accuracy);
  219. }
  220. #endif
  221. /* Handle sensor on/off combinations. */
  222. static void setup_gyro(void)
  223. {
  224. unsigned char mask = 0, lp_accel_was_on = 0;
  225. if (hal.sensors & ACCEL_ON)
  226. mask |= INV_XYZ_ACCEL;
  227. if (hal.sensors & GYRO_ON) {
  228. mask |= INV_XYZ_GYRO;
  229. lp_accel_was_on |= hal.lp_accel_mode;
  230. }
  231. #ifdef COMPASS_ENABLED
  232. if (hal.sensors & COMPASS_ON) {
  233. mask |= INV_XYZ_COMPASS;
  234. lp_accel_was_on |= hal.lp_accel_mode;
  235. }
  236. #endif
  237. /* If you need a power transition, this function should be called with a
  238. * mask of the sensors still enabled. The driver turns off any sensors
  239. * excluded from this mask.
  240. */
  241. mpu_set_sensors(mask);
  242. mpu_configure_fifo(mask);
  243. if (lp_accel_was_on) {
  244. unsigned short rate;
  245. hal.lp_accel_mode = 0;
  246. /* Switching out of LP accel, notify MPL of new accel sampling rate. */
  247. mpu_get_sample_rate(&rate);
  248. inv_set_accel_sample_rate(1000000L / rate);
  249. }
  250. }
  251. static void tap_cb(unsigned char direction, unsigned char count)
  252. {
  253. switch (direction) {
  254. case TAP_X_UP:
  255. MPL_LOGI("Tap X+ ");
  256. break;
  257. case TAP_X_DOWN:
  258. MPL_LOGI("Tap X- ");
  259. break;
  260. case TAP_Y_UP:
  261. MPL_LOGI("Tap Y+ ");
  262. break;
  263. case TAP_Y_DOWN:
  264. MPL_LOGI("Tap Y- ");
  265. break;
  266. case TAP_Z_UP:
  267. MPL_LOGI("Tap Z+ ");
  268. break;
  269. case TAP_Z_DOWN:
  270. MPL_LOGI("Tap Z- ");
  271. break;
  272. default:
  273. return;
  274. }
  275. MPL_LOGI("x%d\n", count);
  276. return;
  277. }
  278. static void android_orient_cb(unsigned char orientation)
  279. {
  280. switch (orientation) {
  281. case ANDROID_ORIENT_PORTRAIT:
  282. MPL_LOGI("Portrait\n");
  283. break;
  284. case ANDROID_ORIENT_LANDSCAPE:
  285. MPL_LOGI("Landscape\n");
  286. break;
  287. case ANDROID_ORIENT_REVERSE_PORTRAIT:
  288. MPL_LOGI("Reverse Portrait\n");
  289. break;
  290. case ANDROID_ORIENT_REVERSE_LANDSCAPE:
  291. MPL_LOGI("Reverse Landscape\n");
  292. break;
  293. default:
  294. return;
  295. }
  296. }
  297. static inline void run_self_test(void)
  298. {
  299. int result;
  300. long gyro[3], accel[3];
  301. #if defined (MPU6500) || defined (MPU9250)
  302. result = mpu_run_6500_self_test(gyro, accel, 0);
  303. #elif defined (MPU6050) || defined (MPU9150)
  304. result = mpu_run_self_test(gyro, accel);
  305. #endif
  306. if (result == 0x7) {
  307. MPL_LOGI("Passed!\n");
  308. MPL_LOGI("accel: %7.4f %7.4f %7.4f\n",
  309. accel[0]/65536.f,
  310. accel[1]/65536.f,
  311. accel[2]/65536.f);
  312. MPL_LOGI("gyro: %7.4f %7.4f %7.4f\n",
  313. gyro[0]/65536.f,
  314. gyro[1]/65536.f,
  315. gyro[2]/65536.f);
  316. /* Test passed. We can trust the gyro data here, so now we need to update calibrated data*/
  317. #ifdef USE_CAL_HW_REGISTERS
  318. /*
  319. * This portion of the code uses the HW offset registers that are in the MPUxxxx devices
  320. * instead of pushing the cal data to the MPL software library
  321. */
  322. unsigned char i = 0;
  323. for(i = 0; i<3; i++) {
  324. gyro[i] = (long)(gyro[i] * 32.8f); //convert to +-1000dps
  325. accel[i] *= 2048.f; //convert to +-16G
  326. accel[i] = accel[i] >> 16;
  327. gyro[i] = (long)(gyro[i] >> 16);
  328. }
  329. mpu_set_gyro_bias_reg(gyro);
  330. #if defined (MPU6500) || defined (MPU9250)
  331. mpu_set_accel_bias_6500_reg(accel);
  332. #elif defined (MPU6050) || defined (MPU9150)
  333. mpu_set_accel_bias_6050_reg(accel);
  334. #endif
  335. #else
  336. /* Push the calibrated data to the MPL library.
  337. *
  338. * MPL expects biases in hardware units << 16, but self test returns
  339. * biases in g's << 16.
  340. */
  341. unsigned short accel_sens;
  342. float gyro_sens;
  343. mpu_get_accel_sens(&accel_sens);
  344. accel[0] *= accel_sens;
  345. accel[1] *= accel_sens;
  346. accel[2] *= accel_sens;
  347. inv_set_accel_bias(accel, 3);
  348. mpu_get_gyro_sens(&gyro_sens);
  349. gyro[0] = (long) (gyro[0] * gyro_sens);
  350. gyro[1] = (long) (gyro[1] * gyro_sens);
  351. gyro[2] = (long) (gyro[2] * gyro_sens);
  352. inv_set_gyro_bias(gyro, 3);
  353. #endif
  354. }
  355. else {
  356. if (!(result & 0x1))
  357. MPL_LOGE("Gyro failed.\n");
  358. if (!(result & 0x2))
  359. MPL_LOGE("Accel failed.\n");
  360. if (!(result & 0x4))
  361. MPL_LOGE("Compass failed.\n");
  362. }
  363. }
  364. static void handle_input(int argc, char **argv)
  365. {
  366. char c;
  367. if (argc < 2)
  368. {
  369. rt_kprintf("\n");
  370. // rt_kprintf("mpu6xxx [OPTION] [PARAM]\n");
  371. rt_kprintf("argc must more than 2\n");
  372. return ;
  373. }
  374. else if (argc == 2)
  375. {
  376. c = argv[1];
  377. rt_kprintf("input c=%c\n", c);
  378. }
  379. else
  380. {
  381. rt_kprintf("Unknown command!\n");
  382. }
  383. switch (c) {
  384. /* These commands turn off individual sensors. */
  385. case '8':
  386. hal.sensors ^= ACCEL_ON;
  387. setup_gyro();
  388. if (!(hal.sensors & ACCEL_ON))
  389. inv_accel_was_turned_off();
  390. break;
  391. case '9':
  392. hal.sensors ^= GYRO_ON;
  393. setup_gyro();
  394. if (!(hal.sensors & GYRO_ON))
  395. inv_gyro_was_turned_off();
  396. break;
  397. #ifdef COMPASS_ENABLED
  398. case '0':
  399. hal.sensors ^= COMPASS_ON;
  400. setup_gyro();
  401. if (!(hal.sensors & COMPASS_ON))
  402. inv_compass_was_turned_off();
  403. break;
  404. #endif
  405. /* The commands send individual sensor data or fused data to the PC. */
  406. case 'a':
  407. hal.report ^= PRINT_ACCEL;
  408. break;
  409. case 'g':
  410. hal.report ^= PRINT_GYRO;
  411. break;
  412. #ifdef COMPASS_ENABLED
  413. case 'c':
  414. hal.report ^= PRINT_COMPASS;
  415. break;
  416. #endif
  417. case 'e':
  418. hal.report ^= PRINT_EULER;
  419. break;
  420. case 'r':
  421. hal.report ^= PRINT_ROT_MAT;
  422. break;
  423. case 'q':
  424. hal.report ^= PRINT_QUAT;
  425. break;
  426. case 'h':
  427. hal.report ^= PRINT_HEADING;
  428. break;
  429. case 'i':
  430. hal.report ^= PRINT_LINEAR_ACCEL;
  431. break;
  432. case 'o':
  433. hal.report ^= PRINT_GRAVITY_VECTOR;
  434. break;
  435. #ifdef COMPASS_ENABLED
  436. case 'w':
  437. send_status_compass();
  438. break;
  439. #endif
  440. /* This command prints out the value of each gyro register for debugging.
  441. * If logging is disabled, this function has no effect.
  442. */
  443. case 'd':
  444. mpu_reg_dump();
  445. break;
  446. /* Test out low-power accel mode. */
  447. case 'p':
  448. if (hal.dmp_on)
  449. /* LP accel is not compatible with the DMP. */
  450. break;
  451. mpu_lp_accel_mode(20);
  452. /* When LP accel mode is enabled, the driver automatically configures
  453. * the hardware for latched interrupts. However, the MCU sometimes
  454. * misses the rising/falling edge, and the hal.new_gyro flag is never
  455. * set. To avoid getting locked in this state, we're overriding the
  456. * driver's configuration and sticking to unlatched interrupt mode.
  457. *
  458. * TODO: The MCU supports level-triggered interrupts.
  459. */
  460. mpu_set_int_latched(0);
  461. hal.sensors &= ~(GYRO_ON|COMPASS_ON);
  462. hal.sensors |= ACCEL_ON;
  463. hal.lp_accel_mode = 1;
  464. inv_gyro_was_turned_off();
  465. inv_compass_was_turned_off();
  466. break;
  467. /* The hardware self test can be run without any interaction with the
  468. * MPL since it's completely localized in the gyro driver. Logging is
  469. * assumed to be enabled; otherwise, a couple LEDs could probably be used
  470. * here to display the test results.
  471. */
  472. case 't':
  473. run_self_test();
  474. /* Let MPL know that contiguity was broken. */
  475. inv_accel_was_turned_off();
  476. inv_gyro_was_turned_off();
  477. inv_compass_was_turned_off();
  478. break;
  479. /* Depending on your application, sensor data may be needed at a faster or
  480. * slower rate. These commands can speed up or slow down the rate at which
  481. * the sensor data is pushed to the MPL.
  482. *
  483. * In this example, the compass rate is never changed.
  484. */
  485. case '1':
  486. if (hal.dmp_on) {
  487. dmp_set_fifo_rate(10);
  488. inv_set_quat_sample_rate(100000L);
  489. } else
  490. mpu_set_sample_rate(10);
  491. inv_set_gyro_sample_rate(100000L);
  492. inv_set_accel_sample_rate(100000L);
  493. break;
  494. case '2':
  495. if (hal.dmp_on) {
  496. dmp_set_fifo_rate(20);
  497. inv_set_quat_sample_rate(50000L);
  498. } else
  499. mpu_set_sample_rate(20);
  500. inv_set_gyro_sample_rate(50000L);
  501. inv_set_accel_sample_rate(50000L);
  502. break;
  503. case '3':
  504. if (hal.dmp_on) {
  505. dmp_set_fifo_rate(40);
  506. inv_set_quat_sample_rate(25000L);
  507. } else
  508. mpu_set_sample_rate(40);
  509. inv_set_gyro_sample_rate(25000L);
  510. inv_set_accel_sample_rate(25000L);
  511. break;
  512. case '4':
  513. if (hal.dmp_on) {
  514. dmp_set_fifo_rate(50);
  515. inv_set_quat_sample_rate(20000L);
  516. } else
  517. mpu_set_sample_rate(50);
  518. inv_set_gyro_sample_rate(20000L);
  519. inv_set_accel_sample_rate(20000L);
  520. break;
  521. case '5':
  522. if (hal.dmp_on) {
  523. dmp_set_fifo_rate(100);
  524. inv_set_quat_sample_rate(10000L);
  525. } else
  526. mpu_set_sample_rate(100);
  527. inv_set_gyro_sample_rate(10000L);
  528. inv_set_accel_sample_rate(10000L);
  529. break;
  530. case ',':
  531. /* Set hardware to interrupt on gesture event only. This feature is
  532. * useful for keeping the MCU asleep until the DMP detects as a tap or
  533. * orientation event.
  534. */
  535. dmp_set_interrupt_mode(DMP_INT_GESTURE);
  536. break;
  537. case '.':
  538. /* Set hardware to interrupt periodically. */
  539. dmp_set_interrupt_mode(DMP_INT_CONTINUOUS);
  540. break;
  541. case '6':
  542. /* Toggle pedometer display. */
  543. hal.report ^= PRINT_PEDO;
  544. break;
  545. case '7':
  546. /* Reset pedometer. */
  547. dmp_set_pedometer_step_count(0);
  548. dmp_set_pedometer_walk_time(0);
  549. break;
  550. case 'f':
  551. if (hal.lp_accel_mode)
  552. /* LP accel is not compatible with the DMP. */
  553. return;
  554. /* Toggle DMP. */
  555. if (hal.dmp_on) {
  556. unsigned short dmp_rate;
  557. unsigned char mask = 0;
  558. hal.dmp_on = 0;
  559. mpu_set_dmp_state(0);
  560. /* Restore FIFO settings. */
  561. if (hal.sensors & ACCEL_ON)
  562. mask |= INV_XYZ_ACCEL;
  563. if (hal.sensors & GYRO_ON)
  564. mask |= INV_XYZ_GYRO;
  565. if (hal.sensors & COMPASS_ON)
  566. mask |= INV_XYZ_COMPASS;
  567. mpu_configure_fifo(mask);
  568. /* When the DMP is used, the hardware sampling rate is fixed at
  569. * 200Hz, and the DMP is configured to downsample the FIFO output
  570. * using the function dmp_set_fifo_rate. However, when the DMP is
  571. * turned off, the sampling rate remains at 200Hz. This could be
  572. * handled in inv_mpu.c, but it would need to know that
  573. * inv_mpu_dmp_motion_driver.c exists. To avoid this, we'll just
  574. * put the extra logic in the application layer.
  575. */
  576. dmp_get_fifo_rate(&dmp_rate);
  577. mpu_set_sample_rate(dmp_rate);
  578. inv_quaternion_sensor_was_turned_off();
  579. MPL_LOGI("DMP disabled.\n");
  580. } else {
  581. unsigned short sample_rate;
  582. hal.dmp_on = 1;
  583. /* Preserve current FIFO rate. */
  584. mpu_get_sample_rate(&sample_rate);
  585. dmp_set_fifo_rate(sample_rate);
  586. inv_set_quat_sample_rate(1000000L / sample_rate);
  587. mpu_set_dmp_state(1);
  588. MPL_LOGI("DMP enabled.\n");
  589. }
  590. break;
  591. case 'm':
  592. /* Test the motion interrupt hardware feature. */
  593. #ifndef MPU6050 // not enabled for 6050 product
  594. hal.motion_int_mode = 1;
  595. #endif
  596. break;
  597. case 'v':
  598. /* Toggle LP quaternion.
  599. * The DMP features can be enabled/disabled at runtime. Use this same
  600. * approach for other features.
  601. */
  602. hal.dmp_features ^= DMP_FEATURE_6X_LP_QUAT;
  603. dmp_enable_feature(hal.dmp_features);
  604. if (!(hal.dmp_features & DMP_FEATURE_6X_LP_QUAT)) {
  605. inv_quaternion_sensor_was_turned_off();
  606. MPL_LOGI("LP quaternion disabled.\n");
  607. } else
  608. MPL_LOGI("LP quaternion enabled.\n");
  609. break;
  610. default:
  611. break;
  612. }
  613. hal.rx.cmd = 0;
  614. }
  615. #ifdef FINSH_USING_MSH
  616. MSH_CMD_EXPORT(handle_input, handle mpu commands input);
  617. #endif
  618. /* Every time new gyro data is available, this function is called in an
  619. * ISR context. In this example, it sets a flag protecting the FIFO read
  620. * function.
  621. */
  622. void gyro_data_ready_cb(void)
  623. {
  624. hal.new_gyro = 1;
  625. }
  626. /*******************************************************************************/
  627. /**
  628. * @brief main entry point.
  629. * @par Parameters None
  630. * @retval void None
  631. * @par Required preconditions: None
  632. */
  633. int _motion_driver_example(void)
  634. {
  635. inv_error_t result;
  636. unsigned char accel_fsr, new_temp = 0;
  637. unsigned short gyro_rate, gyro_fsr;
  638. unsigned long timestamp;
  639. struct int_param_s int_param;
  640. // struct rt_mpu_device *dev;
  641. #ifdef COMPASS_ENABLED
  642. unsigned char new_compass = 0;
  643. unsigned short compass_fsr;
  644. #endif
  645. // board_init();
  646. // result = mpu_init(&int_param);
  647. // if (result) {
  648. // MPL_LOGE("Could not initialize gyro.\n");
  649. // }
  650. /* Initialize mpu6xxx, The parameter is RT_NULL, means auto probing for i2c*/
  651. // rt_mpu_init(RT_MPU_DEVICE_NAME, RT_NULL);
  652. mpu_dev = rt_mpu_init(RT_MPU_DEVICE_NAME, RT_NULL);
  653. result = mpu_init(&int_param);
  654. if (result) {
  655. log_e("Could not initialize gyro.\n");
  656. }
  657. // if (dev == RT_NULL)
  658. // {
  659. // rt_kprintf("mpu init failed\n");
  660. // return -1;
  661. // }
  662. // rt_kprintf("mpu init succeed\n");
  663. /* If you're not using an MPU9150 AND you're not using DMP features, this
  664. * function will place all slaves on the primary bus.
  665. * mpu_set_bypass(1);
  666. */
  667. result = inv_init_mpl();
  668. if (result) {
  669. MPL_LOGE("Could not initialize MPL.\n");
  670. }
  671. // /* Compute 6-axis and 9-axis quaternions. */
  672. // inv_enable_quaternion();
  673. // inv_enable_9x_sensor_fusion();
  674. /* The MPL expects compass data at a constant rate (matching the rate
  675. * passed to inv_set_compass_sample_rate). If this is an issue for your
  676. * application, call this function, and the MPL will depend on the
  677. * timestamps passed to inv_build_compass instead.
  678. *
  679. * inv_9x_fusion_use_timestamps(1);
  680. */
  681. /* This function has been deprecated.
  682. * inv_enable_no_gyro_fusion();
  683. */
  684. /* Update gyro biases when not in motion.
  685. * WARNING: These algorithms are mutually exclusive.
  686. */
  687. // inv_enable_fast_nomot();
  688. /* inv_enable_motion_no_motion(); */
  689. /* inv_set_no_motion_time(1000); */
  690. /* Update gyro biases when temperature changes. */
  691. // inv_enable_gyro_tc();
  692. /* This algorithm updates the accel biases when in motion. A more accurate
  693. * bias measurement can be made when running the self-test (see case 't' in
  694. * handle_input), but this algorithm can be enabled if the self-test can't
  695. * be executed in your application.
  696. *
  697. * inv_enable_in_use_auto_calibration();
  698. */
  699. #ifdef COMPASS_ENABLED
  700. /* Compass calibration algorithms. */
  701. inv_enable_vector_compass_cal();
  702. inv_enable_magnetic_disturbance();
  703. #endif
  704. /* If you need to estimate your heading before the compass is calibrated,
  705. * enable this algorithm. It becomes useless after a good figure-eight is
  706. * detected, so we'll just leave it out to save memory.
  707. * inv_enable_heading_from_gyro();
  708. */
  709. /* Allows use of the MPL APIs in read_from_mpl. */
  710. inv_enable_eMPL_outputs();
  711. result = inv_start_mpl();
  712. if (result == INV_ERROR_NOT_AUTHORIZED) {
  713. while (1) {
  714. MPL_LOGE("Not authorized.\n");
  715. }
  716. }
  717. if (result) {
  718. MPL_LOGE("Could not start the MPL.\n");
  719. }
  720. /* Get/set hardware configuration. Start gyro. */
  721. /* Wake up all sensors. */
  722. #ifdef COMPASS_ENABLED
  723. mpu_set_sensors(INV_XYZ_GYRO | INV_XYZ_ACCEL | INV_XYZ_COMPASS);
  724. #else
  725. mpu_set_sensors(INV_XYZ_GYRO | INV_XYZ_ACCEL);
  726. #endif
  727. /* Push both gyro and accel data into the FIFO. */
  728. mpu_configure_fifo(INV_XYZ_GYRO | INV_XYZ_ACCEL);
  729. mpu_set_sample_rate(DEFAULT_MPU_HZ);
  730. #ifdef COMPASS_ENABLED
  731. /* The compass sampling rate can be less than the gyro/accel sampling rate.
  732. * Use this function for proper power management.
  733. */
  734. mpu_set_compass_sample_rate(1000 / COMPASS_READ_MS);
  735. #endif
  736. /* Read back configuration in case it was set improperly. */
  737. mpu_get_sample_rate(&gyro_rate);
  738. mpu_get_gyro_fsr(&gyro_fsr);
  739. mpu_get_accel_fsr(&accel_fsr);
  740. #ifdef COMPASS_ENABLED
  741. mpu_get_compass_fsr(&compass_fsr);
  742. #endif
  743. /* Sync driver configuration with MPL. */
  744. /* Sample rate expected in microseconds. */
  745. inv_set_gyro_sample_rate(1000000L / gyro_rate);
  746. inv_set_accel_sample_rate(1000000L / gyro_rate);
  747. #ifdef COMPASS_ENABLED
  748. /* The compass rate is independent of the gyro and accel rates. As long as
  749. * inv_set_compass_sample_rate is called with the correct value, the 9-axis
  750. * fusion algorithm's compass correction gain will work properly.
  751. */
  752. inv_set_compass_sample_rate(COMPASS_READ_MS * 1000L);
  753. #endif
  754. /* Set chip-to-body orientation matrix.
  755. * Set hardware units to dps/g's/degrees scaling factor.
  756. */
  757. inv_set_gyro_orientation_and_scale(
  758. inv_orientation_matrix_to_scalar(gyro_pdata.orientation),
  759. (long)gyro_fsr<<15);
  760. inv_set_accel_orientation_and_scale(
  761. inv_orientation_matrix_to_scalar(gyro_pdata.orientation),
  762. (long)accel_fsr<<15);
  763. #ifdef COMPASS_ENABLED
  764. inv_set_compass_orientation_and_scale(
  765. inv_orientation_matrix_to_scalar(compass_pdata.orientation),
  766. (long)compass_fsr<<15);
  767. #endif
  768. /* Initialize HAL state variables. */
  769. #ifdef COMPASS_ENABLED
  770. hal.sensors = ACCEL_ON | GYRO_ON | COMPASS_ON;
  771. #else
  772. hal.sensors = ACCEL_ON | GYRO_ON;
  773. #endif
  774. hal.dmp_on = 0;
  775. hal.report = 0;
  776. hal.rx.cmd = 0;
  777. hal.next_pedo_ms = 0;
  778. hal.next_compass_ms = 0;
  779. hal.next_temp_ms = 0;
  780. /* Compass reads are handled by scheduler. */
  781. get_tick_count(&timestamp);
  782. /* To initialize the DMP:
  783. * 1. Call dmp_load_motion_driver_firmware(). This pushes the DMP image in
  784. * inv_mpu_dmp_motion_driver.h into the MPU memory.
  785. * 2. Push the gyro and accel orientation matrix to the DMP.
  786. * 3. Register gesture callbacks. Don't worry, these callbacks won't be
  787. * executed unless the corresponding feature is enabled.
  788. * 4. Call dmp_enable_feature(mask) to enable different features.
  789. * 5. Call dmp_set_fifo_rate(freq) to select a DMP output rate.
  790. * 6. Call any feature-specific control functions.
  791. *
  792. * To enable the DMP, just call mpu_set_dmp_state(1). This function can
  793. * be called repeatedly to enable and disable the DMP at runtime.
  794. *
  795. * The following is a short summary of the features supported in the DMP
  796. * image provided in inv_mpu_dmp_motion_driver.c:
  797. * DMP_FEATURE_LP_QUAT: Generate a gyro-only quaternion on the DMP at
  798. * 200Hz. Integrating the gyro data at higher rates reduces numerical
  799. * errors (compared to integration on the MCU at a lower sampling rate).
  800. * DMP_FEATURE_6X_LP_QUAT: Generate a gyro/accel quaternion on the DMP at
  801. * 200Hz. Cannot be used in combination with DMP_FEATURE_LP_QUAT.
  802. * DMP_FEATURE_TAP: Detect taps along the X, Y, and Z axes.
  803. * DMP_FEATURE_ANDROID_ORIENT: Google's screen rotation algorithm. Triggers
  804. * an event at the four orientations where the screen should rotate.
  805. * DMP_FEATURE_GYRO_CAL: Calibrates the gyro data after eight seconds of
  806. * no motion.
  807. * DMP_FEATURE_SEND_RAW_ACCEL: Add raw accelerometer data to the FIFO.
  808. * DMP_FEATURE_SEND_RAW_GYRO: Add raw gyro data to the FIFO.
  809. * DMP_FEATURE_SEND_CAL_GYRO: Add calibrated gyro data to the FIFO. Cannot
  810. * be used in combination with DMP_FEATURE_SEND_RAW_GYRO.
  811. */
  812. dmp_load_motion_driver_firmware();
  813. dmp_set_orientation(
  814. inv_orientation_matrix_to_scalar(gyro_pdata.orientation));
  815. dmp_register_tap_cb(tap_cb);
  816. dmp_register_android_orient_cb(android_orient_cb);
  817. /*
  818. * Known Bug -
  819. * DMP when enabled will sample sensor data at 200Hz and output to FIFO at the rate
  820. * specified in the dmp_set_fifo_rate API. The DMP will then sent an interrupt once
  821. * a sample has been put into the FIFO. Therefore if the dmp_set_fifo_rate is at 25Hz
  822. * there will be a 25Hz interrupt from the MPU device.
  823. *
  824. * There is a known issue in which if you do not enable DMP_FEATURE_TAP
  825. * then the interrupts will be at 200Hz even if fifo rate
  826. * is set at a different rate. To avoid this issue include the DMP_FEATURE_TAP
  827. *
  828. * DMP sensor fusion works only with gyro at +-2000dps and accel +-2G
  829. */
  830. hal.dmp_features = DMP_FEATURE_6X_LP_QUAT | DMP_FEATURE_TAP |
  831. DMP_FEATURE_ANDROID_ORIENT | DMP_FEATURE_SEND_RAW_ACCEL | DMP_FEATURE_SEND_CAL_GYRO |
  832. DMP_FEATURE_GYRO_CAL;
  833. dmp_enable_feature(hal.dmp_features);
  834. dmp_set_fifo_rate(DEFAULT_MPU_HZ);
  835. mpu_set_dmp_state(1);
  836. hal.dmp_on = 1;
  837. while(1){
  838. unsigned long sensor_timestamp;
  839. int new_data = 0;
  840. // if (USART_GetITStatus(USART2, USART_IT_RXNE)) {
  841. // /* A byte has been received via USART. See handle_input for a list of
  842. // * valid commands.
  843. // */
  844. // USART_ClearITPendingBit(USART2, USART_IT_RXNE);
  845. // handle_input();
  846. // }
  847. get_tick_count(&timestamp);
  848. // #ifdef COMPASS_ENABLED
  849. // /* We're not using a data ready interrupt for the compass, so we'll
  850. // * make our compass reads timer-based instead.
  851. // */
  852. // if ((timestamp > hal.next_compass_ms) && !hal.lp_accel_mode &&
  853. // hal.new_gyro && (hal.sensors & COMPASS_ON)) {
  854. // hal.next_compass_ms = timestamp + COMPASS_READ_MS;
  855. // new_compass = 1;
  856. // }
  857. // #endif
  858. /* Temperature data doesn't need to be read with every gyro sample.
  859. * Let's make them timer-based like the compass reads.
  860. */
  861. if (timestamp > hal.next_temp_ms) {
  862. hal.next_temp_ms = timestamp + TEMP_READ_MS;
  863. new_temp = 1;
  864. }
  865. if (hal.motion_int_mode) {
  866. /* Enable motion interrupt. */
  867. // mpu_lp_motion_interrupt(500, 1, 5);
  868. /* Notify the MPL that contiguity was broken. */
  869. inv_accel_was_turned_off();
  870. inv_gyro_was_turned_off();
  871. inv_compass_was_turned_off();
  872. inv_quaternion_sensor_was_turned_off();
  873. /* Wait for the MPU interrupt. */
  874. while (!hal.new_gyro) {}
  875. /* Restore the previous sensor configuration. */
  876. // mpu_lp_motion_interrupt(0, 0, 0);
  877. hal.motion_int_mode = 0;
  878. }
  879. // if (!hal.sensors || !hal.new_gyro) {
  880. // continue;
  881. // }
  882. if (hal.new_gyro && hal.lp_accel_mode) {
  883. short accel_short[3];
  884. long accel[3];
  885. mpu_get_accel_reg(accel_short, &sensor_timestamp);
  886. accel[0] = (long)accel_short[0];
  887. accel[1] = (long)accel_short[1];
  888. accel[2] = (long)accel_short[2];
  889. inv_build_accel(accel, 0, sensor_timestamp);
  890. new_data = 1;
  891. hal.new_gyro = 0;
  892. } else if (hal.new_gyro && hal.dmp_on) {
  893. short gyro[3], accel_short[3], sensors;
  894. unsigned char more;
  895. long accel[3], quat[4], temperature;
  896. /* This function gets new data from the FIFO when the DMP is in
  897. * use. The FIFO can contain any combination of gyro, accel,
  898. * quaternion, and gesture data. The sensors parameter tells the
  899. * caller which data fields were actually populated with new data.
  900. * For example, if sensors == (INV_XYZ_GYRO | INV_WXYZ_QUAT), then
  901. * the FIFO isn't being filled with accel data.
  902. * The driver parses the gesture data to determine if a gesture
  903. * event has occurred; on an event, the application will be notified
  904. * via a callback (assuming that a callback function was properly
  905. * registered). The more parameter is non-zero if there are
  906. * leftover packets in the FIFO.
  907. */
  908. dmp_read_fifo(gyro, accel_short, quat, &sensor_timestamp, &sensors, &more);
  909. if (!more)
  910. hal.new_gyro = 0;
  911. if (sensors & INV_XYZ_GYRO) {
  912. /* Push the new data to the MPL. */
  913. inv_build_gyro(gyro, sensor_timestamp);
  914. new_data = 1;
  915. if (new_temp) {
  916. new_temp = 0;
  917. /* Temperature only used for gyro temp comp. */
  918. mpu_get_temperature(&temperature, &sensor_timestamp);
  919. inv_build_temp(temperature, sensor_timestamp);
  920. }
  921. }
  922. if (sensors & INV_XYZ_ACCEL) {
  923. accel[0] = (long)accel_short[0];
  924. accel[1] = (long)accel_short[1];
  925. accel[2] = (long)accel_short[2];
  926. inv_build_accel(accel, 0, sensor_timestamp);
  927. new_data = 1;
  928. }
  929. if (sensors & INV_WXYZ_QUAT) {
  930. inv_build_quat(quat, 0, sensor_timestamp);
  931. new_data = 1;
  932. }
  933. } else if (hal.new_gyro) {
  934. short gyro[3], accel_short[3];
  935. unsigned char sensors, more;
  936. long accel[3], temperature;
  937. /* This function gets new data from the FIFO. The FIFO can contain
  938. * gyro, accel, both, or neither. The sensors parameter tells the
  939. * caller which data fields were actually populated with new data.
  940. * For example, if sensors == INV_XYZ_GYRO, then the FIFO isn't
  941. * being filled with accel data. The more parameter is non-zero if
  942. * there are leftover packets in the FIFO. The HAL can use this
  943. * information to increase the frequency at which this function is
  944. * called.
  945. */
  946. hal.new_gyro = 0;
  947. mpu_read_fifo(gyro, accel_short, &sensor_timestamp,
  948. &sensors, &more);
  949. if (more)
  950. hal.new_gyro = 1;
  951. if (sensors & INV_XYZ_GYRO) {
  952. /* Push the new data to the MPL. */
  953. inv_build_gyro(gyro, sensor_timestamp);
  954. new_data = 1;
  955. if (new_temp) {
  956. new_temp = 0;
  957. /* Temperature only used for gyro temp comp. */
  958. mpu_get_temperature(&temperature, &sensor_timestamp);
  959. inv_build_temp(temperature, sensor_timestamp);
  960. }
  961. }
  962. if (sensors & INV_XYZ_ACCEL) {
  963. accel[0] = (long)accel_short[0];
  964. accel[1] = (long)accel_short[1];
  965. accel[2] = (long)accel_short[2];
  966. inv_build_accel(accel, 0, sensor_timestamp);
  967. new_data = 1;
  968. }
  969. }
  970. #ifdef COMPASS_ENABLED
  971. if (new_compass) {
  972. short compass_short[3];
  973. long compass[3];
  974. new_compass = 0;
  975. /* For any MPU device with an AKM on the auxiliary I2C bus, the raw
  976. * magnetometer registers are copied to special gyro registers.
  977. */
  978. if (!mpu_get_compass_reg(compass_short, &sensor_timestamp)) {
  979. compass[0] = (long)compass_short[0];
  980. compass[1] = (long)compass_short[1];
  981. compass[2] = (long)compass_short[2];
  982. /* NOTE: If using a third-party compass calibration library,
  983. * pass in the compass data in uT * 2^16 and set the second
  984. * parameter to INV_CALIBRATED | acc, where acc is the
  985. * accuracy from 0 to 3.
  986. */
  987. inv_build_compass(compass, 0, sensor_timestamp);
  988. }
  989. new_data = 1;
  990. }
  991. #endif
  992. if (new_data) {
  993. inv_execute_on_data();
  994. /* This function reads bias-compensated sensor data and sensor
  995. * fusion outputs from the MPL. The outputs are formatted as seen
  996. * in eMPL_outputs.c. This function only needs to be called at the
  997. * rate requested by the host.
  998. */
  999. read_from_mpl();
  1000. }
  1001. rt_thread_mdelay(10);
  1002. }
  1003. // rt_mpu_deinit(dev);
  1004. }
  1005. int motion_driver_example(void)
  1006. {
  1007. rt_err_t ret = RT_EOK;
  1008. rt_thread_t thread = RT_NULL;
  1009. thread = rt_thread_create("motion_driver",
  1010. _motion_driver_example, RT_NULL,
  1011. 10*1024, 5, 10);
  1012. if(thread == RT_NULL)
  1013. {
  1014. return RT_ERROR;
  1015. }
  1016. rt_thread_startup(thread);
  1017. return RT_EOK;
  1018. }
  1019. MSH_CMD_EXPORT(motion_driver_example, motion driver test function);