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

I2C reads/writes: How to communicate with a 7bit I2C slave that has a 16bit memory map?

I am working with a sensor IC (IQS572) that communicates via I2C with my main microcontroller. Im using the nRF52382 chip. This sensor IC has a 7bit I2C slave address, but all of its internal registers that I want to read/write from have 16bit (2 byte) addresses. Most of my experience is with 8bit addressing schemes, so I am struggling a bit to set up my I2C/TWI code to properly configure this sensor IC. I have not been successful finding Nordic Forum posts that provide the answer I need. I have included my attempt for 16bit reads and writes below. twiRegRead16() seems to work as expected, but twiRegWrite16() doesnt seem to work.

The requirements from the sensor IC for an I2C write operation are as follows:

START, Slave Address + WRITE, ACK, Register Address HIGH, ACK, Register Address LOW, ACK, <data N>, ACK, <data n+1>, ACK, STOP

Notice there is no repeated START, as would be the case with the TXTX descriptor. Perhaps there is an easy way to prevent the repeated START for these specific writes?

uint32_t twiRegWrite16(uint8_t slaveAddr, uint16_t regAddr, uint8_t const * pdata, uint16_t length)
{
    uint32_t ret;
    uint8_t upperAddr = (regAddr >> 8) & 0x00FF;
    uint8_t lowerAddr = regAddr & 0x00ff;

    uint8_t tx_buff[2];
    tx_buff[1] = lowerAddr;
    tx_buff[0] = upperAddr;
    nrf_drv_twi_xfer_desc_t xfer;

    xfer.type = NRF_DRV_TWI_XFER_TX;
    xfer.address = slaveAddr;
    xfer.primary_length = sizeof(tx_buff);
    xfer.secondary_length = length;
    xfer.p_primary_buf = tx_buff;
    xfer.p_secondary_buf = pdata;
    m_xfer_status = 0;

    // NOTE: Could something as simple as this work instead?
    //uint8_t buffer[length + 2];
    //buffer[0] = upperAddr;
    //buffer[1] = lowerAddr;
    //memcpy(buffer + 2, pdata, length);
    //nrf_drv_twi_xfer_desc_t xfer = NRF_DRV_TWI_XFER_DESC_TX(slaveAddr, buffer, length + 1);

    ret = nrf_drv_twi_xfer(&m_twi, &xfer, 0);

    if (NRF_SUCCESS != ret)
    {
        return ret;
    }

    // Wait for response for 5 ms
    for(uint32_t k = 0; k <= 50; k++)
    {
        if(m_xfer_status != 0)
        {
            nrf_delay_ms(1);
            break;
        }
        nrf_delay_us(1);
    }

    if(m_xfer_status == TWI_XFER_STATUS_SUCCESS)
    {
        return NRF_SUCCESS;
    }
    else
    {
        return NRF_ERROR_INTERNAL;
    }
}


uint32_t twiRegRead16(uint8_t slaveAddr, uint16_t regAddr, uint8_t * pdata, uint16_t length)
{
    uint32_t ret;
    uint8_t tx_buff[2];

    m_xfer_status = 0;
    uint8_t upperAddr = (regAddr >> 8) & 0x00FF;
    uint8_t lowerAddr = regAddr & 0x00ff;
    tx_buff[1] = lowerAddr;
    tx_buff[0] = upperAddr;

    nrf_drv_twi_xfer_desc_t xfer = NRF_DRV_TWI_XFER_DESC_TXRX(slaveAddr, tx_buff, 2, pdata, length);
    ret = nrf_drv_twi_xfer(&m_twi, &xfer, 0);

    if (NRF_SUCCESS != ret)
    {
        return ret;
    }

    // Wait for response for 5 ms
    for(uint32_t k = 0; k <= 5000; k++)
    {
        if(m_xfer_status != 0)
        {
            nrf_delay_ms(1);
            break;
        }
        nrf_delay_us(1);
    }

    if(m_xfer_status == TWI_XFER_STATUS_SUCCESS)
    {
        return NRF_SUCCESS;
    }
    else
    {
        return NRF_ERROR_INTERNAL;
    }
}



  • Hi there,

    The write code that is commented out looks ok. Could you try that one? I think the secondary buffer are ignored on a normal TX. 

    regards

    Jared 

  • Hi Jared. I had initially started with that commented out approach, but moved to the uncommented approach above because it wasnt working at first. I now realize I had a very small bug that was a result of copy/pasting the function skeleton from my previous 8bit implementation. For anyone looking at this post, the bug was in the line nrf_drv_twi_xfer_desc_t xfer = NRF_DRV_TWI_XFER_DESC_TX(slaveAddr, buffer, length + 1); where I was inputting length + 1 erroneously instead of length +2 to account for the 2bytes of the 16bit register address instead of just the 1byte for the 8bit register addresses.

Related