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

TWI hanlder is not called

I use Twi for reading data from the lsm sensors. I want to use a twi_handler in which I will set the xfer_done_flag on the true and go off into a sleep mode until the flag is set to a false so that the sensors can successfully read the data. But the problem is that the TWI handler is not called. The problem is exactly in the software, as the example twi_sensor from sdk works.

twi initialization:

void twi_init(void) {
  const nrf_drv_twi_config_t twi_lsm330dlc_config = {
      .scl = SCL_,
      .sda = SDA_,
      .frequency = NRF_TWI_FREQ_400K,
      .interrupt_priority = APP_IRQ_PRIORITY_LOWEST,
      .clear_bus_init = true};

  ret_code_t error = nrf_drv_twi_init(&m_twi, &twi_lsm330dlc_config, twi_handler, NULL);

  APP_ERROR_CHECK(error);

  nrf_drv_twi_enable(&m_twi);
}

TWI handler:

void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
{
    switch (p_event->type)
    {
        case NRF_DRV_TWI_EVT_DONE:
            if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_RX)
            {
                data_handler(m_sample);
            }
            m_xfer_done = true;
            break;
        default:
            break;
    }
}

sdk_config.h twi settings:

// <e> TWI_ENABLED - nrf_drv_twi - TWI/TWIM peripheral driver
//==========================================================
#ifndef TWI_ENABLED
#define TWI_ENABLED 1
#endif
// <o> TWI_DEFAULT_CONFIG_FREQUENCY  - Frequency
 
// <26738688=> 100k 
// <67108864=> 250k 
// <104857600=> 400k 

#ifndef TWI_DEFAULT_CONFIG_FREQUENCY
#define TWI_DEFAULT_CONFIG_FREQUENCY 104857600
#endif

// <q> TWI_DEFAULT_CONFIG_CLR_BUS_INIT  - Enables bus clearing procedure during init
 

#ifndef TWI_DEFAULT_CONFIG_CLR_BUS_INIT
#define TWI_DEFAULT_CONFIG_CLR_BUS_INIT 0
#endif

// <q> TWI_DEFAULT_CONFIG_HOLD_BUS_UNINIT  - Enables bus holding after uninit
 

#ifndef TWI_DEFAULT_CONFIG_HOLD_BUS_UNINIT
#define TWI_DEFAULT_CONFIG_HOLD_BUS_UNINIT 0
#endif

// <o> TWI_DEFAULT_CONFIG_IRQ_PRIORITY  - Interrupt priority
 

// <i> Priorities 0,2 (nRF51) and 0,1,4,5 (nRF52) are reserved for SoftDevice
// <0=> 0 (highest) 
// <1=> 1 
// <2=> 2 
// <3=> 3 
// <4=> 4 
// <5=> 5 
// <6=> 6 
// <7=> 7 

#ifndef TWI_DEFAULT_CONFIG_IRQ_PRIORITY
#define TWI_DEFAULT_CONFIG_IRQ_PRIORITY 7
#endif

// <e> TWI0_ENABLED - Enable TWI0 instance
//==========================================================
#ifndef TWI0_ENABLED
#define TWI0_ENABLED 1
#endif
// <q> TWI0_USE_EASY_DMA  - Use EasyDMA (if present)
 

#ifndef TWI0_USE_EASY_DMA
#define TWI0_USE_EASY_DMA 1
#endif

// </e>

// <e> TWI1_ENABLED - Enable TWI1 instance
//==========================================================
#ifndef TWI1_ENABLED
#define TWI1_ENABLED 0
#endif
// <q> TWI1_USE_EASY_DMA  - Use EasyDMA (if present)
 

#ifndef TWI1_USE_EASY_DMA
#define TWI1_USE_EASY_DMA 0
#endif

// </e>

// <q> TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED  - Enables nRF52 anomaly 109 workaround for TWIM.
 

// <i> The workaround uses interrupts to wake up the CPU by catching
// <i> the start event of zero-frequency transmission, clear the 
// <i> peripheral, set desired frequency, start the peripheral, and
// <i> the proper transmission. See more in the Errata document or
// <i> Anomaly 109 Addendum located at https://infocenter.nordicsemi.com/

#ifndef TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED
#define TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED 0
#endif

  • showing the code which makes the twi calls would be helpful. Also are you getting back any error for the call?

  • #define LSM330D_WHO_AM_I_G 0x0F
    
    bool LSM330DLC_init(uint8_t address_g, uint8_t address_a) {
      //whoami_read_gyro
      uint8_t whoami = LSM330D_WHO_AM_I_G;
      uint8_t resultsWhoAmI;
    
      nrf_drv_twi_tx(&m_twi, address_g, &whoami, 1, true);
      nrf_drv_twi_rx(&m_twi, address_g, &resultsWhoAmI, 1);
    
      if (resultsWhoAmI != LSM330D_WHOAMI_G_VAL)
        return false;
    
      return true;
    }

    When reading from the LSM without using TWI_HANDLER, " NULL" in the nrf_drv_twi_init
    function:

    ret_code_t ret = nrf_drv_twi_init(&m_twi, &twi_lsm330dlc_config, NULL, NULL);
    if(ret != NRF_SUCCESS) SEGGER_RTT_TerminalOut(0, "ERROR");

     no errors are returned. The function returns NRF_SUСCESS.

    But when i use TWI_HANDLER, returns NRF_ERROR_BUSY, in second twi call

    
    ret_code_t ret = nrf_drv_twi_init(&m_twi, &twi_lsm330dlc_config, twi_handler, NULL);
    if(ret != NRF_SUCCESS) SEGGER_RTT_TerminalOut(0, "ERROR");

  • when you have a handler i believe you are running in async mode vs polling when no handler (null) is used. If this is correct then you would need to wait for the first command to finish before sending the second command. If not then you will be accessing the bus before the bus is clear or released. You can use m_xfer_done as a flag to resolve the issue. 

  • my problem is that the twi_handler function is not called after the twi call. I wanted to use Twi_Hanlder to set flags. 

  • understood but I believe you are running async so without a flag to stop the program from accessing the bus you will most likely always get a error_busy fault. Your handler should clear the flag and application should set the flag.

    reset flag

    call twi_tx

    while((flag) == 0); // wait it handler to clear flag

    reset flag

    call twi_rx

    Note reset, set, clear and be whatever 0 or 1 value logic you pick.

    This is why I think when you have null as the handler it works. Using null make the twi call do a busy wait while providing the handler allows the program to continue executing. 

Related