AP_Baro_FBM320.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. /*
  14. FCM320 barometer driver
  15. */
  16. #include "AP_Baro_FBM320.h"
  17. #include <utility>
  18. #include <stdio.h>
  19. extern const AP_HAL::HAL &hal;
  20. #define FBM320_REG_ID 0x6B
  21. #define FBM320_REG_DATA 0xF6
  22. #define FBM320_REG_CMD 0xF4
  23. #define FBM320_CMD_READ_T 0x2E
  24. #define FBM320_CMD_READ_P 0xF4
  25. #define FBM320_WHOAMI 0x42
  26. AP_Baro_FBM320::AP_Baro_FBM320(AP_Baro &baro, AP_HAL::OwnPtr<AP_HAL::Device> _dev)
  27. : AP_Baro_Backend(baro)
  28. , dev(std::move(_dev))
  29. {
  30. }
  31. AP_Baro_Backend *AP_Baro_FBM320::probe(AP_Baro &baro,
  32. AP_HAL::OwnPtr<AP_HAL::Device> _dev)
  33. {
  34. if (!_dev) {
  35. return nullptr;
  36. }
  37. AP_Baro_FBM320 *sensor = new AP_Baro_FBM320(baro, std::move(_dev));
  38. if (!sensor || !sensor->init()) {
  39. delete sensor;
  40. return nullptr;
  41. }
  42. return sensor;
  43. }
  44. /*
  45. read calibration data
  46. */
  47. bool AP_Baro_FBM320::read_calibration(void)
  48. {
  49. uint8_t tmp[2];
  50. uint16_t R[10];
  51. for (uint8_t i=0; i<9; i++) {
  52. if (!dev->read_registers(0xAA+(i*2),&tmp[0],1)) {
  53. return false;
  54. }
  55. if (!dev->read_registers(0xAB+(i*2),&tmp[1],1)) {
  56. return false;
  57. }
  58. R[i] = ((uint8_t)tmp[0] << 8 | tmp[1]);
  59. }
  60. if (!dev->read_registers(0xA4,&tmp[0],1)) {
  61. return false;
  62. }
  63. if (!dev->read_registers(0xF1,&tmp[0],1)) {
  64. return false;
  65. }
  66. R[9] = ((uint8_t)tmp[0] << 8) | tmp[1];
  67. /* Use R0~R9 calculate C0~C12 of FBM320-02 */
  68. calibration.C0 = R[0] >> 4;
  69. calibration.C1 = ((R[1] & 0xFF00) >> 5) | (R[2] & 7);
  70. calibration.C2 = ((R[1] & 0xFF) << 1) | (R[4] & 1);
  71. calibration.C3 = R[2] >> 3;
  72. calibration.C4 = ((uint32_t)R[3] << 2) | (R[0] & 3);
  73. calibration.C5 = R[4] >> 1;
  74. calibration.C6 = R[5] >> 3;
  75. calibration.C7 = ((uint32_t)R[6] << 3) | (R[5] & 7);
  76. calibration.C8 = R[7] >> 3;
  77. calibration.C9 = R[8] >> 2;
  78. calibration.C10 = ((R[9] & 0xFF00) >> 6) | (R[8] & 3);
  79. calibration.C11 = R[9] & 0xFF;
  80. calibration.C12 = ((R[0] & 0x0C) << 1) | (R[7] & 7);
  81. return true;
  82. }
  83. bool AP_Baro_FBM320::init()
  84. {
  85. if (!dev || !dev->get_semaphore()->take(HAL_SEMAPHORE_BLOCK_FOREVER)) {
  86. return false;
  87. }
  88. dev->set_speed(AP_HAL::Device::SPEED_HIGH);
  89. uint8_t whoami;
  90. if (!dev->read_registers(FBM320_REG_ID, &whoami, 1) ||
  91. whoami != FBM320_WHOAMI) {
  92. // not a FBM320
  93. dev->get_semaphore()->give();
  94. return false;
  95. }
  96. printf("FBM320 ID 0x%x\n", whoami);
  97. if (!read_calibration()) {
  98. dev->get_semaphore()->give();
  99. return false;
  100. }
  101. dev->write_register(FBM320_REG_CMD, FBM320_CMD_READ_T);
  102. instance = _frontend.register_sensor();
  103. dev->get_semaphore()->give();
  104. // request 50Hz update
  105. dev->register_periodic_callback(20 * AP_USEC_PER_MSEC, FUNCTOR_BIND_MEMBER(&AP_Baro_FBM320::timer, void));
  106. return true;
  107. }
  108. /*
  109. calculate corrected pressure and temperature
  110. */
  111. void AP_Baro_FBM320::calculate_PT(int32_t UT, int32_t UP, int32_t &pressure, int32_t &temperature)
  112. {
  113. const struct fbm320_calibration &cal = calibration;
  114. int32_t DT, DT2, X01, X02, X03, X11, X12, X13, X21, X22, X23, X24, X25, X26, X31, X32, CF, PP1, PP2, PP3, PP4;
  115. DT = ((UT - 8388608) >> 4) + (cal.C0 << 4);
  116. X01 = (cal.C1 + 4459) * DT >> 1;
  117. X02 = ((((cal.C2 - 256) * DT) >> 14) * DT) >> 4;
  118. X03 = (((((cal.C3 * DT) >> 18) * DT) >> 18) * DT);
  119. temperature = ((2500 << 15) - X01 - X02 - X03) >> 15;
  120. DT2 = (X01 + X02 + X03) >> 12;
  121. X11 = ((cal.C5 - 4443) * DT2);
  122. X12 = (((cal.C6 * DT2) >> 16) * DT2) >> 2;
  123. X13 = ((X11 + X12) >> 10) + ((cal.C4 + 120586) << 4);
  124. X21 = ((cal.C8 + 7180) * DT2) >> 10;
  125. X22 = (((cal.C9 * DT2) >> 17) * DT2) >> 12;
  126. X23 = (X22 >= X21) ? (X22 - X21) : (X21 - X22);
  127. X24 = (X23 >> 11) * (cal.C7 + 166426);
  128. X25 = ((X23 & 0x7FF) * (cal.C7 + 166426)) >> 11;
  129. X26 = (X21 >= X22) ? (((0 - X24 - X25) >> 11) + cal.C7 + 166426) : (((X24 + X25) >> 11) + cal.C7 + 166426);
  130. PP1 = ((UP - 8388608) - X13) >> 3;
  131. PP2 = (X26 >> 11) * PP1;
  132. PP3 = ((X26 & 0x7FF) * PP1) >> 11;
  133. PP4 = (PP2 + PP3) >> 10;
  134. CF = (2097152 + cal.C12 * DT2) >> 3;
  135. X31 = (((CF * cal.C10) >> 17) * PP4) >> 2;
  136. X32 = (((((CF * cal.C11) >> 15) * PP4) >> 18) * PP4);
  137. pressure = ((X31 + X32) >> 15) + PP4 + 99880;
  138. }
  139. // acumulate a new sensor reading
  140. void AP_Baro_FBM320::timer(void)
  141. {
  142. uint8_t buf[3];
  143. if (!dev->read_registers(0xF6, buf, sizeof(buf))) {
  144. return;
  145. }
  146. int32_t value = ((uint32_t)buf[0] << 16) | ((uint32_t)buf[1] << 8) | (uint32_t)buf[2];
  147. if (step == 0) {
  148. value_T = value;
  149. } else {
  150. int32_t pressure, temperature;
  151. calculate_PT(value_T, value, pressure, temperature);
  152. if (pressure_ok(pressure)) {
  153. WITH_SEMAPHORE(_sem);
  154. pressure_sum += pressure;
  155. // sum and convert to degrees
  156. temperature_sum += temperature*0.01;
  157. count++;
  158. }
  159. }
  160. if (step++ >= 5) {
  161. dev->write_register(FBM320_REG_CMD, FBM320_CMD_READ_T);
  162. step = 0;
  163. } else {
  164. dev->write_register(FBM320_REG_CMD, FBM320_CMD_READ_P);
  165. }
  166. }
  167. // transfer data to the frontend
  168. void AP_Baro_FBM320::update(void)
  169. {
  170. if (count == 0) {
  171. return;
  172. }
  173. WITH_SEMAPHORE(_sem);
  174. _copy_to_frontend(instance, pressure_sum/count, temperature_sum/count);
  175. pressure_sum = 0;
  176. temperature_sum = 0;
  177. count=0;
  178. }