This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

TWI stuck and blocked

Hi,

I'm connecting to a proximity sensor, IQS263 over TWI interface and having some weird problems.

I'm using the same code I used to connect with the Invensense MPU 9250 so I know that on the same platform, the same code works fine with no problems.

For the IQS263 part I need to pull a RDY line high (which I do via GPIO).

Then I just init the TWI in the standard manner and start trying to talk to the device.

It just seems to hang and tracing down through nrf_drv_twi.c it seems this never happens

        if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_TXDSENT))

if I look in function twi_x_start_transfer basically that it gets stuck here

        while (twi_transfer(p_twi, &p_cb->error, &p_cb->bytes_transferred, (uint8_t *)p_data, length, no_stop))
    {}

Note the first bit of code here is down in twi_transfer and appears to just never get a TXD sent...

I'm working remotely at the moment so I can't scope the part/TWI bus to check what's happening so it could likely be a HW issue as I said the TWI code runs on another board for a different device..

My configuration is like this

    static uint32_t twi_master_init(void)
{
    uint32_t err_code;
    const nrf_drv_twi_config_t config =
    {
        .scl                = PROXIMITY_I2C_SCL,
        .sda                = PROXIMITY_I2C_SDA,
        .frequency          = TWI0_CONFIG_FREQUENCY,
        .interrupt_priority = TWI0_CONFIG_IRQ_PRIORITY
    };
    
    err_code = nrf_drv_twi_init(&m_twi_master, &config, NULL /*twi_handler*/, NULL);
    APP_ERROR_CHECK(err_code);
    
    nrf_drv_twi_enable(&m_twi_master);
    
    RMLOG("I2C sensor is at address 0x%02X SCL is %u and SDA is %u",
          IQS263_ADDR,
          PROXIMITY_I2C_SCL,
          PROXIMITY_I2C_SDA);

And sending looks like this...

static int i2c_read(unsigned char slave_addr, unsigned char reg_addr, unsigned char length, unsigned char *data)
{

    uint32_t err_code=0;
    
    if (!twi_inited) {
        return -1;
    }

    // We need to pull the RDY line low
    nrf_gpio_cfg_output(PROXIMITY_I2C_RDY);
    nrf_gpio_pin_clear(PROXIMITY_I2C_RDY);
    
    RMLOG("R[0x%02X]: A: 0x%02X L: %u", slave_addr, reg_addr, length);

    // Write the register we want to read
    err_code = nrf_drv_twi_tx(&m_twi_master, slave_addr, &reg_addr, 1, true);
    if (err_code != NRF_SUCCESS) {
        RMLOG("Failed to write register to read");
        return -1;
    }

    RMLOG("Going to read it");
    
    // Read it
    err_code = nrf_drv_twi_rx(&m_twi_master, slave_addr, data, length);
    if (err_code != NRF_SUCCESS) {
        RMLOG("Failed to read register");
    }
    else {
        RMLOG("First byte of response was 0x%02X", *data);
    }

    
    // Let it float high.. well, it should have a pull up high actually...
    nrf_gpio_pin_set(PROXIMITY_I2C_RDY);

    RMLOG("Finished");
    
    return 0;
    
}

Any help appreciated if someone has an idea off the top of their head...

  • Hi,

    If I understand you correctly you are using a GPIO on the nRF52 to pull down the RDY pin whenever you want to read data. However the way I read the datasheet, and after skimming through this IQS263 driver, that is not the way to go. I think the IQS263 is controlling the pin, pulling it low whenever it has new data available. What you should do is to set up an interrupt triggering on a negative edge on the RDY signal. When the interrupt is triggered you can read data.

    I think the datasheet is a little vague on this though, so I might be wrong.

  • Hi Martin,

    Yes, I also went and re-read the driver code as well as their data sheet (I had made some assumptions) but it doesn't appear to have fix it.

    For example I now do this to wait for the communications window with the IC but it appears to break after no delay (which I find almost impossible to believe)..

    So I had set it as an input with a pull-up so it sits high..

    Then I pull it low for 10ms to signal to the IQS that I want to communicate

    Then I set it as an input (floating high) and the IQS should pull it low to say "ok, I'm ready"

    But doesn't seem to happen.

    I'm in Sweden at the mo so will have to wait until I get back to NZ to break out the scope and figure out what's up.. feel its a HW problem on my PCB..

    nrf_gpio_cfg_input(PROXIMITY_I2C_RDY, NRF_GPIO_PIN_PULLUP);
    delay_ms(10);
    
    // We need to pull the RDY line low for at least 10ms
    nrf_gpio_cfg_output(PROXIMITY_I2C_RDY);
    nrf_gpio_pin_clear(PROXIMITY_I2C_RDY);
    
    delay_ms(10);
    
    nrf_gpio_cfg_input(PROXIMITY_I2C_RDY, NRF_GPIO_PIN_PULLUP);
    
    
    int i=0;
    for (i=0; i<200; i++) {
        if (!nrf_gpio_pin_read(PROXIMITY_I2C_RDY)) {
            break;
        }
        delay_ms(1);
    }
    
    if (i == 200) {
        RMLOG("Broke out, never detected");
    }
    RMLOG("Detected after %u",i);
    
  • Does it say anywhere that you should take control of the RDY pin like this?

    Maybe you can try to use a TWI event handler and see if it returns any error codes that make sense.

    Anyway I think a logic trace might be very helpful.

  • I looked at the driver you sent (I had another one from the chip co) and it's doing what I'm doing.. so I think its a HW fault on my boards. They are new (Board bring up) but simple but hey.. never know.

    Might have to wait until I can get the scope/logic analyser on it.. give me a chance to try my new analyser!!

    And yeah, the docs say to do it that way.. I don't think the line ever moves from ground which makes me wonder if the chip is powered/working at all.. I don't even have a multi-meter with me which is a pain.

  • It's a nice part, its got some crazy range for a capacitive prox pickup... best out of about 5 chips I tried.

    Plus works across the V range of the Nordic.. so its a nice tidy combo.

Related