bmp280.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /**
  2. * Ciastkolog.pl (https://github.com/ciastkolog)
  3. *
  4. */
  5. /**
  6. * The MIT License (MIT)
  7. *
  8. * Copyright (c) 2016 sheinz (https://github.com/sheinz)
  9. * Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in
  19. * all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. * THE SOFTWARE.
  28. */
  29. #include "bmp280.h"
  30. #include <stdio.h>
  31. #include <math.h>
  32. #include "iot_i2c.h"
  33. #include "iot_i2c_ex.h"
  34. /**
  35. * BMP280 registers
  36. */
  37. #define BMP280_REG_TEMP_XLSB 0xFC /* bits: 7-4 */
  38. #define BMP280_REG_TEMP_LSB 0xFB
  39. #define BMP280_REG_TEMP_MSB 0xFA
  40. #define BMP280_REG_TEMP (BMP280_REG_TEMP_MSB)
  41. #define BMP280_REG_PRESS_XLSB 0xF9 /* bits: 7-4 */
  42. #define BMP280_REG_PRESS_LSB 0xF8
  43. #define BMP280_REG_PRESS_MSB 0xF7
  44. #define BMP280_REG_PRESSURE (BMP280_REG_PRESS_MSB)
  45. #define BMP280_REG_CONFIG 0xF5 /* bits: 7-5 t_sb; 4-2 filter; 0 spi3w_en */
  46. #define BMP280_REG_CTRL 0xF4 /* bits: 7-5 osrs_t; 4-2 osrs_p; 1-0 mode */
  47. #define BMP280_REG_STATUS 0xF3 /* bits: 3 measuring; 0 im_update */
  48. #define BMP280_REG_RESET 0xE0
  49. #define BMP280_REG_ID 0xD0
  50. #define BMP280_REG_CALIB 0x88
  51. #define BMP280_RESET_VALUE 0xB6
  52. #define WIFI_IOT_I2C_IDX_1 1
  53. void bmp280_init_default_params(bmp280_params_t *params) {
  54. params->mode = BMP280_MODE_NORMAL;
  55. params->filter = BMP280_FILTER_OFF;
  56. params->oversampling_pressure = BMP280_STANDARD;
  57. params->oversampling_temperature = BMP280_STANDARD;
  58. params->standby = BMP280_STANDBY_250;
  59. }
  60. static uint8_t read_register16(uint8_t reg, uint16_t *value) {
  61. uint8_t rx_buff[2];
  62. uint32_t status = 0;
  63. IotI2cData bmp280_i2c_data = {0};
  64. uint8_t buffer[1] = {reg};
  65. bmp280_i2c_data.sendBuf = buffer;
  66. bmp280_i2c_data.sendLen = 1;
  67. bmp280_i2c_data.receiveBuf = rx_buff;
  68. bmp280_i2c_data.receiveLen = 2;
  69. status = IoTI2cWriteread(WIFI_IOT_I2C_IDX_1, (BMP280_I2C_ADDRESS_0<<1)|0x00, &bmp280_i2c_data);
  70. if (status != 0)
  71. {
  72. printf("===== Error: I2C write status = 0x%x! =====\r\n", status);
  73. return false;
  74. }
  75. *value = (uint16_t) ((rx_buff[1] << 8) | rx_buff[0]);
  76. return true;
  77. }
  78. static uint8_t read_data( uint8_t reg, uint8_t *value,uint8_t len) {
  79. uint32_t status = 0;
  80. IotI2cData bmp280_i2c_data = {0};
  81. uint8_t buffer[1] = {reg};
  82. bmp280_i2c_data.sendBuf = buffer;
  83. bmp280_i2c_data.sendLen = 1;
  84. bmp280_i2c_data.receiveBuf = value;
  85. bmp280_i2c_data.receiveLen = len;
  86. status = IoTI2cWriteread(WIFI_IOT_I2C_IDX_1, (BMP280_I2C_ADDRESS_0<<1)|0x00, &bmp280_i2c_data);
  87. if (status != 0)
  88. {
  89. printf("===== Error: I2C write status = 0x%x! =====\r\n", status);
  90. return 1;
  91. }
  92. return 0;
  93. }
  94. static bool read_calibration_data(BMP280_HandleTypedef *dev) {
  95. if (read_register16(0x88, &dev->dig_T1)
  96. && read_register16(0x8a, (uint16_t *) &dev->dig_T2)
  97. && read_register16(0x8c, (uint16_t *) &dev->dig_T3)
  98. && read_register16(0x8e, &dev->dig_P1)
  99. && read_register16(0x90, (uint16_t *) &dev->dig_P2)
  100. && read_register16(0x92, (uint16_t *) &dev->dig_P3)
  101. && read_register16(0x94, (uint16_t *) &dev->dig_P4)
  102. && read_register16(0x96, (uint16_t *) &dev->dig_P5)
  103. && read_register16(0x98, (uint16_t *) &dev->dig_P6)
  104. && read_register16(0x9a, (uint16_t *) &dev->dig_P7)
  105. && read_register16(0x9c, (uint16_t *) &dev->dig_P8)
  106. && read_register16(0x9e,(uint16_t *) &dev->dig_P9)) {
  107. return true;
  108. }
  109. return false;
  110. }
  111. static int write_register8(uint8_t reg, uint8_t value) {
  112. uint32_t status = 0;
  113. uint8_t send_data[2] = { reg,value };
  114. status = IoTI2cWrite(WIFI_IOT_I2C_IDX_1,(BMP280_I2C_ADDRESS_0<<1)|0x00,send_data,2);
  115. if (status != 0)
  116. {
  117. printf("===== Error: I2C write status = 0x%x! =====\r\n", status);
  118. return status;
  119. }
  120. return 0;
  121. }
  122. bool bmp280_init(BMP280_HandleTypedef *dev, bmp280_params_t *params) {
  123. if (read_data(BMP280_REG_ID, &dev->id, 1)) {
  124. return false;
  125. }
  126. if (dev->id != BMP280_CHIP_ID && dev->id != BME280_CHIP_ID) {
  127. return false;
  128. }
  129. // Soft reset.
  130. if (write_register8(BMP280_REG_RESET, BMP280_RESET_VALUE)) {
  131. return false;
  132. }
  133. // Wait until finished copying over the NVP data.
  134. while (1) {
  135. uint8_t status;
  136. if (!read_data(BMP280_REG_STATUS, &status, 1)
  137. && (status & 1) == 0)
  138. break;
  139. }
  140. if (!read_calibration_data(dev)) {
  141. return false;
  142. }
  143. uint8_t config = (params->standby << 5) | (params->filter << 2);
  144. if (write_register8(BMP280_REG_CONFIG, config)) {
  145. return false;
  146. }
  147. if (params->mode == BMP280_MODE_FORCED) {
  148. params->mode = BMP280_MODE_SLEEP; // initial mode for forced is sleep
  149. }
  150. uint8_t ctrl = (params->oversampling_temperature << 5)
  151. | (params->oversampling_pressure << 2) | (params->mode);
  152. if (write_register8(BMP280_REG_CTRL, ctrl)) {
  153. return false;
  154. }
  155. return true;
  156. }
  157. bool bmp280_force_measurement(void) {
  158. uint8_t ctrl;
  159. if (read_data(BMP280_REG_CTRL, &ctrl, 1))
  160. return false;
  161. ctrl &= ~0b11; // clear two lower bits
  162. ctrl |= BMP280_MODE_FORCED;
  163. if (write_register8(BMP280_REG_CTRL, ctrl)) {
  164. return false;
  165. }
  166. return true;
  167. }
  168. bool bmp280_is_measuring(void) {
  169. uint8_t status;
  170. if (read_data(BMP280_REG_STATUS, &status, 1))
  171. return false;
  172. if (status & (1 << 3)) {
  173. return true;
  174. }
  175. return false;
  176. }
  177. /**
  178. * Compensation algorithm is taken from BMP280 datasheet.
  179. *
  180. * Return value is in degrees Celsius.
  181. */
  182. static inline int32_t compensate_temperature(BMP280_HandleTypedef *dev, int32_t adc_temp,
  183. int32_t *fine_temp) {
  184. int32_t var1, var2;
  185. var1 = ((((adc_temp >> 3) - ((int32_t) dev->dig_T1 << 1)))
  186. * (int32_t) dev->dig_T2) >> 11;
  187. var2 = (((((adc_temp >> 4) - (int32_t) dev->dig_T1)
  188. * ((adc_temp >> 4) - (int32_t) dev->dig_T1)) >> 12)
  189. * (int32_t) dev->dig_T3) >> 14;
  190. *fine_temp = var1 + var2;
  191. return (*fine_temp * 5 + 128) >> 8;
  192. }
  193. /**
  194. * Compensation algorithm is taken from BMP280 datasheet.
  195. *
  196. * Return value is in Pa, 24 integer bits and 8 fractional bits.
  197. */
  198. static inline uint32_t compensate_pressure(BMP280_HandleTypedef *dev, int32_t adc_press,
  199. int32_t fine_temp) {
  200. int64_t var1, var2, p;
  201. var1 = (int64_t) fine_temp - 128000;
  202. var2 = var1 * var1 * (int64_t) dev->dig_P6;
  203. var2 = var2 + ((var1 * (int64_t) dev->dig_P5) << 17);
  204. var2 = var2 + (((int64_t) dev->dig_P4) << 35);
  205. var1 = ((var1 * var1 * (int64_t) dev->dig_P3) >> 8)
  206. + ((var1 * (int64_t) dev->dig_P2) << 12);
  207. var1 = (((int64_t) 1 << 47) + var1) * ((int64_t) dev->dig_P1) >> 33;
  208. if (var1 == 0) {
  209. return 0; // avoid exception caused by division by zero
  210. }
  211. p = 1048576 - adc_press;
  212. p = (((p << 31) - var2) * 3125) / var1;
  213. var1 = ((int64_t) dev->dig_P9 * (p >> 13) * (p >> 13)) >> 25;
  214. var2 = ((int64_t) dev->dig_P8 * p) >> 19;
  215. p = ((p + var1 + var2) >> 8) + ((int64_t) dev->dig_P7 << 4);
  216. return p;
  217. }
  218. #define CONST_PF 0.1902630958 //(1/5.25588f) Pressure factor
  219. #define FIX_TEMP 25 // Fixed Temperature. ASL is a function of pressure and temperature, but as the temperature changes so much (blow a little towards the flie and watch it drop 5 degrees) it corrupts the ASL estimates.
  220. // TLDR: Adjusting for temp changes does more harm than good.
  221. /*
  222. * Converts pressure to altitude above sea level (ASL) in meters
  223. */
  224. static float bme280PressureToAltitude(float* pressure/*, float* groundPressure, float* groundTemp*/)
  225. {
  226. if (*pressure>0)
  227. {
  228. return((1.0f-pow((*pressure/1010),CONST_PF))*(25+273.15f))/0.0065f;
  229. }
  230. else
  231. {
  232. return 0;
  233. }
  234. }
  235. bool bmp280_read_fixed(BMP280_HandleTypedef *dev, int32_t *temperature, uint32_t *pressure) {
  236. int32_t adc_pressure;
  237. int32_t adc_temp;
  238. uint8_t data[8];
  239. // Need to read in one sequence to ensure they match.
  240. size_t size = 6;
  241. if (read_data(0xf7, data, size)) {
  242. return false;
  243. }
  244. adc_pressure = data[0] << 12 | data[1] << 4 | data[2] >> 4;
  245. adc_temp = data[3] << 12 | data[4] << 4 | data[5] >> 4;
  246. int32_t fine_temp;
  247. *temperature = compensate_temperature(dev, adc_temp, &fine_temp);
  248. *pressure = compensate_pressure(dev, adc_pressure, fine_temp);
  249. return true;
  250. }
  251. bool bmp280_read_float(BMP280_HandleTypedef *dev, float *temperature, float *pressure, float* asl) {
  252. int32_t fixed_temperature;
  253. uint32_t fixed_pressure;
  254. if (bmp280_read_fixed(dev, &fixed_temperature, &fixed_pressure)) {
  255. *temperature = (float) fixed_temperature / 100;
  256. *pressure = (float) fixed_pressure / 25600;
  257. *asl = (float)bme280PressureToAltitude(pressure);
  258. return true;
  259. }
  260. return false;
  261. }