This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Softdevice assert with TWI

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.

Related