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

I2C: How do I specify a register address to read from when calling nrf_drv_twi_rx()?

I'm using nrf_drv_twi to talk to an accelerometer from an nRF51822 on a custom board. I'm on SDK 10.0.0. I'm following the example from the SDK, peripheral/twi_sensor. And I'm using blocking mode, with no handler.

In the calls to nrf_drv_twi_tx(), I see the example code is using a two element array of uint8_t where the first element is the register address and the second is the value.

register_value_pair[0] = KXTJ2_CTRL_REG1;
register_value_pair[1] = 0b00000000;
err_code = nrf_drv_twi_tx(&m_twi_kionix, KIONIX_SLAVE_ADDRESS, register_value_pair,
		sizeof(register_value_pair), false);
APP_ERROR_CHECK(err_code);

So far so good. But when it comes to the RX, the third param is just data, with no register address. How can the slave device or the driver possibly know which register I'm reading?

  • Hi Eliot,

    I have not used the KXTJ2 accelerometer, but can find output registers in datasheet of it. Here is an example to read accelerometer values.

    #define KXTJ2_XOUT_L		0x06
    #define KXTJ2_XOUT_H		0x07
    #define KXTJ2_YOUT_L		0x08
    #define KXTJ2_YOUT_H		0x09
    #define KXTJ2_ZOUT_L		0x0A
    #define KXTJ2_ZOUT_H		0x0B    
    
    ret_code_t err_code;
    uint8_t accelvalue[6];
    uint8_t addr8 = KXTJ2_XOUT_L;
    
    err_code = nrf_drv_twi_tx(&m_twi_kionix, KIONIX_SLAVE_ADDRESS, &addr8, 1, true);
    if (NRF_SUCCESS == err_code)
        err_code = nrf_drv_twi_rx(&m_twi_kionix, KIONIX_SLAVE_ADDRESS, accelvalue, 6, false);
    APP_ERROR_CHECK(err_code);
    

    If you want read the CTRL_REG1 register,

    ret_code_t err_code;
    uint8_t value;
    uint8_t addr8 = KXTJ2_CTRL_REG1;
    
    err_code = nrf_drv_twi_tx(&m_twi_kionix, KIONIX_SLAVE_ADDRESS, &addr8, 1, true);
    if (NRF_SUCCESS == err_code)
        err_code = nrf_drv_twi_rx(&m_twi_kionix, KIONIX_SLAVE_ADDRESS, &value, 1, false);
    APP_ERROR_CHECK(err_code);
    

    Merry Christmas. :)

  • Thanks for responding on Christmas Eve! This is helpful but I'm still confused, sorry. Are you saying if ever I want to read a register, I first have to write to it? What if I don't want to change the value? Seems a strange approach. Maybe this is an I2C idiom I've been missing or something?

  • Yes, you have to write to register. The sceret is in the slave address. Internally nrf_drv_twi_rx and nrf_drv_twi_tx use 8 bit address. When we pass 7 bit address to these functions, they shift it to make 8 bit. At this time nrf_drv_twi_tx translates slave address to ((address << 1) | 0) and nrf_drv_twi_rx translates to ((address << 1) | 1). Therefore the slave addresses of RX and TX are distinguished from each other in fact. The slave device understands that slave address ends with 1 on last bit is a command to read register values, and address ends with 0 is command a to write it. That is an I2C idiom.

Related