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

Conversion from NRFX_TWI to NRFX_TWIM

HI,

I am working on the interface between the nrf52832 and the MPU9250 IMU.

I have communication working fine with using nrfx_twi, but I have the following error when I try to use  nrfx_twim :

<error> app: ASSERTION FAILED at /Users/slareau/nrf52_development/nRF5_SDK_16/modules/nrfx/drivers/src/nrfx_twim.c:561

I can get WHOIAM working indicating that the communication between the NRF52 and the IMU is working.

The error occur when I call the IMU self-test.

Looking nrfx_twim.c line 561 is :  p_xfer_desc->secondary_length))    from the following code:

nrfx_err_t nrfx_twim_xfer(nrfx_twim_t           const * p_instance,
                          nrfx_twim_xfer_desc_t const * p_xfer_desc,
                          uint32_t                      flags)
{
    NRFX_ASSERT(TWIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
                                     p_xfer_desc->primary_length,
                                     p_xfer_desc->secondary_length));

    nrfx_err_t err_code = NRFX_SUCCESS;

 I have include the init / read / write driver below.  Those came from an old exemple (SDK12)  that I have modernize as I could - I don't have a lot of experience and nrfx TWI and TWIM exemple are rare...  As I mention, the nrfx_twi version work fine (except for a compass calibration issue - might be related to communication issue or not).

To create the TWIM version, i have juste replace TWI by TWIM in appropriate place, and change the SDK_config setting.

How can I fix this ? Your help is always greatly appreciate.

Regards,

 /*
  * The library is not extensively tested and only
  * meant as a simple explanation and for inspiration.
  * NO WARRANTY of ANY KIND is provided.
  */


#if defined(MPU_USES_TWI) // Use TWI drivers

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "nrfx_twim.h"
#include "nrf_drv_mpu.h"
#include "app_util_platform.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"

#include "nrf_log.h"



/* Pins to connect MPU. Pinout is different for nRF51 DK and nRF52 DK
 * and therefore I have added a conditional statement defining different pins
 * for each board. This is only for my own convenience. 
 */
/*
 #if defined BOARD_PCA10040
   #define MPU_TWI_SDA_PIN 26
  #define MPU_TWI_SCL_PIN 27

 # elif  BOARD_HOL18008
 #define MPU_TWI_SDA_PIN 11 // HOL18008
 #define MPU_TWI_SCL_PIN 12 
 #endif
*/
 //#define MPU_TWI_SDA_PIN 26
 //#define MPU_TWI_SCL_PIN 27  // HOL18008 + MPU9255 ext
  
  #define MPU_TWI_SDA_PIN 22
  #define MPU_TWI_SCL_PIN 24  // Ebyte73 + MPU9255 ext
  


#define MPU_TWI_BUFFER_SIZE     	14 // 14 byte buffers will suffice to read acceleromter, gyroscope and temperature data in one transmission.
#define MPU_TWI_TIMEOUT 		15000 //10000 SL
#define MPU_ADDRESS     		0x68 
#define MPU_AK89XX_MAGN_ADDRESS         0x0C


static const nrfx_twim_t m_twi_instance = NRFX_TWIM_INSTANCE(0);
volatile static bool twi_tx_done = false;
volatile static bool twi_rx_done = false;

uint8_t twi_tx_buffer[MPU_TWI_BUFFER_SIZE];

static void twi_event_handler(nrfx_twim_evt_t const * p_event, void * p_context)
{
    switch(p_event->type)
    {
        case NRFX_TWIM_EVT_DONE:
            switch(p_event->xfer_desc.type)
            {
                case NRFX_TWIM_XFER_TX:
                    twi_tx_done = true;
                    break;
                case NRFX_TWIM_XFER_TXTX:
                    twi_tx_done = true;
                    break;
                case NRFX_TWIM_XFER_RX:
                    twi_rx_done = true;
                    break;
                case NRFX_TWIM_XFER_TXRX:
                    twi_rx_done = true;
                    break;
                default:
                    break;
            }
            break;
        case NRFX_TWIM_EVT_ADDRESS_NACK:
            break;
        case NRFX_TWIM_EVT_DATA_NACK:
            break;
        default:
            break;
    }
}



/**
 * @brief TWI initialization.
 * Just the usual way. Nothing special here
 */
uint32_t nrf_drv_mpu_init(void)
{
    uint32_t err_code;
    
    const nrfx_twim_config_t twi_mpu_config = {
       .scl                = MPU_TWI_SCL_PIN,
       .sda                = MPU_TWI_SDA_PIN,
       .frequency          = NRF_TWIM_FREQ_400K
     //  .interrupt_priority = APP_IRQ_PRIORITY_HIGHEST,
       //.clear_bus_init     = false
    };
    
    err_code = nrfx_twim_init(&m_twi_instance, &twi_mpu_config, twi_event_handler, NULL);
    if(err_code != NRF_SUCCESS)
	{
		return err_code;
	}
    
    nrfx_twim_enable(&m_twi_instance);
	
	return NRF_SUCCESS;
}




// The TWI driver is not able to do two transmits without repeating the ADDRESS + Write bit byte
// Hence we need to merge the MPU register address with the buffer and then transmit all as one transmission
static void merge_register_and_data(uint8_t * new_buffer, uint8_t reg, uint8_t * p_data, uint32_t length)
{
    new_buffer[0] = reg;
    memcpy((new_buffer + 1), p_data, length);
}


uint32_t  nrf_mpu_write(uint8_t slave_addr, uint8_t reg_addr, uint8_t length, uint8_t  * p_data)
//uint32_t  Sensors_I2C_WriteRegister(uint8_t slave_addr, uint8_t reg_addr, uint8_t length, uint8_t  * p_data)
{
    // This burst write function is not optimal and needs improvement.
    // The new SDK 11 TWI driver is not able to do two transmits without repeating the ADDRESS + Write bit byte
    uint32_t err_code;
    uint32_t timeout = MPU_TWI_TIMEOUT;

    uint8_t twi_tx_buffer[length+1];
    twi_tx_buffer[0] = reg_addr;
    memcpy(&twi_tx_buffer[1], p_data, length);

    // Merging MPU register address and p_data into one buffer.
    //merge_register_and_data(twi_tx_buffer, reg_addr, p_data, length);
     
    // Setting up transfer
    nrfx_twim_xfer_desc_t xfer_desc;
    xfer_desc.address = MPU_ADDRESS;
    xfer_desc.type = NRFX_TWIM_XFER_TX;
    xfer_desc.primary_length = length + 1;
    xfer_desc.p_primary_buf = twi_tx_buffer;

    // Transferring
    err_code = nrfx_twim_xfer(&m_twi_instance, &xfer_desc, 0);

    while((!twi_tx_done) && --timeout);
    if(!timeout) return NRF_ERROR_TIMEOUT;
    twi_tx_done = false;

    return err_code;
}




uint32_t  nrf_mpu_read(uint8_t slave_addr, uint8_t reg_addr, uint8_t length, uint8_t  * p_data)
//uint32_t  Sensors_I2C_ReadRegister(uint8_t slave_addr, uint8_t reg_addr, uint8_t length, uint8_t  * p_data)
{
    uint32_t err_code;
    uint32_t timeout = MPU_TWI_TIMEOUT;

    //NRF_LOG_INFO("Read twi");

    err_code = nrfx_twim_tx(&m_twi_instance, MPU_ADDRESS, &reg_addr, 1, false);
    if(err_code != NRF_SUCCESS) return err_code;

    //nrf_delay_ms(1); does not help

    //NRF_LOG_INFO("Read twi");

    while((!twi_tx_done) && --timeout);
    if(!timeout) return NRF_ERROR_TIMEOUT;
    twi_tx_done = false;

    err_code = nrfx_twim_rx(&m_twi_instance, MPU_ADDRESS, p_data, length);
    if(err_code != NRF_SUCCESS) return err_code;

    timeout = MPU_TWI_TIMEOUT;
    while((!twi_rx_done) && --timeout);
    if(!timeout) return NRF_ERROR_TIMEOUT;
    twi_rx_done = false;

    return err_code;

}


#endif // Use TWI drivers

/**
  @}
*/

<error> app: ASSERTION FAILED at /Users/slareau/nrf52_development/nRF5_SDK_16/modules/nrfx/drivers/src/nrfx_twim.c:561

Related