PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

282 lines
7.4KB

  1. #include "NXPMotionSense.h"
  2. #include "utility/NXPSensorRegisters.h"
  3. #include <util/crc16.h>
  4. #include <elapsedMillis.h>
  5. #define NXP_MOTION_CAL_EEADDR 60
  6. #define NXP_MOTION_CAL_SIZE 68
  7. bool NXPMotionSense::begin()
  8. {
  9. unsigned char buf[NXP_MOTION_CAL_SIZE];
  10. uint8_t i;
  11. uint16_t crc;
  12. Wire.begin();
  13. Wire.setClock(400000);
  14. memset(accel_mag_raw, 0, sizeof(accel_mag_raw));
  15. memset(gyro_raw, 0, sizeof(gyro_raw));
  16. //Serial.println("init hardware");
  17. while (!FXOS8700_begin()) {
  18. Serial.println("config error FXOS8700");
  19. delay(1000);
  20. }
  21. while (!FXAS21002_begin()) {
  22. Serial.println("config error FXAS21002");
  23. delay(1000);
  24. }
  25. while (!MPL3115_begin()) {
  26. Serial.println("config error MPL3115");
  27. delay(1000);
  28. }
  29. //Serial.println("init done");
  30. for (i=0; i < NXP_MOTION_CAL_SIZE; i++) {
  31. buf[i] = EEPROM.read(NXP_MOTION_CAL_EEADDR + i);
  32. }
  33. crc = 0xFFFF;
  34. for (i=0; i < NXP_MOTION_CAL_SIZE; i++) {
  35. crc = _crc16_update(crc, buf[i]);
  36. }
  37. if (crc == 0 && buf[0] == 117 && buf[1] == 84) {
  38. memcpy(cal, buf+2, sizeof(cal));
  39. } else {
  40. memset(cal, 0, sizeof(cal));
  41. cal[9] = 50.0f;
  42. }
  43. return true;
  44. }
  45. void NXPMotionSense::update()
  46. {
  47. static elapsedMillis msec;
  48. int32_t alt;
  49. if (FXOS8700_read(accel_mag_raw)) { // accel + mag
  50. //Serial.println("accel+mag");
  51. }
  52. if (MPL3115_read(&alt, &temperature_raw)) { // alt
  53. //Serial.println("alt");
  54. }
  55. if (FXAS21002_read(gyro_raw)) { // gyro
  56. //Serial.println("gyro");
  57. newdata = 1;
  58. }
  59. }
  60. static bool write_reg(uint8_t i2c, uint8_t addr, uint8_t val)
  61. {
  62. Wire.beginTransmission(i2c);
  63. Wire.write(addr);
  64. Wire.write(val);
  65. return Wire.endTransmission() == 0;
  66. }
  67. static bool read_regs(uint8_t i2c, uint8_t addr, uint8_t *data, uint8_t num)
  68. {
  69. Wire.beginTransmission(i2c);
  70. Wire.write(addr);
  71. if (Wire.endTransmission(false) != 0) return false;
  72. Wire.requestFrom(i2c, num);
  73. if (Wire.available() != num) return false;
  74. while (num > 0) {
  75. *data++ = Wire.read();
  76. num--;
  77. }
  78. return true;
  79. }
  80. static bool read_regs(uint8_t i2c, uint8_t *data, uint8_t num)
  81. {
  82. Wire.requestFrom(i2c, num);
  83. if (Wire.available() != num) return false;
  84. while (num > 0) {
  85. *data++ = Wire.read();
  86. num--;
  87. }
  88. return true;
  89. }
  90. bool NXPMotionSense::FXOS8700_begin()
  91. {
  92. const uint8_t i2c_addr=FXOS8700_I2C_ADDR0;
  93. uint8_t b;
  94. //Serial.println("FXOS8700_begin");
  95. // detect if chip is present
  96. if (!read_regs(i2c_addr, FXOS8700_WHO_AM_I, &b, 1)) return false;
  97. //Serial.printf("FXOS8700 ID = %02X\n", b);
  98. if (b != 0xC7) return false;
  99. // place into standby mode
  100. if (!write_reg(i2c_addr, FXOS8700_CTRL_REG1, 0)) return false;
  101. // configure magnetometer
  102. if (!write_reg(i2c_addr, FXOS8700_M_CTRL_REG1, 0x1F)) return false;
  103. if (!write_reg(i2c_addr, FXOS8700_M_CTRL_REG2, 0x20)) return false;
  104. // configure accelerometer
  105. if (!write_reg(i2c_addr, FXOS8700_XYZ_DATA_CFG, 0x01)) return false; // 4G range
  106. if (!write_reg(i2c_addr, FXOS8700_CTRL_REG2, 0x02)) return false; // hires
  107. if (!write_reg(i2c_addr, FXOS8700_CTRL_REG1, 0x15)) return false; // 100Hz A+M
  108. //Serial.println("FXOS8700 Configured");
  109. return true;
  110. }
  111. bool NXPMotionSense::FXOS8700_read(int16_t *data) // accel + mag
  112. {
  113. static elapsedMicros usec_since;
  114. static int32_t usec_history=5000;
  115. const uint8_t i2c_addr=FXOS8700_I2C_ADDR0;
  116. uint8_t buf[13];
  117. int32_t usec = usec_since;
  118. if (usec + 100 < usec_history) return false;
  119. if (!read_regs(i2c_addr, FXOS8700_STATUS, buf, 1)) return false;
  120. if (buf[0] == 0) return false;
  121. usec_since -= usec;
  122. int diff = (usec - usec_history) >> 3;
  123. if (diff < -15) diff = -15;
  124. else if (diff > 15) diff = 15;
  125. usec_history += diff;
  126. if (!read_regs(i2c_addr, FXOS8700_OUT_X_MSB, buf+1, 12)) return false;
  127. //if (!read_regs(i2c_addr, buf, 13)) return false;
  128. data[0] = (int16_t)((buf[1] << 8) | buf[2]);
  129. data[1] = (int16_t)((buf[3] << 8) | buf[4]);
  130. data[2] = (int16_t)((buf[5] << 8) | buf[6]);
  131. data[3] = (int16_t)((buf[7] << 8) | buf[8]);
  132. data[4] = (int16_t)((buf[9] << 8) | buf[10]);
  133. data[5] = (int16_t)((buf[11] << 8) | buf[12]);
  134. return true;
  135. }
  136. bool NXPMotionSense::FXAS21002_begin()
  137. {
  138. const uint8_t i2c_addr=FXAS21002_I2C_ADDR0;
  139. uint8_t b;
  140. if (!read_regs(i2c_addr, FXAS21002_WHO_AM_I, &b, 1)) return false;
  141. //Serial.printf("FXAS21002 ID = %02X\n", b);
  142. if (b != 0xD7) return false;
  143. // place into standby mode
  144. if (!write_reg(i2c_addr, FXAS21002_CTRL_REG1, 0)) return false;
  145. // switch to active mode, 100 Hz output rate
  146. if (!write_reg(i2c_addr, FXAS21002_CTRL_REG0, 0x00)) return false;
  147. if (!write_reg(i2c_addr, FXAS21002_CTRL_REG1, 0x0E)) return false;
  148. //Serial.println("FXAS21002 Configured");
  149. return true;
  150. }
  151. bool NXPMotionSense::FXAS21002_read(int16_t *data) // gyro
  152. {
  153. static elapsedMicros usec_since;
  154. static int32_t usec_history=10000;
  155. const uint8_t i2c_addr=FXAS21002_I2C_ADDR0;
  156. uint8_t buf[7];
  157. int32_t usec = usec_since;
  158. if (usec + 100 < usec_history) return false;
  159. if (!read_regs(i2c_addr, FXAS21002_STATUS, buf, 1)) return false;
  160. if (buf[0] == 0) return false;
  161. usec_since -= usec;
  162. int diff = (usec - usec_history) >> 3;
  163. if (diff < -15) diff = -15;
  164. else if (diff > 15) diff = 15;
  165. usec_history += diff;
  166. //Serial.println(usec);
  167. if (!read_regs(i2c_addr, FXAS21002_STATUS, buf, 7)) return false;
  168. //if (!read_regs(i2c_addr, buf, 7)) return false;
  169. data[0] = (int16_t)((buf[1] << 8) | buf[2]);
  170. data[1] = (int16_t)((buf[3] << 8) | buf[4]);
  171. data[2] = (int16_t)((buf[5] << 8) | buf[6]);
  172. return true;
  173. }
  174. bool NXPMotionSense::MPL3115_begin() // pressure
  175. {
  176. const uint8_t i2c_addr=MPL3115_I2C_ADDR;
  177. uint8_t b;
  178. if (!read_regs(i2c_addr, MPL3115_WHO_AM_I, &b, 1)) return false;
  179. //Serial.printf("MPL3115 ID = %02X\n", b);
  180. if (b != 0xC4) return false;
  181. // place into standby mode
  182. if (!write_reg(i2c_addr, MPL3115_CTRL_REG1, 0)) return false;
  183. // switch to active, altimeter mode, 512 ms measurement, polling mode
  184. if (!write_reg(i2c_addr, MPL3115_CTRL_REG1, 0xB9)) return false;
  185. // enable events
  186. if (!write_reg(i2c_addr, MPL3115_PT_DATA_CFG, 0x07)) return false;
  187. //Serial.println("MPL3115 Configured");
  188. return true;
  189. }
  190. bool NXPMotionSense::MPL3115_read(int32_t *altitude, int16_t *temperature)
  191. {
  192. static elapsedMicros usec_since;
  193. static int32_t usec_history=980000;
  194. const uint8_t i2c_addr=MPL3115_I2C_ADDR;
  195. uint8_t buf[6];
  196. int32_t usec = usec_since;
  197. if (usec + 500 < usec_history) return false;
  198. if (!read_regs(i2c_addr, FXAS21002_STATUS, buf, 1)) return false;
  199. if (buf[0] == 0) return false;
  200. if (!read_regs(i2c_addr, buf, 6)) return false;
  201. usec_since -= usec;
  202. int diff = (usec - usec_history) >> 3;
  203. if (diff < -1000) diff = -1000;
  204. else if (diff > 1000) diff = 1000;
  205. usec_history += diff;
  206. int32_t a = ((uint32_t)buf[1] << 12) | ((uint16_t)buf[2] << 4) | (buf[3] >> 4);
  207. if (a & 0x00080000) a |= 0xFFF00000;
  208. *altitude = a;
  209. *temperature = (int16_t)((buf[4] << 8) | buf[5]);
  210. //Serial.printf("%02X %d %d: ", buf[0], usec, usec_history);
  211. //Serial.printf("%6d,%6d", a, *temperature);
  212. //Serial.println();
  213. return true;
  214. }
  215. bool NXPMotionSense::writeCalibration(const void *data)
  216. {
  217. const uint8_t *p = (const uint8_t *)data;
  218. uint16_t crc;
  219. uint8_t i;
  220. if (p[0] != 117 || p[1] != 84) return false;
  221. crc = 0xFFFF;
  222. for (i=0; i < NXP_MOTION_CAL_SIZE; i++) {
  223. crc = _crc16_update(crc, p[i]);
  224. }
  225. if (crc != 0) return false;
  226. for (i=0; i < NXP_MOTION_CAL_SIZE; i++) {
  227. EEPROM.write(NXP_MOTION_CAL_EEADDR + i, p[i]);
  228. }
  229. for (i=0; i < NXP_MOTION_CAL_SIZE; i++) {
  230. if (EEPROM.read(NXP_MOTION_CAL_EEADDR + i) != p[i]) return false;
  231. }
  232. memcpy(cal, ((const uint8_t *)data)+2, sizeof(cal));
  233. return true;
  234. }