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

app_twi with EasyDMA

Hi, I want to control a g-sensor by nRF52832 via i2c.

I am using an example( nRF5_SDK_12.2.0\examples\ble_peripheral\ble_app_uart\pca10040\s132\arm4) and I add the app_twi into the project.

In the sdk_config.h, I set TWI0_ENABLED and TWI0_USE_EASY_DMA as 1. There are no any error after compiling, but I always got NRF_ERROR_INVALID_ADDR on run-time. However, If I set the TWI0_USE_EASY_DMA as 0, It works. I take a look at my settings of Keil, In the Target label, the IRAM1 starts from 0x20002128 and the size is 0xDED8 bytes.

Could you please kindly give me some advices?

  1. Why can't app_twi use easy DMA?
  2. Is the Easy DMA using the address 0x20000000 in RAM? The example is using the RAM from 0x20002128, so it doesn't work?
  3. I refer to the twi_sensor_pca10040 example, it uses nrf_drv_twi_tx to implement. What the pros and cons between nrf_drv_twi and app_twi? Which methods should I use?

Thank you so much!!

  • Hi,

    The EasyDMA requires the data to be located in RAM region. From Product Specification:

    If the TXD.PTR and the RXD.PTR are not pointing to the Data RAM region, an EasyDMA transfer may result in a HardFault or RAM corruption.

    The TWIM driver checks for this, for example in the twim_xfer(..) function:

    if (!nrf_drv_is_in_RAM(p_xfer_desc->p_primary_buf))
    {
        err_code = NRF_ERROR_INVALID_ADDR;
        NRF_LOG_WARNING("Function: %s, error code: %s.\r\n", (uint32_t)__func__, (uint32_t)ERR_TO_STR(err_code));
        return err_code;
    }
    

    nrf_drv_is_in_RAM(..):

    __STATIC_INLINE bool nrf_drv_is_in_RAM(void const * const ptr)
    {
        return ((((uintptr_t)ptr) & 0xE0000000u) == 0x20000000u);
    }
    

    So the startaddress of the data have to be in the range 0x20000000 to 0x40000000 - 1.

    If you use the const keyword, the variable will be placed in flash instead of RAM. You only have to worry about the app_twi_transfer_t:p_data variable, this cannot be const.

    I have not used app_twi that much, so I would prefer to use nrf_drv_twi. App_twi uses nrf_drv_twi, it just adds another layer on top of it.


    PS: I see that the TWI transaction manager example in SDK 12.2.0 does not work with EasyDMA turned on. This is because of these lines (in lm75b.c/.h and mma7660.c/.h)

    //mma7660.c
    uint8_t const mma7660_xout_reg_addr = MMA7660_REG_XOUT;
    static uint8_t const default_config[] = { LM75B_REG_CONF, 0 };
    
    //mma7660.h
    extern uint8_t const mma7660_xout_reg_addr;
    
    //lm75b.c
    uint8_t const lm75b_conf_reg_addr  = LM75B_REG_CONF;
    uint8_t const lm75b_temp_reg_addr  = LM75B_REG_TEMP;
    uint8_t const lm75b_tos_reg_addr   = LM75B_REG_TOS;
    uint8_t const lm75b_thyst_reg_addr = LM75B_REG_THYST;
    static uint8_t const default_config[] = { MMA7660_REG_MODE, 1 };
    
    //lm75b.h
    extern uint8_t const lm75b_conf_reg_addr;
    extern uint8_t const lm75b_temp_reg_addr;
    extern uint8_t const lm75b_tos_reg_addr;
    extern uint8_t const lm75b_thyst_reg_addr;
    

    Remove the const and it should work. I will report this internally.

Related