AP_Baro_BMP388.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /*
  2. This program is free software: you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation, either version 3 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program. If not, see <http://www.gnu.org/licenses/>.
  12. */
  13. #include "AP_Baro_BMP388.h"
  14. #include <utility>
  15. extern const AP_HAL::HAL &hal;
  16. #define BMP388_MODE_SLEEP 0
  17. #define BMP388_MODE_FORCED 1
  18. #define BMP388_MODE_NORMAL 3
  19. #define BMP388_MODE BMP388_MODE_NORMAL
  20. #define BMP388_ID 0x50
  21. #define BMP388_REG_ID 0x00
  22. #define BMP388_REG_ERR 0x02
  23. #define BMP388_REG_STATUS 0x03
  24. #define BMP388_REG_PRESS 0x04 // 24 bit
  25. #define BMP388_REG_TEMP 0x07 // 24 bit
  26. #define BMP388_REG_TIME 0x0C // 24 bit
  27. #define BMP388_REG_EVENT 0x10
  28. #define BMP388_REG_INT_STS 0x11
  29. #define BMP388_REG_FIFO_LEN 0x12 // 9 bit
  30. #define BMP388_REG_FIFO_DATA 0x14
  31. #define BMP388_REG_FIFO_WTMK 0x15 // 9 bit
  32. #define BMP388_REG_FIFO_CNF1 0x17
  33. #define BMP388_REG_FIFO_CNF2 0x18
  34. #define BMP388_REG_INT_CTRL 0x19
  35. #define BMP388_REG_PWR_CTRL 0x1B
  36. #define BMP388_REG_OSR 0x1C
  37. #define BMP388_REG_ODR 0x1D
  38. #define BMP388_REG_CONFIG 0x1F
  39. #define BMP388_REG_CMD 0x7E
  40. #define BMP388_REG_CAL_P 0x36
  41. #define BMP388_REG_CAL_T 0x31
  42. AP_Baro_BMP388::AP_Baro_BMP388(AP_Baro &baro, AP_HAL::OwnPtr<AP_HAL::Device> _dev)
  43. : AP_Baro_Backend(baro)
  44. , dev(std::move(_dev))
  45. {
  46. }
  47. AP_Baro_Backend *AP_Baro_BMP388::probe(AP_Baro &baro,
  48. AP_HAL::OwnPtr<AP_HAL::Device> _dev)
  49. {
  50. if (!_dev) {
  51. return nullptr;
  52. }
  53. AP_Baro_BMP388 *sensor = new AP_Baro_BMP388(baro, std::move(_dev));
  54. if (!sensor || !sensor->init()) {
  55. delete sensor;
  56. return nullptr;
  57. }
  58. return sensor;
  59. }
  60. bool AP_Baro_BMP388::init()
  61. {
  62. if (!dev) {
  63. return false;
  64. }
  65. WITH_SEMAPHORE(dev->get_semaphore());
  66. has_sample = false;
  67. dev->set_speed(AP_HAL::Device::SPEED_HIGH);
  68. // setup to allow reads on SPI
  69. if (dev->bus_type() == AP_HAL::Device::BUS_TYPE_SPI) {
  70. dev->set_read_flag(0x80);
  71. }
  72. // normal mode, temp and pressure
  73. dev->write_register(BMP388_REG_PWR_CTRL, 0x33, true);
  74. uint8_t whoami;
  75. if (!dev->read_registers(BMP388_REG_ID, &whoami, 1) ||
  76. whoami != BMP388_ID) {
  77. // not a BMP388
  78. return false;
  79. }
  80. // read the calibration data
  81. dev->read_registers(BMP388_REG_CAL_P, (uint8_t *)&calib_p, sizeof(calib_p));
  82. dev->read_registers(BMP388_REG_CAL_T, (uint8_t *)&calib_t, sizeof(calib_t));
  83. scale_calibration_data();
  84. dev->setup_checked_registers(4);
  85. // normal mode, temp and pressure
  86. dev->write_register(BMP388_REG_PWR_CTRL, 0x33, true);
  87. instance = _frontend.register_sensor();
  88. // request 50Hz update
  89. dev->register_periodic_callback(20 * AP_USEC_PER_MSEC, FUNCTOR_BIND_MEMBER(&AP_Baro_BMP388::timer, void));
  90. return true;
  91. }
  92. // acumulate a new sensor reading
  93. void AP_Baro_BMP388::timer(void)
  94. {
  95. uint8_t buf[7];
  96. if (!dev->read_registers(BMP388_REG_STATUS, buf, sizeof(buf))) {
  97. return;
  98. }
  99. const uint8_t status = buf[0];
  100. if ((status & 0x20) != 0) {
  101. // we have pressure data
  102. update_pressure((buf[3] << 16) | (buf[2] << 8) | buf[1]);
  103. }
  104. if ((status & 0x40) != 0) {
  105. // we have temperature data
  106. update_temperature((buf[6] << 16) | (buf[5] << 8) | buf[4]);
  107. }
  108. dev->check_next_register();
  109. }
  110. // transfer data to the frontend
  111. void AP_Baro_BMP388::update(void)
  112. {
  113. WITH_SEMAPHORE(_sem);
  114. if (!has_sample) {
  115. return;
  116. }
  117. _copy_to_frontend(instance, pressure, temperature);
  118. has_sample = false;
  119. }
  120. /*
  121. convert calibration data from NVM values to values ready for
  122. compensation calculations
  123. */
  124. void AP_Baro_BMP388::scale_calibration_data(void)
  125. {
  126. // note that this assumes little-endian MCU
  127. calib.par_t1 = calib_t.nvm_par_t1 * 256.0;
  128. calib.par_t2 = calib_t.nvm_par_t2 / 1073741824.0f;
  129. calib.par_t3 = calib_t.nvm_par_t3 / 281474976710656.0f;
  130. calib.par_p1 = (calib_p.nvm_par_p1 - 16384) / 1048576.0f;
  131. calib.par_p2 = (calib_p.nvm_par_p2 - 16384) / 536870912.0f;
  132. calib.par_p3 = calib_p.nvm_par_p3 / 4294967296.0f;
  133. calib.par_p4 = calib_p.nvm_par_p4 / 137438953472.0;
  134. calib.par_p5 = calib_p.nvm_par_p5 * 8.0f;
  135. calib.par_p6 = calib_p.nvm_par_p6 / 64.0;
  136. calib.par_p7 = calib_p.nvm_par_p7 / 256.0f;
  137. calib.par_p8 = calib_p.nvm_par_p8 / 32768.0f;
  138. calib.par_p9 = calib_p.nvm_par_p9 / 281474976710656.0f;
  139. calib.par_p10 = calib_p.nvm_par_p10 / 281474976710656.0f;
  140. calib.par_p11 = calib_p.nvm_par_p11 / 36893488147419103232.0f;
  141. }
  142. /*
  143. update temperature from raw sample
  144. */
  145. void AP_Baro_BMP388::update_temperature(uint32_t data)
  146. {
  147. float partial1 = data - calib.par_t1;
  148. float partial2 = partial1 * calib.par_t2;
  149. WITH_SEMAPHORE(_sem);
  150. temperature = partial2 + sq(partial1) * calib.par_t3;
  151. }
  152. /*
  153. update pressure from raw pressure data
  154. */
  155. void AP_Baro_BMP388::update_pressure(uint32_t data)
  156. {
  157. float partial1 = calib.par_p6 * temperature;
  158. float partial2 = calib.par_p7 * powf(temperature, 2);
  159. float partial3 = calib.par_p8 * powf(temperature, 3);
  160. float partial_out1 = calib.par_p5 + partial1 + partial2 + partial3;
  161. partial1 = calib.par_p2 * temperature;
  162. partial2 = calib.par_p3 * powf(temperature, 2);
  163. partial3 = calib.par_p4 * powf(temperature, 3);
  164. float partial_out2 = data * (calib.par_p1 + partial1 + partial2 + partial3);
  165. partial1 = powf(data, 2);
  166. partial2 = calib.par_p9 + calib.par_p10 * temperature;
  167. partial3 = partial1 * partial2;
  168. float partial4 = partial3 + powf(data, 3) * calib.par_p11;
  169. float press = partial_out1 + partial_out2 + partial4;
  170. WITH_SEMAPHORE(_sem);
  171. pressure = press;
  172. has_sample = true;
  173. }