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

  • Good Morning.

    Yes the same thing happens when I set the #define TWI0_USE_EASY_DMA 0    or   when I try TWI it in blocking mode.

    Sometimes ERROR 33282 [NRF_ERROR_DRV_TWI_ERR_DNACK] is produced and other times the program just stalls. If I apply both options then this error is produced all the time.

    Is there any chance that the NRF_LOG_INFO () that I use to print messages, produce some problem ? I have set deferred mode to unchecked.

    Last minute progress: I increased the TWI clock from 400kHz to  416kHz by adding a new definition in the nrf52840_bitfields.h ( #define TWI_FREQUENCY_FREQUENCY_K  (0x0CF30000UL) ) and now the whole thing works great....

    Although I should be happy right now, I am a little confused. Can you explain this strange behavior?

    Thank you for your assistance

  • I don't know what might be the problem here, can you think of any way I may be able to recreate it here using an nRF52840-DK?

    I have searched a bit on the forum, I could find this case, but that one seems to be working:
    https://devzone.nordicsemi.com/f/nordic-q-a/42254/twi-inconsistent-read-of-slave-device-address-location-in-nrf5-sdk-15-2 

  • Hi.  The best thing would be if you could test it with an ICM20948 ic.... but since this might not be feasible maybe you could test the protocol in different SCL fequencies with an other I2C sensor .

    I tested it at 100,250,400 and 416kHz. The first two simply do not return nothing. They produce DNACK error . The 400kHz works sometimes and 416kHz all the time.

    Is there any way that I can configure the MCU clock source since  TWI depends on HFCLK source?     Apart from that

  • masterLee said:
    Is there any way that I can configure the MCU clock source since  TWI depends on HFCLK source?

    Sorry no.

    I have ordered an ICM20948 from ebay, and if you can provide a project I may run on a nRF52-DK then I can try to recreate it as soon as I received it.

Reply Children
  • Hi Kenneth, sorry for the delayed answer. I modified the ICM20948 example and transferred it to the Dongle. The example now functions with 400k speed. This leads me to assume that the pull-up resistors of the I2C on the DK are different from those on my ICM module.

    Regards

  • Hello masterLee,

    I am using nrf52840 with SDK 15.3. I see a lot of twi drivers and its confusing which one to use. I want to read the ICM 20948 sensor data in burst mode for my application. In the second step I want to use the tap detection in DMP, so i have to write the DMP firmware into the ICM. But my twi drivers seem to constantly return with err_code 0x11 or 0x03 errors. Please let me know which is the best twi drivers for ICM. Your help would be much appreciated. Thanks and regards.

  • Use nrf_drv_twi.h . Basicaly what you need to do as a first step would be to read the device ID of ICM20948. The code for the ID is given in the sensor's datasheet.

    If you receive the same ID with the datasheet then your TWI  communication is working. If you receive garbage data, check the TWI handler function and the places you assign your twi_xfer_done flag to false. Also you should note that it is a good practice to reset the ICM20948 before performing anything else.

Related