Try to make BMP280 communication more resilient
If communication times out or a NAK is received, this is now recognized and sensor values are flagged as invalid. The communication then restarts on the next regular cycle. This is still to be tested.
This commit is contained in:
parent
4d4cc41b46
commit
5090b7de4a
84
src/bmp280.c
84
src/bmp280.c
|
@ -16,7 +16,8 @@ typedef enum {
|
|||
WAIT_MEASUREMENT_COMPLETE,
|
||||
READ_RESULTS,
|
||||
COMPENSATE_TEMPERATURE,
|
||||
COMPENSATE_PRESSURE
|
||||
COMPENSATE_PRESSURE,
|
||||
ERROR // set by the I²C callback in case of errors/timeout
|
||||
} bmp280_readout_state_t;
|
||||
|
||||
static bmp280_readout_state_t m_readout_state;
|
||||
|
@ -45,7 +46,7 @@ static int32_t m_temp_raw;
|
|||
static int32_t m_press_raw;
|
||||
|
||||
|
||||
static void cb_i2c_dma(const uint8_t *rdata, size_t rlen);
|
||||
static void cb_i2c_dma(i2c_dma_evt_t evt, const uint8_t *rdata, size_t rlen);
|
||||
|
||||
|
||||
bool bmp280_init(void)
|
||||
|
@ -151,44 +152,53 @@ static void trigger_read_results(void)
|
|||
}
|
||||
|
||||
|
||||
static void cb_i2c_dma(const uint8_t *rdata, size_t rlen)
|
||||
static void cb_i2c_dma(i2c_dma_evt_t evt, const uint8_t *rdata, size_t rlen)
|
||||
{
|
||||
(void)rlen;
|
||||
|
||||
switch(m_readout_state) {
|
||||
case SEND_REQUEST:
|
||||
m_readout_state = WAIT_MEASUREMENT_COMPLETE;
|
||||
trigger_read_status_register();
|
||||
break;
|
||||
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();
|
||||
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;
|
||||
}
|
||||
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);
|
||||
case I2C_DMA_EVT_TIMEOUT:
|
||||
case I2C_DMA_EVT_NAK:
|
||||
m_readout_state = ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -218,7 +228,13 @@ bool bmp280_loop(void)
|
|||
m_last_pressure = bmp280_comp_pressure(m_press_raw);
|
||||
m_readout_state = READY;
|
||||
m_measurements_valid = true;
|
||||
retval = true;
|
||||
retval = true; // measurement complete
|
||||
break;
|
||||
|
||||
case ERROR:
|
||||
m_readout_state = READY;
|
||||
m_measurements_valid = false;
|
||||
retval = true; // measurement cycle terminated
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <fxp.h>
|
||||
|
||||
bool bmp280_init(void);
|
||||
bool bmp280_loop(void); // returns true if measurements have been updated
|
||||
bool bmp280_loop(void); // returns true when measurement cycle has terminated (successfully or with error)
|
||||
|
||||
bool bmp280_start_measurement(void);
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#define DMA_CHANNEL_TX DMA_CHANNEL2
|
||||
#define DMA_CHANNEL_RX DMA_CHANNEL3
|
||||
|
||||
#define TIMEOUT_COUNTER_VALUE 100 // milliseconds
|
||||
|
||||
static uint8_t m_wdata[2];
|
||||
static uint8_t m_wlen;
|
||||
static uint8_t m_rdata[32];
|
||||
|
@ -16,6 +18,8 @@ static uint8_t m_rlen;
|
|||
static uint8_t m_addr;
|
||||
static uint32_t m_i2c;
|
||||
|
||||
static uint32_t m_timeout_counter;
|
||||
|
||||
typedef enum {
|
||||
IDLE,
|
||||
SEND_DATA,
|
||||
|
@ -101,9 +105,16 @@ void i2c_dma_loop(void)
|
|||
} else {
|
||||
// no RX requested => we are done here
|
||||
m_state = IDLE;
|
||||
m_callback(NULL, 0);
|
||||
m_callback(I2C_DMA_EVT_TRANSFER_COMPLETE, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if(I2C_ISR(m_i2c) & I2C_ISR_NACKF) {
|
||||
// there should be no NACK during the transfer => abort
|
||||
I2C_ICR(m_i2c) |= I2C_ICR_NACKCF; // clear the interrupt flag
|
||||
m_state = IDLE;
|
||||
m_callback(I2C_DMA_EVT_NAK, NULL, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case RECEIVE_DATA:
|
||||
|
@ -112,10 +123,22 @@ void i2c_dma_loop(void)
|
|||
dma_clear_interrupt_flags(DMA1, DMA_CHANNEL_RX, DMA_TCIF);
|
||||
|
||||
m_state = IDLE;
|
||||
m_callback(m_rdata, m_rlen);
|
||||
m_callback(I2C_DMA_EVT_TRANSFER_COMPLETE, m_rdata, m_rlen);
|
||||
}
|
||||
|
||||
if(I2C_ISR(m_i2c) & I2C_ISR_NACKF) {
|
||||
// there should be no NACK during the transfer => abort
|
||||
I2C_ICR(m_i2c) |= I2C_ICR_NACKCF; // clear the interrupt flag
|
||||
m_state = IDLE;
|
||||
m_callback(I2C_DMA_EVT_NAK, NULL, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
m_timeout_counter--;
|
||||
if(m_timeout_counter == 0) {
|
||||
m_callback(I2C_DMA_EVT_TIMEOUT, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -141,6 +164,8 @@ void i2c_dma_start_transfer7(uint32_t i2c, uint8_t addr, const uint8_t *w, size_
|
|||
i2c_enable_autoend(i2c); // stop condition after write transfer
|
||||
}
|
||||
|
||||
m_timeout_counter = TIMEOUT_COUNTER_VALUE;
|
||||
|
||||
i2c_send_start(i2c); // start the transfer. The rest is handled by the DMA.
|
||||
setup_txdma();
|
||||
}
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
typedef enum
|
||||
{
|
||||
I2C_DMA_EVT_TRANSFER_COMPLETE,
|
||||
I2C_DMA_EVT_ADDR_NAK,
|
||||
I2C_DMA_EVT_NAK,
|
||||
I2C_DMA_EVT_TIMEOUT,
|
||||
} i2c_dma_evt_t;
|
||||
|
||||
typedef void (*i2c_dma_callback_t)(const uint8_t *rdata, size_t rlen);
|
||||
typedef void (*i2c_dma_callback_t)(i2c_dma_evt_t evt, const uint8_t *rdata, size_t rlen);
|
||||
|
||||
void i2c_dma_init(i2c_dma_callback_t callback);
|
||||
|
||||
|
|
Loading…
Reference in a new issue