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

Twi Transfers Never Complete

I am attempting to use SDK15 with the nrf52832 to communicate with multiple sensors over I2C. However, in the twi_sensor and twi_master_using_nrf_twi_mngr examples, as well as my own code adapted from these examples, the first twi transfer is never completed. I have tried using blocking and non blocking modes of nrfx_twi, used both nrf_twi_mngr_perform and nrf_twi_mngr_schedule, clearing the bus before init, and disabling the internal pull-ups as my sensors have built in pull up resistors. This occurs with the sensors connected connected and when the sensors are disconnected pins floating. 

My understanding of the TWI modules is that if communication fails an error will be returned, but instead the application hangs after the first transfer call occurs. This leads me to believe there may be a problem with the initialization of the twi_modules or the queuing of transactions, however, the examples are equally non-functional on my board. Unfortunately, I do not have access to a digital logic analyzer to view the bus as I am working from home. I am unsure how to debug further, as all API calls return successfully up to the first transfer, and after that the program hangs. Do you have any suggestions as to how I could get the examples working? Because the issue occurs with the examples I have not included my own code, however, I would be happy to include it if it could provide more info. 

Parents
  • Update: Attempting to run the same example on the nrf52 DK provided some more info. The twi_scanner successfully identified the device address as 0x68. However, the twi_mngr example returns error 0x03 for cb_data.transaction_result during nrf_twi_mngr_perform calls. The development kit still hangs on the twi_sensor example at line 96 in main.c, "while (m_xfer_done == false);". This leads me to believe the problem is related to the interrupt/callback handling, but because the examples also exhibit this behavior I am unsure where to go from here. 

    void LM75B_set_mode(void)
    {
        ret_code_t err_code;
    
        /* Writing to LM75B_REG_CONF "0" set temperature sensor in NORMAL mode. */
        uint8_t reg[2] = {LM75B_REG_CONF, NORMAL_MODE};
        err_code = nrf_drv_twi_tx(&m_twi, LM75B_ADDR, reg, sizeof(reg), false);
        APP_ERROR_CHECK(err_code);
        while (m_xfer_done == false);
    
        /* Writing to pointer byte. */
        reg[0] = LM75B_REG_TEMP;
        m_xfer_done = false;
        err_code = nrf_drv_twi_tx(&m_twi, LM75B_ADDR, reg, 1, false);
        APP_ERROR_CHECK(err_code);
        while (m_xfer_done == false);
    }

  • I was able to nail down the cause of the error 0x03 with the devkit as a NACK in the twi manager's built in event handler. However, the custom board still hangs with no calls to callbacks or event handlers. The custom board has a direct connection to the I2C sensors, just like the devkit. Is there something internal with the nrf52832 that could be interfering with twi, or could the pin traces be too close together and interfering with each other? The traces are a minimum of .4mm apart at all points. 

Reply
  • I was able to nail down the cause of the error 0x03 with the devkit as a NACK in the twi manager's built in event handler. However, the custom board still hangs with no calls to callbacks or event handlers. The custom board has a direct connection to the I2C sensors, just like the devkit. Is there something internal with the nrf52832 that could be interfering with twi, or could the pin traces be too close together and interfering with each other? The traces are a minimum of .4mm apart at all points. 

Children
  • I switched over from the twi_mngr implementation to nrfx_twi in my custom program and added address and data NACK handling. It runs successfully on the devkit, yet after the first tx call on the custom board the twi event handler is never reached, with a NACK or otherwise. This leads me to believe the issue is either a difference in between my circuit board and the devkit or a difference between the nrf52832 and nrf52dk platforms. I have included the twi related code below in case it will shed some light on the subject.

    twi_evt_handler

    void twi_evt_handler(nrfx_twi_evt_t const * p_event, void * p_context)
    {
        switch (p_event->type)
        {
            case NRFX_TWI_EVT_DONE:
              //if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_RX)
              //{
                //data_handler(m_sample);
              //}
              m_xfer_done = true;
              break;
            case NRFX_TWI_EVT_ADDRESS_NACK:
              NRF_LOG_WARNING("mpu9250 address nack");
              twi_nack = true;
            case NRFX_TWI_EVT_DATA_NACK:
              NRF_LOG_WARNING("mpu9250 data nack");
              twi_nack = true;
            default:
              NRF_LOG_WARNING("twi_evt_handler unknown evt");
              break;
        }
    }
     

    twi_init

    static void twi_init(void)
    {
        ret_code_t err_code = 0;
        nrfx_twi_config_t twi0_mpu9250_config;
        twi0_mpu9250_config.scl                = SCL0;
        twi0_mpu9250_config.sda                = SDA0;
        twi0_mpu9250_config.frequency          = NRF_TWI_FREQ_100K;
        twi0_mpu9250_config.interrupt_priority = APP_IRQ_PRIORITY_LOW;
        //twi0_mpu9250_config.clear_bus_init     = false;
        twi0_mpu9250_config.hold_bus_uninit    = false;
        //err_code = nrf_twi_mngr_init(&m_nrf_twi_mngr0, &twi0_mpu9250_config);
        err_code = nrfx_twi_init(&m_twi0, &twi0_mpu9250_config, twi_evt_handler, NULL);
        APP_ERROR_CHECK(err_code);
        nrfx_twi_enable(&m_twi0);
        
        nrfx_twi_config_t twi1_mpu9250_config;
        twi1_mpu9250_config.scl                = SCL1;
        twi1_mpu9250_config.sda                = SDA1;
        twi1_mpu9250_config.frequency          = NRF_TWI_FREQ_100K;
        twi1_mpu9250_config.interrupt_priority = APP_IRQ_PRIORITY_LOW;
        //twi0_mpu9250_config.clear_bus_init     = false;
        twi1_mpu9250_config.hold_bus_uninit    = false;
        //err_code = nrf_twi_mngr_init(&m_nrf_twi_mngr1, &twi1_mpu9250_config);
        err_code = nrfx_twi_init(&m_twi1, &twi1_mpu9250_config, twi_evt_handler, NULL);
        APP_ERROR_CHECK(err_code);
        nrfx_twi_enable(&m_twi1);
    
    }

    write_mpu9250

    void write_mpu9250(uint8_t * reg_addr, uint8_t * p_buffer, uint8_t byte_cnt)
    {
      ret_code_t err_code = NRF_SUCCESS;
      uint8_t reg[byte_cnt + 1];
      reg[0] = *reg_addr;
      for(int i = 0; i < byte_cnt; i++){
        reg[i+1] = p_buffer[i];
      }
      m_xfer_done = false;
      twi_nack = false;
      if(current_mpu9250_id == 0){
        APP_ERROR_CHECK(nrfx_twi_tx(&m_twi0, MPU9250_ADDRESS, reg, 1, false));
        while(!m_xfer_done){
          if(twi_nack){
            twi_nack = false;
            APP_ERROR_CHECK(nrfx_twi_tx(&m_twi0, MPU9250_ADDRESS, reg, 1, false));
          }
        }
      }
      if(current_mpu9250_id == 1){
        APP_ERROR_CHECK(nrfx_twi_tx(&m_twi1, MPU9250_ADDRESS, reg, 1, false));
        while(!m_xfer_done){
          if(twi_nack){
            twi_nack = false;
            APP_ERROR_CHECK(nrfx_twi_tx(&m_twi1, MPU9250_ADDRESS, reg, 1, false));
          }
        }
      }
    }

  • Use an oscilloscope to look at the I²C signals.

    My guess is: You forgot the pullup resistors on you custom board, and SCL is pulled permanently LOW by parasitics.

  • I went in and looked at the signals, you're right both SCL and SDA are pulled low. The SCL and SDA lines are configured to use the internal pullups of the nrf52832, and the i2c sensors are mpu9250 breakout boards with 10kohm pullup resistors included. I had expected these to be sufficient, would stronger pullups with lower resistances solve the problem?

  • Which pins are you using for the TWI interfaces? I could not find the definition of SCLx/SDAx in the code you posted.

  • Pins 0.01 and 0.02 are SCL lines and pins 0.03 and 0.04 are SDA. Rather than have two I2C busses with all four signal lines close together, would one I2C bus using non-adjacent traces reduce parasitic capacitance? 

Related