2022-10-08 20:50:08 +02:00
|
|
|
#include <libopencm3/stm32/i2c.h>
|
|
|
|
#include <libopencm3/stm32/gpio.h>
|
|
|
|
|
2022-10-15 20:49:31 +02:00
|
|
|
#include "i2c_dma.h"
|
|
|
|
|
2022-10-08 20:50:08 +02:00
|
|
|
#include "pinout.h"
|
|
|
|
|
|
|
|
#include "bmp280_comp.h"
|
|
|
|
#include "bmp280.h"
|
|
|
|
|
|
|
|
#define BMP280_7BIT_ADDR 0x76
|
|
|
|
|
2022-10-15 20:49:31 +02:00
|
|
|
typedef enum {
|
|
|
|
READY,
|
|
|
|
SEND_REQUEST,
|
|
|
|
WAIT_MEASUREMENT_COMPLETE,
|
|
|
|
READ_RESULTS,
|
|
|
|
COMPENSATE_TEMPERATURE,
|
2022-11-09 20:47:13 +01:00
|
|
|
COMPENSATE_PRESSURE,
|
|
|
|
ERROR // set by the I²C callback in case of errors/timeout
|
2022-10-15 20:49:31 +02:00
|
|
|
} bmp280_readout_state_t;
|
|
|
|
|
|
|
|
static bmp280_readout_state_t m_readout_state;
|
|
|
|
|
2022-10-08 20:50:08 +02:00
|
|
|
// calibration value cache, shared with bmp280_comp.c
|
|
|
|
|
|
|
|
extern uint16_t dig_T1;
|
|
|
|
extern int16_t dig_T2;
|
|
|
|
extern int16_t dig_T3;
|
|
|
|
|
|
|
|
extern uint16_t dig_P1;
|
|
|
|
extern int16_t dig_P2;
|
|
|
|
extern int16_t dig_P3;
|
|
|
|
extern int16_t dig_P4;
|
|
|
|
extern int16_t dig_P5;
|
|
|
|
extern int16_t dig_P6;
|
|
|
|
extern int16_t dig_P7;
|
|
|
|
extern int16_t dig_P8;
|
|
|
|
extern int16_t dig_P9;
|
|
|
|
|
|
|
|
static fxp_t m_last_temperature = 0;
|
|
|
|
static fxp_t m_last_pressure = 0;
|
2022-10-15 21:41:50 +02:00
|
|
|
static bool m_measurements_valid = false;
|
2022-10-08 20:50:08 +02:00
|
|
|
|
2022-10-15 20:49:31 +02:00
|
|
|
static int32_t m_temp_raw;
|
|
|
|
static int32_t m_press_raw;
|
|
|
|
|
|
|
|
|
2022-11-09 20:47:13 +01:00
|
|
|
static void cb_i2c_dma(i2c_dma_evt_t evt, const uint8_t *rdata, size_t rlen);
|
2022-10-15 20:49:31 +02:00
|
|
|
|
|
|
|
|
2022-10-08 20:50:08 +02:00
|
|
|
bool bmp280_init(void)
|
|
|
|
{
|
2022-10-15 21:41:50 +02:00
|
|
|
m_measurements_valid = false;
|
|
|
|
|
2022-10-08 20:50:08 +02:00
|
|
|
// configure pins for I2C1
|
|
|
|
gpio_set_af(BMP280_I2C_PORT, GPIO_AF4, BMP280_I2C_SCL | BMP280_I2C_SDA);
|
|
|
|
gpio_mode_setup(BMP280_I2C_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BMP280_I2C_SCL | BMP280_I2C_SDA);
|
|
|
|
|
|
|
|
// Set up I²C
|
|
|
|
i2c_reset(I2C1);
|
|
|
|
|
|
|
|
i2c_set_speed(I2C1, i2c_speed_sm_100k, 48);
|
|
|
|
|
|
|
|
i2c_peripheral_enable(I2C1);
|
|
|
|
|
|
|
|
// Set up the Chip
|
|
|
|
uint8_t wdata[2];
|
|
|
|
uint8_t rdata[32];
|
|
|
|
uint8_t wsize, rsize;
|
|
|
|
|
2022-10-08 21:48:43 +02:00
|
|
|
// check for chip presence by accessing the chip id register (not a proper read!)
|
|
|
|
i2c_set_7bit_address(I2C1, BMP280_7BIT_ADDR);
|
|
|
|
i2c_set_write_transfer_dir(I2C1);
|
|
|
|
i2c_set_bytes_to_transfer(I2C1, 1);
|
|
|
|
i2c_enable_autoend(I2C1);
|
|
|
|
i2c_send_start(I2C1);
|
|
|
|
|
|
|
|
uint32_t timeout = 1000000;
|
|
|
|
while(--timeout && !i2c_transmit_int_status(I2C1)); // wait for the address transfer to complete
|
|
|
|
|
|
|
|
i2c_send_data(I2C1, 0xD0);
|
|
|
|
|
|
|
|
if((timeout == 0) || i2c_nack(I2C1)) {
|
|
|
|
// something went wrong during communication
|
|
|
|
goto err_out;
|
|
|
|
}
|
|
|
|
|
2022-10-08 20:50:08 +02:00
|
|
|
// read the chip ID
|
|
|
|
wsize = 0;
|
|
|
|
wdata[wsize++] = 0xD0;
|
|
|
|
rsize = 1;
|
|
|
|
|
|
|
|
i2c_transfer7(I2C1, BMP280_7BIT_ADDR, wdata, wsize, rdata, rsize);
|
|
|
|
|
|
|
|
if(rdata[0] != 0x58) {
|
|
|
|
// unexpected chip id
|
|
|
|
goto err_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read calibration data
|
|
|
|
wsize = 0;
|
|
|
|
wdata[wsize++] = 0x88; // first calibration data register of first block
|
|
|
|
rsize = 0xA1 + 1 - 0x88;
|
|
|
|
|
|
|
|
i2c_transfer7(I2C1, BMP280_7BIT_ADDR, wdata, wsize, rdata, rsize);
|
|
|
|
|
|
|
|
dig_T1 = (((uint16_t)rdata[ 1]) << 8) | rdata[ 0]; // 0x88, 0x89
|
|
|
|
dig_T2 = (((int16_t)(int8_t)rdata[ 3]) << 8) | rdata[ 2]; // 0x8A, 0x8B
|
|
|
|
dig_T3 = (((int16_t)(int8_t)rdata[ 5]) << 8) | rdata[ 4]; // 0x8C, 0x8D
|
|
|
|
|
|
|
|
dig_P1 = (((uint16_t)rdata[ 7]) << 8) | rdata[ 6]; // 0x8E, 0x8F
|
|
|
|
dig_P2 = (((int16_t)(int8_t)rdata[ 9]) << 8) | rdata[ 8]; // 0x90, 0x91
|
|
|
|
dig_P3 = (((int16_t)(int8_t)rdata[11]) << 8) | rdata[10]; // 0x92, 0x93
|
|
|
|
dig_P4 = (((int16_t)(int8_t)rdata[13]) << 8) | rdata[12]; // 0x94, 0x95
|
|
|
|
dig_P5 = (((int16_t)(int8_t)rdata[15]) << 8) | rdata[14]; // 0x96, 0x97
|
|
|
|
dig_P6 = (((int16_t)(int8_t)rdata[17]) << 8) | rdata[16]; // 0x98, 0x99
|
|
|
|
dig_P7 = (((int16_t)(int8_t)rdata[19]) << 8) | rdata[18]; // 0x9A, 0x9B
|
|
|
|
dig_P8 = (((int16_t)(int8_t)rdata[21]) << 8) | rdata[20]; // 0x9C, 0x9D
|
|
|
|
dig_P9 = (((int16_t)(int8_t)rdata[23]) << 8) | rdata[22]; // 0x9E, 0x9F
|
|
|
|
|
2022-10-15 20:49:31 +02:00
|
|
|
i2c_dma_init(cb_i2c_dma);
|
|
|
|
|
2022-10-08 20:50:08 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
err_out:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-15 20:49:31 +02:00
|
|
|
static void trigger_read_status_register(void)
|
2022-10-08 20:50:08 +02:00
|
|
|
{
|
2022-10-15 20:49:31 +02:00
|
|
|
uint8_t wdata[1];
|
|
|
|
uint8_t wsize = 0, rsize;
|
2022-10-08 20:50:08 +02:00
|
|
|
|
2022-10-15 20:49:31 +02:00
|
|
|
wdata[wsize++] = 0xF3; // status register
|
|
|
|
rsize = 1;
|
2022-10-08 20:50:08 +02:00
|
|
|
|
2022-10-15 20:49:31 +02:00
|
|
|
i2c_dma_start_transfer7(I2C1, BMP280_7BIT_ADDR, wdata, wsize, rsize);
|
2022-10-08 20:50:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-15 20:49:31 +02:00
|
|
|
static void trigger_read_results(void)
|
2022-10-08 20:50:08 +02:00
|
|
|
{
|
|
|
|
uint8_t wdata[1];
|
|
|
|
uint8_t wsize = 0, rsize;
|
|
|
|
|
2022-10-15 20:49:31 +02:00
|
|
|
wdata[wsize++] = 0xF7;
|
|
|
|
rsize = 8;
|
|
|
|
|
|
|
|
i2c_dma_start_transfer7(I2C1, BMP280_7BIT_ADDR, wdata, wsize, rsize);
|
|
|
|
}
|
2022-10-08 20:50:08 +02:00
|
|
|
|
|
|
|
|
2022-11-09 20:47:13 +01:00
|
|
|
static void cb_i2c_dma(i2c_dma_evt_t evt, const uint8_t *rdata, size_t rlen)
|
2022-10-15 20:49:31 +02:00
|
|
|
{
|
|
|
|
(void)rlen;
|
|
|
|
|
2022-11-09 20:47:13 +01:00
|
|
|
switch(evt) {
|
|
|
|
case I2C_DMA_EVT_TRANSFER_COMPLETE:
|
|
|
|
switch(m_readout_state) {
|
|
|
|
case SEND_REQUEST:
|
|
|
|
m_readout_state = WAIT_MEASUREMENT_COMPLETE;
|
|
|
|
trigger_read_status_register();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WAIT_MEASUREMENT_COMPLETE:
|
|
|
|
if((rdata[0] & 0x09) != 0) {
|
|
|
|
// either "measuring" or "im_update" is active, so measurement is not complete yet.
|
|
|
|
// try again:
|
|
|
|
trigger_read_status_register();
|
|
|
|
} else {
|
|
|
|
m_readout_state = READ_RESULTS;
|
|
|
|
trigger_read_results();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case READ_RESULTS:
|
|
|
|
m_press_raw =
|
|
|
|
((int32_t)rdata[0] << 12) // press_msb (0xF7)
|
|
|
|
| ((int32_t)rdata[1] << 4) // press_lsb (0xF8)
|
|
|
|
| ((int32_t)rdata[2] >> 4); // press_xlsb (0xF9)
|
|
|
|
|
|
|
|
m_temp_raw =
|
|
|
|
((int32_t)rdata[3] << 12) // temp_msb (0xFA)
|
|
|
|
| ((int32_t)rdata[4] << 4) // temp_lsb (0xFB)
|
|
|
|
| ((int32_t)rdata[5] >> 4); // temp_xlsb (0xFC)
|
|
|
|
|
|
|
|
m_readout_state = COMPENSATE_TEMPERATURE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
// should never happen
|
|
|
|
while(1);
|
|
|
|
break;
|
2022-10-15 20:49:31 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2022-11-09 20:47:13 +01:00
|
|
|
case I2C_DMA_EVT_TIMEOUT:
|
|
|
|
case I2C_DMA_EVT_NAK:
|
|
|
|
m_readout_state = ERROR;
|
2022-10-15 20:49:31 +02:00
|
|
|
break;
|
2022-10-08 20:50:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-15 20:49:31 +02:00
|
|
|
bool bmp280_loop(void)
|
2022-10-08 20:50:08 +02:00
|
|
|
{
|
2022-10-15 20:49:31 +02:00
|
|
|
bool retval = false;
|
|
|
|
|
|
|
|
switch(m_readout_state) {
|
|
|
|
case READY:
|
|
|
|
// nothing to do in this state
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SEND_REQUEST:
|
|
|
|
case WAIT_MEASUREMENT_COMPLETE:
|
|
|
|
case READ_RESULTS:
|
|
|
|
// handled in cb_i2c_dma exclusively
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMPENSATE_TEMPERATURE:
|
|
|
|
m_last_temperature = bmp280_comp_temperature(m_temp_raw);
|
|
|
|
m_readout_state = COMPENSATE_PRESSURE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMPENSATE_PRESSURE:
|
|
|
|
m_last_pressure = bmp280_comp_pressure(m_press_raw);
|
|
|
|
m_readout_state = READY;
|
2022-10-15 21:41:50 +02:00
|
|
|
m_measurements_valid = true;
|
2022-11-09 20:47:13 +01:00
|
|
|
retval = true; // measurement complete
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ERROR:
|
|
|
|
m_readout_state = READY;
|
|
|
|
m_measurements_valid = false;
|
|
|
|
retval = true; // measurement cycle terminated
|
2022-10-15 20:49:31 +02:00
|
|
|
break;
|
|
|
|
}
|
2022-10-08 20:50:08 +02:00
|
|
|
|
2022-10-15 20:49:31 +02:00
|
|
|
if(m_readout_state != READY) {
|
|
|
|
i2c_dma_loop();
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
2022-10-08 20:50:08 +02:00
|
|
|
|
|
|
|
|
2022-10-15 20:49:31 +02:00
|
|
|
bool bmp280_start_measurement(void)
|
|
|
|
{
|
|
|
|
uint8_t wdata[2];
|
|
|
|
uint8_t wsize = 0;
|
|
|
|
|
|
|
|
if(m_readout_state != READY) {
|
|
|
|
return false; // still busy
|
|
|
|
}
|
|
|
|
|
|
|
|
wdata[wsize++] = 0xF4; // measurement control register
|
|
|
|
wdata[wsize++] = (0x01 << 5) | (0x01 << 2) | 0x01; // pressure x1, temp x1, forced mode
|
2022-10-08 20:50:08 +02:00
|
|
|
|
2022-10-15 20:49:31 +02:00
|
|
|
i2c_dma_start_transfer7(I2C1, BMP280_7BIT_ADDR, wdata, wsize, 0);
|
2022-10-08 20:50:08 +02:00
|
|
|
|
2022-10-15 20:49:31 +02:00
|
|
|
m_readout_state = SEND_REQUEST;
|
2022-10-08 20:50:08 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-15 21:41:50 +02:00
|
|
|
bool bmp280_are_measurements_valid(void)
|
|
|
|
{
|
|
|
|
return m_measurements_valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-08 20:50:08 +02:00
|
|
|
fxp_t bmp280_get_temperature(void)
|
|
|
|
{
|
|
|
|
return m_last_temperature;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fxp_t bmp280_get_pressure(void)
|
|
|
|
{
|
|
|
|
return m_last_pressure;
|
|
|
|
}
|