BMP280.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /*
  2. Unitemp - Universal temperature reader
  3. Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n)
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #include "BMP280.h"
  16. const SensorType BMP280 = {
  17. .typename = "BMP280",
  18. .interface = &I2C,
  19. .datatype = UT_DATA_TYPE_TEMP_PRESS,
  20. .pollingInterval = 500,
  21. .allocator = unitemp_BMP280_alloc,
  22. .mem_releaser = unitemp_BMP280_free,
  23. .initializer = unitemp_BMP280_init,
  24. .deinitializer = unitemp_BMP280_deinit,
  25. .updater = unitemp_BMP280_update};
  26. //Интервал обновления калибровочных значений
  27. #define BMP280_CAL_UPDATE_INTERVAL 60000
  28. #define TEMP_CAL_START_ADDR 0x88
  29. #define PRESS_CAL_START_ADDR 0x8E
  30. #define BMP280_ID 0x58
  31. #define BMP280_REG_STATUS 0xF3
  32. #define BMP280_REG_CTRL_MEAS 0xF4
  33. #define BMP280_REG_CONFIG 0xF5
  34. //Преддескретизация температуры
  35. #define BMP280_TEMP_OVERSAMPLING_SKIP 0b00000000
  36. #define BMP280_TEMP_OVERSAMPLING_1 0b00100000
  37. #define BMP280_TEMP_OVERSAMPLING_2 0b01000000
  38. #define BMP280_TEMP_OVERSAMPLING_4 0b01100000
  39. #define BMP280_TEMP_OVERSAMPLING_8 0b10000000
  40. #define BMP280_TEMP_OVERSAMPLING_16 0b10100000
  41. //Преддескретизация давления
  42. #define BMP280_PRESS_OVERSAMPLING_SKIP 0b00000000
  43. #define BMP280_PRESS_OVERSAMPLING_1 0b00000100
  44. #define BMP280_PRESS_OVERSAMPLING_2 0b00001000
  45. #define BMP280_PRESS_OVERSAMPLING_4 0b00001100
  46. #define BMP280_PRESS_OVERSAMPLING_8 0b00010000
  47. #define BMP280_PRESS_OVERSAMPLING_16 0b00010100
  48. //Режимы работы датчика
  49. #define BMP280_MODE_SLEEP 0b00000000 //Спит и мало кушает
  50. #define BMP280_MODE_FORCED 0b00000001 //Обновляет значения 1 раз, после чего уходит в сон
  51. #define BMP280_MODE_NORMAL 0b00000011 //Регулярно обновляет значения
  52. //Период обновления в нормальном режиме
  53. #define BMP280_STANDBY_TIME_0_5 0b00000000
  54. #define BMP280_STANDBY_TIME_62_5 0b00100000
  55. #define BMP280_STANDBY_TIME_125 0b01000000
  56. #define BMP280_STANDBY_TIME_250 0b01100000
  57. #define BMP280_STANDBY_TIME_500 0b10000000
  58. #define BMP280_STANDBY_TIME_1000 0b10100000
  59. #define BMP280_STANDBY_TIME_2000 0b11000000
  60. #define BMP280_STANDBY_TIME_4000 0b11100000
  61. //Коэффициент фильтрации значений
  62. #define BMP280_FILTER_COEFF_1 0b00000000
  63. #define BMP280_FILTER_COEFF_2 0b00000100
  64. #define BMP280_FILTER_COEFF_4 0b00001000
  65. #define BMP280_FILTER_COEFF_8 0b00001100
  66. #define BMP280_FILTER_COEFF_16 0b00010000
  67. //Разрешить работу по SPI
  68. #define BMP280_SPI_3W_ENABLE 0b00000001
  69. #define BMP280_SPI_3W_DISABLE 0b00000000
  70. static float bmp280_compensate_T_float(I2CSensor* i2c_sensor, int32_t adc_T) {
  71. BMP280_instance* bmp280_instance = (BMP280_instance*)i2c_sensor->sensorInstance;
  72. int32_t var1, var2;
  73. var1 = ((((adc_T >> 3) - ((int32_t)bmp280_instance->temp_cal.dig_T1 << 1))) *
  74. ((int32_t)bmp280_instance->temp_cal.dig_T2)) >>
  75. 11;
  76. var2 = (((((adc_T >> 4) - ((int32_t)bmp280_instance->temp_cal.dig_T1)) *
  77. ((adc_T >> 4) - ((int32_t)bmp280_instance->temp_cal.dig_T1))) >>
  78. 12) *
  79. ((int32_t)bmp280_instance->temp_cal.dig_T3)) >>
  80. 14;
  81. bmp280_instance->t_fine = var1 + var2;
  82. return ((bmp280_instance->t_fine * 5 + 128) >> 8) / 100.0f;
  83. }
  84. static float bmp280_compensate_P_float(I2CSensor* i2c_sensor, int32_t adc_P) {
  85. BMP280_instance* bmp280_instance = (BMP280_instance*)i2c_sensor->sensorInstance;
  86. int32_t var1, var2;
  87. uint32_t p;
  88. var1 = (((int32_t)bmp280_instance->t_fine) >> 1) - (int32_t)64000;
  89. var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * ((int32_t)bmp280_instance->press_cal.dig_P6);
  90. var2 = var2 + ((var1 * ((int32_t)bmp280_instance->press_cal.dig_P5)) << 1);
  91. var2 = (var2 >> 2) + (((int32_t)bmp280_instance->press_cal.dig_P4) << 16);
  92. var1 = (((bmp280_instance->press_cal.dig_P3 * (((var1 >> 2) * (var1 >> 2)) >> 13)) >> 3) +
  93. ((((int32_t)bmp280_instance->press_cal.dig_P2) * var1) >> 1)) >>
  94. 18;
  95. var1 = ((((32768 + var1)) * ((int32_t)bmp280_instance->press_cal.dig_P1)) >> 15);
  96. if(var1 == 0) {
  97. return 0; // avoid exception caused by division by zero
  98. }
  99. p = (((uint32_t)(((int32_t)1048576) - adc_P) - (var2 >> 12))) * 3125;
  100. if(p < 0x80000000) {
  101. p = (p << 1) / ((uint32_t)var1);
  102. } else {
  103. p = (p / (uint32_t)var1) * 2;
  104. }
  105. var1 = (((int32_t)bmp280_instance->press_cal.dig_P9) *
  106. ((int32_t)(((p >> 3) * (p >> 3)) >> 13))) >>
  107. 12;
  108. var2 = (((int32_t)(p >> 2)) * ((int32_t)bmp280_instance->press_cal.dig_P8)) >> 13;
  109. p = (uint32_t)((int32_t)p + ((var1 + var2 + bmp280_instance->press_cal.dig_P7) >> 4));
  110. return p;
  111. }
  112. static bool bmp280_readCalValues(I2CSensor* i2c_sensor) {
  113. BMP280_instance* bmp280_instance = (BMP280_instance*)i2c_sensor->sensorInstance;
  114. if(!unitemp_i2c_readRegArray(
  115. i2c_sensor, TEMP_CAL_START_ADDR, 6, (uint8_t*)&bmp280_instance->temp_cal))
  116. return false;
  117. #ifdef UNITEMP_DEBUG
  118. FURI_LOG_D(
  119. APP_NAME,
  120. "Sensor BMP280 (0x%02X) calibration values: T1: %d, T2: %d, T3: %d",
  121. i2c_sensor->currentI2CAdr,
  122. bmp280_instance->temp_cal.dig_T1,
  123. bmp280_instance->temp_cal.dig_T2,
  124. bmp280_instance->temp_cal.dig_T3);
  125. #endif
  126. if(!unitemp_i2c_readRegArray(
  127. i2c_sensor, PRESS_CAL_START_ADDR, 18, (uint8_t*)&bmp280_instance->press_cal))
  128. return false;
  129. #ifdef UNITEMP_DEBUG
  130. FURI_LOG_D(
  131. APP_NAME,
  132. "Sensor BMP280 (0x%02X): P1-9: %d, %d, %d, %d, %d, %d, %d, %d, %d",
  133. i2c_sensor->currentI2CAdr,
  134. bmp280_instance->press_cal.dig_P1,
  135. bmp280_instance->press_cal.dig_P2,
  136. bmp280_instance->press_cal.dig_P3,
  137. bmp280_instance->press_cal.dig_P4,
  138. bmp280_instance->press_cal.dig_P5,
  139. bmp280_instance->press_cal.dig_P6,
  140. bmp280_instance->press_cal.dig_P7,
  141. bmp280_instance->press_cal.dig_P8,
  142. bmp280_instance->press_cal.dig_P9);
  143. #endif
  144. bmp280_instance->last_cal_update_time = furi_get_tick();
  145. return true;
  146. }
  147. static bool bmp280_isMeasuring(Sensor* sensor) {
  148. I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
  149. return (bool)((unitemp_i2c_readReg(i2c_sensor, BMP280_REG_STATUS) & 0x08) >> 3);
  150. }
  151. bool unitemp_BMP280_alloc(Sensor* sensor, char* args) {
  152. UNUSED(args);
  153. I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
  154. BMP280_instance* bmp280_instance = malloc(sizeof(BMP280_instance));
  155. if(bmp280_instance == NULL) {
  156. FURI_LOG_E(APP_NAME, "Failed to allocation sensor %s instance", sensor->name);
  157. return false;
  158. }
  159. i2c_sensor->sensorInstance = bmp280_instance;
  160. i2c_sensor->minI2CAdr = 0x76 << 1;
  161. i2c_sensor->maxI2CAdr = 0x77 << 1;
  162. return true;
  163. }
  164. bool unitemp_BMP280_init(Sensor* sensor) {
  165. I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
  166. //Перезагрузка
  167. unitemp_i2c_writeReg(i2c_sensor, 0xE0, 0xB6);
  168. //Чтение ID датчика
  169. uint8_t id = unitemp_i2c_readReg(i2c_sensor, 0xD0);
  170. if(id != BMP280_ID) {
  171. FURI_LOG_E(
  172. APP_NAME,
  173. "Sensor %s returned wrong ID 0x%02X, expected 0x%02X",
  174. sensor->name,
  175. id,
  176. BMP280_ID);
  177. return false;
  178. }
  179. //Чтение калибровочных значений
  180. if(!bmp280_readCalValues(i2c_sensor)) {
  181. FURI_LOG_E(APP_NAME, "Failed to read calibration values sensor %s", sensor->name);
  182. return false;
  183. }
  184. //Настройка режимов работы
  185. unitemp_i2c_writeReg(
  186. i2c_sensor,
  187. BMP280_REG_CTRL_MEAS,
  188. BMP280_TEMP_OVERSAMPLING_2 | BMP280_PRESS_OVERSAMPLING_4 | BMP280_MODE_NORMAL);
  189. //Настройка периода опроса и фильтрации значений
  190. unitemp_i2c_writeReg(
  191. i2c_sensor,
  192. BMP280_REG_CONFIG,
  193. BMP280_STANDBY_TIME_500 | BMP280_FILTER_COEFF_16 | BMP280_SPI_3W_DISABLE);
  194. return true;
  195. }
  196. bool unitemp_BMP280_deinit(Sensor* sensor) {
  197. I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
  198. //Перевод в сон
  199. unitemp_i2c_writeReg(i2c_sensor, BMP280_REG_CTRL_MEAS, BMP280_MODE_SLEEP);
  200. return true;
  201. }
  202. UnitempStatus unitemp_BMP280_update(Sensor* sensor) {
  203. I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
  204. BMP280_instance* instance = i2c_sensor->sensorInstance;
  205. uint32_t t = furi_get_tick();
  206. if(furi_get_tick() - instance->last_cal_update_time > BMP280_CAL_UPDATE_INTERVAL) {
  207. bmp280_readCalValues(i2c_sensor);
  208. }
  209. uint8_t buff[3];
  210. //Проверка инициализированности датчика
  211. unitemp_i2c_readRegArray(i2c_sensor, 0xF4, 2, buff);
  212. if(buff[0] == 0) {
  213. FURI_LOG_W(APP_NAME, "Sensor %s is not initialized!", sensor->name);
  214. return UT_SENSORSTATUS_ERROR;
  215. }
  216. while(bmp280_isMeasuring(sensor)) {
  217. if(furi_get_tick() - t > 100) {
  218. return UT_SENSORSTATUS_TIMEOUT;
  219. }
  220. }
  221. if(!unitemp_i2c_readRegArray(i2c_sensor, 0xFA, 3, buff)) return UT_SENSORSTATUS_TIMEOUT;
  222. int32_t adc_T = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4);
  223. if(!unitemp_i2c_readRegArray(i2c_sensor, 0xF7, 3, buff)) return UT_SENSORSTATUS_TIMEOUT;
  224. int32_t adc_P = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4);
  225. sensor->temp = bmp280_compensate_T_float(i2c_sensor, adc_T);
  226. sensor->pressure = bmp280_compensate_P_float(i2c_sensor, adc_P);
  227. return UT_SENSORSTATUS_OK;
  228. }
  229. bool unitemp_BMP280_free(Sensor* sensor) {
  230. I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
  231. free(i2c_sensor->sensorInstance);
  232. return true;
  233. }