SP8EBC-ParaTNC/system/src/drivers/bme280.c

340 wiersze
8.6 KiB
C

/*
* bma150.c
*
* Created on: 21.06.2020
* Author: mateusz
*/
#include <drivers/bme280.h>
#include "../drivers/i2c.h"
#include <string.h>
#define RESET_MAGIC_WORD 0xB6
#define TX_ADDR 0xEC // 11101100
#define RX_ADDR 0xED // 11101101
#define MODE 3 // Normal aka 'cyclic' mode
#define FILTER_COEFFICIENT_LN 16
#define HUMIDITY_OVERSAMPLING 4 // oversampling x8
#define PRESSURE_OVERSAMPLING 3 // oversampling x4
#define TEMPERATURE_OVERSAMPLING 3 // oversampling x4
#define STANDBY_TIME 5 // one second
#define CTRL_HUM_ADDR 0xF2
#define STATUS_ADDR 0xF3
#define CTRL_MEAS_ADDR 0xF4
#define CONFIG_ADDR 0xF5
#define RESET_ADDR 0xE0
#define PRESS_MSB_ADDR 0xF7
#define VALUES_LN 8
#define CALIB00_ADDR 0x88
#define CALIB00_READ_LN 0x1A
#define CALIB26_ADDR 0xE1
#define CALIB26_READ_LN 0x10
uint8_t bme280_sensor_avaliable = 0;
uint8_t bme280_data_buffer[BME280_LN_RAW_DATA + 1];
uint8_t bme280_calibration_data[BME280_LN_CALIBRATION + 1];
int32_t t_fine = 0;
/**
* This function resets the BMA150 sensor to initial state. After it is called
* the sensor must be reconfigured once again.
*/
int32_t bme280_reset(bme280_qf_t* qf) {
int32_t out = BME280_OK;
// i2c transmit buffer
uint8_t tx_buf[] = {RESET_ADDR, RESET_MAGIC_WORD, 0};
// Send a data to sensor
i2c_send_data(TX_ADDR, tx_buf, 0);
// Wait until the transmission will finish or fail (due to timeout or any other error)
while (i2c_state != I2C_IDLE && i2c_state != I2C_ERROR);
// If reset was successfull enable a driver
if (i2c_state == I2C_IDLE) {
// Enable sensor comms
bme280_sensor_avaliable = 1;
// wait for sensor reset
delay_fixed(50);
}
else {
// Set Quality Factor to unavaliable
*qf = BME280_QF_NOT_AVAILABLE;
// Return with keeping 'ms5611_sensor_abaliable' set to zero which will
// disable comms
out = BME280_SENSOR_NOT_RESPONDING;
}
return out;
}
int32_t bme280_setup(void) {
int32_t out = BME280_OK;
// local variables to represent the data wrote to configuration registers
uint8_t ctrl_meas = 0;
uint8_t ctrl_hum = 0;
uint8_t config = 0;
if (bme280_sensor_avaliable == 0) {
return BME280_SENSOR_NOT_AVALIABLE;
}
// setting humidity measurement configutation
ctrl_hum = HUMIDITY_OVERSAMPLING;
// set mode, and oversampling for humidity and temperature
ctrl_meas = MODE | (PRESSURE_OVERSAMPLING << 2) | (TEMPERATURE_OVERSAMPLING << 5);
// set standby time and filter lenght
config = (FILTER_COEFFICIENT_LN << 2) | (STANDBY_TIME << 5);
// transmit buffer
uint8_t tx_buff[] = {CTRL_HUM_ADDR, ctrl_hum, CTRL_MEAS_ADDR, ctrl_meas, CONFIG_ADDR, config, 0};
// Send a data to sensor
i2c_send_data(TX_ADDR, tx_buff, 0);
// Wait until the transmission will finish or fail (due to timeout or any other error)
while (i2c_state != I2C_IDLE && i2c_state != I2C_ERROR);
// If reset was successfull enable a driver
if (i2c_state == I2C_IDLE) {
;
}
else {
out = BME280_SENSOR_NOT_RESPONDING;
}
return out;
}
int32_t bme280_read_calibration(uint8_t* calibration) {
int32_t out = BME280_OK;
if (bme280_sensor_avaliable == 0) {
return BME280_SENSOR_NOT_AVALIABLE;
}
// transmit buffer
uint8_t tx_buf[] = {CALIB00_ADDR, 0, 0};
// Send a data to sensor
i2c_send_data(TX_ADDR, tx_buf, 0);
// Wait until the transmission will finish or fail (due to timeout or any other error)
while (i2c_state != I2C_IDLE && i2c_state != I2C_ERROR);
// check if transmission was successfull
if (i2c_state == I2C_IDLE) {
;
}
else {
return BME280_SENSOR_NOT_RESPONDING;
}
// clearing receive buffer
memset(calibration, 0x00, BME280_LN_CALIBRATION);
// reading first segment of calibration data
i2c_receive_data(RX_ADDR, CALIB00_READ_LN);
// Wait until receiving will finish or fail (due to timeout or any other error)
while (i2c_state != I2C_IDLE && i2c_state != I2C_ERROR);
// check if receive was successfull
if (i2c_state == I2C_IDLE) {
;
}
else {
return BME280_SENSOR_NOT_RESPONDING;
}
// copying read data
memcpy(calibration, (uint8_t*)i2c_rx_data, CALIB00_READ_LN);
// preparing the buffer to receive second segment of calibration data
tx_buf[0] = CALIB26_ADDR;
// Send the second request to the sensor
i2c_send_data(TX_ADDR, tx_buf, 0);
// Wait until the transmission will finish or fail (due to timeout or any other error)
while (i2c_state != I2C_IDLE && i2c_state != I2C_ERROR);
// check if transmission was successfull
if (i2c_state == I2C_IDLE) {
;
}
else {
return BME280_SENSOR_NOT_RESPONDING;
}
// reading second segment of calibration data
i2c_receive_data(RX_ADDR, CALIB26_READ_LN);
// Wait until receiving will finish or fail (due to timeout or any other error)
while (i2c_state != I2C_IDLE && i2c_state != I2C_ERROR);
// check if receive was successfull
if (i2c_state == I2C_IDLE) {
;
}
else {
return BME280_SENSOR_NOT_RESPONDING;
}
// copying read data
memcpy(calibration + CALIB00_READ_LN, (uint8_t*)i2c_rx_data, CALIB26_READ_LN);
return out;
}
int32_t bme280_read_raw_data(uint8_t* raw_data) {
int32_t out = BME280_OK;
if (bme280_sensor_avaliable == 0) {
return BME280_SENSOR_NOT_AVALIABLE;
}
// transmit buffer
uint8_t tx_buf[] = {PRESS_MSB_ADDR, 0, 0};
// Send a data to sensor
i2c_send_data(TX_ADDR, tx_buf, 0);
// Wait until the transmission will finish or fail (due to timeout or any other error)
while (i2c_state != I2C_IDLE && i2c_state != I2C_ERROR);
// check if transmission was successfull
if (i2c_state == I2C_IDLE) {
;
}
else {
return BME280_SENSOR_NOT_RESPONDING;
}
// clearing receive buffer
memset(raw_data, 0x00, BME280_LN_RAW_DATA);
// reading first segment of calibration data
i2c_receive_data(RX_ADDR, BME280_LN_RAW_DATA);
// Wait until receiving will finish or fail (due to timeout or any other error)
while (i2c_state != I2C_IDLE && i2c_state != I2C_ERROR);
// check if receive was successfull
if (i2c_state == I2C_IDLE) {
;
}
else {
return BME280_SENSOR_NOT_RESPONDING;
}
// copying read data
memcpy(raw_data, (uint8_t*)i2c_rx_data, BME280_LN_RAW_DATA);
return out;
}
int32_t bme280_get_pressure(float* out, uint32_t raw_data, bme280_qf_t* qf) {
int32_t ret = BME280_OK;
int32_t var1, var2;
uint32_t p;
uint32_t adc_P = raw_data;
var1 = (((int32_t)t_fine)>>1) - (int32_t)64000;
var2 = (((var1>>2) * (var1>>2)) >> 11 ) * ((int32_t)bme280_get_dig_P6());
var2 = var2 + ((var1*((int32_t)bme280_get_dig_P5()))<<1);
var2 = (var2>>2)+(((int32_t)bme280_get_dig_P4())<<16);
var1 = (((bme280_get_dig_P3() * (((var1>>2) * (var1>>2)) >> 13 )) >> 3) + ((((int32_t)bme280_get_dig_P2()) * var1)>>1))>>18;
var1 =((((32768+var1))*((int32_t)bme280_get_dig_P1()))>>15);
if (var1 == 0)
{
*qf = BME280_QF_PRESSURE_DEGRADED;
return BME280_WRONG_PRESSURE_READOUT; // avoid exception caused by division by zero
}
p = (((uint32_t)(((int32_t)1048576)-adc_P)-(var2>>12)))*3125;
if (p < 0x80000000)
{
p = (p << 1) / ((uint32_t)var1);
}
else
{
p = (p / (uint32_t)var1) * 2;
}
var1 = (((int32_t)bme280_get_dig_P9()) * ((int32_t)(((p>>3) * (p>>3))>>13)))>>12;
var2 = (((int32_t)(p>>2)) * ((int32_t)bme280_get_dig_P8()))>>13;
p = (uint32_t)((int32_t)p + ((var1 + var2 + bme280_get_dig_P7()) >> 4));
*out = p / 100.0f;
return ret;
}
int32_t bme280_get_temperature(float* out, uint32_t raw_data, bme280_qf_t* qf) {
int32_t ret = BME280_OK;
uint32_t adc_T = raw_data;
int32_t var1, var2, T;
var1 = (((( adc_T >> 3 ) - ((int32_t)bme280_get_dig_T1() << 1))) * ((int32_t)bme280_get_dig_T2())) >> 11;
var2 = (((((adc_T >> 4 ) - ((int32_t)bme280_get_dig_T1())) * ((adc_T>>4) - ((int32_t)bme280_get_dig_T1()))) >> 12) * ((int32_t)bme280_get_dig_T3())) >> 14;
t_fine = var1 + var2;
T = (t_fine * 5 + 128) >> 8;
*out = (T / 100.0f);
return ret;
}
int32_t bme280_get_humidity(int8_t* out, uint16_t raw_data, bme280_qf_t* qf) {
int32_t ret = BME280_OK;
int32_t v_x1_u32r;
uint32_t val = 0;
int32_t adc_H = raw_data;
v_x1_u32r = (t_fine - ((int32_t)76800));
v_x1_u32r = (((((adc_H << 14) - (((int32_t)bme280_get_dig_H4()) << 20) - (((int32_t)bme280_get_dig_H5()) * v_x1_u32r)) +
((int32_t)16384)) >> 15) * (((((((v_x1_u32r * ((int32_t)bme280_get_dig_H6())) >> 10) * (((v_x1_u32r *
((int32_t)bme280_get_dig_H3())) >> 11) + ((int32_t)32768))) >> 10) + ((int32_t)2097152)) *
((int32_t)bme280_get_dig_H2()) + 8192) >> 14));
v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((int32_t)bme280_get_dig_H1())) >> 4));
v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
val = (uint32_t)(v_x1_u32r>>12);
*out = (val / 1024);
if (*out > 99 || *out < 0) {
*qf = BME280_QF_HUMIDITY_DEGRADED;
ret = BME280_WRONG_HUMIDITY_READOUT;
}
return ret;
}