Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Correct order of nrf_drv_twi commands

Hi, I try to read data from the ICM20948 IMU with I2C from my nRF 52840 DK.

Initialization of the device is correct, the IMU ID is sent to nRF correctly which means that the TWI protocol works fine  but when I initiate the process to read the accelerometer and gyroscope data from the IMU, the following error appears in the terminal emulator   app: ERROR 17 [NRF_ERROR_BUSY] at  ... ... ...  ICM20948.c:180.

The part of code that is pointed is line 12  in the following code snippet

void read_IMU(void){
   
       uint8_t pinax[] = {ICM20948_ACCEL_XOUT_H};
       int8_t rawData[12] = {0};
    
       err_code = nrf_drv_twi_tx(&m_twi, ICM20948_ADDRESS, pinax, sizeof(pinax), false); 
       while(nrf_drv_twi_is_busy(&m_twi));
       APP_ERROR_CHECK(err_code);
       
       err_code = nrf_drv_twi_rx(&m_twi, ICM20948_ADDRESS, &rawData[0], 12);      
       //while(nrf_drv_twi_is_busy(&m_twi));     
       APP_ERROR_CHECK(err_code); //   <<<===== ERROR 17 [NRF ERROR BUSY]
       
       accel_buffer[0] = (int16_t) ((rawData[0] << 8) | rawData[1]); // x axis raw data
       accel_buffer[1] = (int16_t) ((rawData[2] << 8) | rawData[3]); // y axis raw data
       accel_buffer[2] = (int16_t) ((rawData[4] << 8) | rawData[5]); // z axis raw data
    
       gyro_buffer[0] = (int16_t) ((rawData[6] << 8)  | rawData[7]);  // x axis raw data
       gyro_buffer[1] = (int16_t) ((rawData[8] << 8)  | rawData[9]);  // y axis raw data
       gyro_buffer[2] = (int16_t) ((rawData[10] << 8) | rawData[11]); // z axis raw data
}

Now, if I add this line of code ---> while(nrf_drv_twi_is_busy(&m_twi));  before the APP_ERROR_CHECK() in line 11, the problem disappears

but in the next command  where I want to fetch the IMU data ---> nrf_drv_twi_rx()  , the  SDA line stays low and no stop is produced from the nRF52840 TWI.

As a result I cannot get an RX event from the nRF.   What am I doing wrong here?

Also, I cannot understand if the way that I am using nrf_drv_twi_is_busy(&m_twi) is correct or if I should use it another way

Thank you for your time

Parents
  • Hi,

    I am not sure which SDK you are using, but make sure you are using the lates e.g. SDKv15.3.

    I suggest you start with the \examples\peripheral\twi_sensor as reference, and you can find that it uses a m_xfer_done flag between the twi_handler() and main() to be informed about when the preceding twi transfer is finished and ready to start the next.

    Best regards,
    Kenneth

  • I was based on that example to do this.The nRF SDK I use is 15.2.0.

    I partially solved the issue by increasing the TWI speed to 400kHz.

    I say partially because now when I fetch data from the sensor continuously once per second at some point the SDA line stalls at the point where data are brought back from the sensor.

    This is depicted in the following images taken from the logic analyzer.

    The first image shows the IMU accel/gyro data transfers and at the right end of the image the SDA stall is shown

    The second  image shows one of these IMU accel/gyro data transfers and again at the right end of the image the SDA stall is shown

    What do you think it might cause it?

  • I suspect some race condition in the code, do you experience the same if you disable EasyDMA, example:
    #define TWI0_USE_EASY_DMA 0

    OR

    Have you tried to operate the twi driver in blocking mode? In that case there is no callback event handler, and instead nrf_drv_twi_tx() and nrf_drv_twi_rx() will return when transfer is complete (you can skip the while(nrf_drv_twi_is_busy())-loops). This can be done by calling nrf_drv_twi_init() with NULL as event_handler, e.g: nrf_drv_twi_init(&m_twi, &twi_config, NULL, NULL);

    Best regards,
    Kenneth

Reply
  • I suspect some race condition in the code, do you experience the same if you disable EasyDMA, example:
    #define TWI0_USE_EASY_DMA 0

    OR

    Have you tried to operate the twi driver in blocking mode? In that case there is no callback event handler, and instead nrf_drv_twi_tx() and nrf_drv_twi_rx() will return when transfer is complete (you can skip the while(nrf_drv_twi_is_busy())-loops). This can be done by calling nrf_drv_twi_init() with NULL as event_handler, e.g: nrf_drv_twi_init(&m_twi, &twi_config, NULL, NULL);

    Best regards,
    Kenneth

Children
Related