Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

TWI manager read too many bytes?

Hi
despite trying 3 different approaches (even using the Nordic driver lis2dh12 on a blinky-based project and installing Segger Studio to step/debug into the library code) I keep stumbling over the same problem. I try to read 1 byte from LIS2DH sensor using TWI manager. My mistake must be so big I can't see it :-(

I boiled down the code to a few lines and I think this is not specific to the LIS2DH. I expect it to behave the same way on other I2C devices too.

I set up a transaction to read one byte from WHO_AM_I register on the sensor. The read is performed and it returns error == 0 and the correct constant value == 0x33 from the sensor.
Looks as if everything is working perfectly. BUT the oscilloscope reveals that 2 bytes have been fetched from the sensor:

the first read has ACK, the second read is NACKed.

I boiled down the code to the minimum:

static void twi_config(void) {
    uint32_t err_code;

    nrf_drv_twi_config_t const config = {
       .scl                = I2C_PIN_SCL,
       .sda                = I2C_PIN_SDA,
       .frequency          = NRF_DRV_TWI_FREQ_100K,
       .interrupt_priority = APP_IRQ_PRIORITY_LOWEST,
       .clear_bus_init     = false
    };

    err_code = nrf_twi_mngr_init(&m_nrf_twi_mngr, &config);
    APP_ERROR_CHECK(err_code);
}


uint8_t NRF_TWI_MNGR_BUFFER_LOC_IND lis2dh_whoami_reg_addr = 0x0F;
uint8_t NRF_TWI_MNGR_BUFFER_LOC_IND lis2dh_whoami_value = 0;
#define LIS2DH_WHO_AM_I_TRANSFER_COUNT     2

static nrf_twi_mngr_transfer_t const lis2dh_WHO_AM_I_transfers[LIS2DH_WHO_AM_I_TRANSFER_COUNT] = {
    NRF_TWI_MNGR_WRITE(LIS2DH_ADDR, &lis2dh_whoami_reg_addr, 1, NRF_TWI_MNGR_NO_STOP), \
    NRF_TWI_MNGR_READ (LIS2DH_ADDR, &lis2dh_whoami_value,    1, 0)
};

int main(void) {
    ret_code_t err_code;

    log_init();
    lfclk_config();
    err_code = nrf_pwr_mgmt_init();
    APP_ERROR_CHECK(err_code);
    NRF_LOG_INFO("test WHO_AM_I started");
    NRF_LOG_FLUSH();

    twi_config();

    err_code = nrf_twi_mngr_perform(&m_nrf_twi_mngr, NULL, lis2dh_WHO_AM_I_transfers, LIS2DH_WHO_AM_I_TRANSFER_COUNT, NULL);
    NRF_LOG_INFO("err_code %d    who_am_i 0x%0x", err_code, lis2dh_whoami_value);

    while (true) {
        nrf_pwr_mgmt_run();
        NRF_LOG_FLUSH();
    }
}

I use SDK16 and in sdk_config I have set

#define NRFX_TWIM_ENABLED 1
#define NRFX_TWIM0_ENABLED 1
#define NRFX_TWIM1_ENABLED 0

#define NRFX_TWI_ENABLED 1
#define NRFX_TWI0_ENABLED 1
#define NRFX_TWI1_ENABLED 0

#define TWI_ENABLED 1
#define TWI0_ENABLED 1
#define TWI0_USE_EASY_DMA 0
#define TWI1_ENABLED 0
#define TWI1_USE_EASY_DMA 0
#define NRF_TWI_MNGR_ENABLED 1

Looks like I do the same mistake over and over again.
When I discovered the Nordic driver for LIS2dDH I thought I was saved. But reading WHO_AM_I with this driver produces the same bogus result.
Reading WHO_AM_I twice is not a problem. but when it comes to reading other registers this leads to a mess.
Any suggestions?

have fun
Peter

Related