On SDK16.0.0 + Mesh SDK 4.1.0
I am getting random softdevice asserts when running our application with TWI accessing a temperature/humidity sensor (HTU21D/HPP845). Sometimes within a few minutes and sometimes it takes hours.
<t: 16498108>, app_error_weak.c, 96, Softdevice assert: 154516:0
I tried both blocking and non-blocking with a handler. I set .interrupt_priority = APP_IRQ_PRIORITY_LOW.
static void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context) {
//Not really being used
}
static void twi_init(void) {
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "twi_init()\n");
ret_code_t err_code;
const nrf_drv_twi_config_t twi_config = {
.scl = I2C_SCL_PIN,
.sda = I2C_SDA_PIN,
.frequency = NRF_DRV_TWI_FREQ_400K,
.interrupt_priority = APP_IRQ_PRIORITY_LOW,
.clear_bus_init = false
};
err_code = nrf_drv_twi_init(&m_twi, &twi_config, twi_handler, NULL); //event handler, non-blocking mode
//err_code = nrf_drv_twi_init(&m_twi, &twi_config, NULL, NULL); //no event handler, blocking mode
ERROR_CHECK(err_code);
nrf_drv_twi_enable(&m_twi);
}
static void read_hpp845(void) {
ret_code_t ret_code = 0;
uint8_t command_address;
uint16_t rawHumidity;
uint16_t rawTemperature;
static uint8_t hpp845_stage = 0;
switch(hpp845_stage) {
case 0: //start_hpp845_humidity
command_address = HPP845_START_HUMIDITY_ADDR;
ret_code = nrf_drv_twi_tx(&m_twi, HPP845_ADDR, &command_address, 1, false);
break;
case 1: //fetch_hpp845_humidity
memset(i2cBuffer_RX, 0, sizeof(i2cBuffer_RX));
ret_code = nrf_drv_twi_rx(&m_twi, HPP845_ADDR, i2cBuffer_RX, 3); //Get raw humidity data
break;
case 2: //continue fetch_hpp845_humidity
rawHumidity = ((unsigned int)i2cBuffer_RX[0] << 8) | ((unsigned int)i2cBuffer_RX[1]);
float tempRH = rawHumidity / (float)65536;
float rh = -6 + (125 * tempRH);
if(rh < 0.0) {
rh = 0.0;
}
else if(rh > 100.0) {
rh = 100.0;
}
hpp845_humidity = (uint8_t)rh;
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "HPP845 Humidity: %u\n", hpp845_humidity);
break;
case 3: //start_hpp845_temperature
command_address = HPP845_START_TEMPERATURE_ADDR;
ret_code = nrf_drv_twi_tx(&m_twi, HPP845_ADDR, &command_address, 1, false);
break;
case 4: //fetch_hpp845_temperature
memset(i2cBuffer_RX, 0, sizeof(i2cBuffer_RX));
ret_code = nrf_drv_twi_rx(&m_twi, HPP845_ADDR, i2cBuffer_RX, 3); //Get raw temperature data
break;
case 5: //continue fetch_hpp845_temperature
rawTemperature = ((unsigned int)i2cBuffer_RX[0] << 8) | ((unsigned int)i2cBuffer_RX[1]);
float tempTemperature = (float)rawTemperature / (float)65536;
float temperatureC = (float)-46.85 + ((float)175.72 *(float)tempTemperature);
//set range limits
if(temperatureC < -40.0) {
temperatureC = -40.0;
}
else if(temperatureC > 125.0) {
temperatureC = 125.0;
}
hpp845_temperature = (uint16_t)((temperatureC*3.0) + 120.0); //in one-third degC and offset by 120 to work in uint16_t
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "HPP845 Temperature: %u in one-third degC (offset +120)\n", hpp845_temperature);
break;
default:
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "ERROR: hpp845_stage out-of-range: %u\n", hpp845_stage);
hpp845_stage = 0; //reset, should never get here
break;
}
if((ret_code == 0) && (hpp845_stage != 5)) {
hpp845_stage++;
}
else if(ret_code != 0) {
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "ERROR: hpp845_stage: %u, ret_code: %u\n", hpp845_stage, ret_code);
hpp845_stage = 0; //reset, something went wrong
}
else {
hpp845_stage = 0; //reset, need to cycle back to start
}
}
I am calling read_hpp845() from an app_timer and I am only running one TWI instruction per app_timer cycle. If I comment out the call, the application works fine. The app_timer is set at 100ms and so I am not even using the twi event handler to check that it was successful, for now I am just assuming that it was.
How do I figure out what is causing the assert?
Thanks.