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

Read and Write TWI Sensor Registers

Hi there,

I'm developing with the nRF52840 right now.

I'm trying to read some sensordata with TWI. The sensors are BMM150, BMI270 and BMP388.

Unfortunately, I already have problems with the my first sensor (BMM150), reading the Chip ID.

To read it, I have to set the Power Control Bit of the sensor. That seems to be working.

But when I want to read registers again, I only get zeros. Even for reading the Power Control Bit.


This is the function to write Registers:

bool writeRegister(uint8_t regNumber, uint8_t value){
  ret_code_t err_code;

  uint8_t valueBuffer[2];
  valueBuffer[0] = regNumber;
  valueBuffer[1] = value;
  err_code = nrf_drv_twi_tx(&m_twi, 0x10, valueBuffer, sizeof(valueBuffer), false);
  APP_ERROR_CHECK(err_code);
  return 1;
}


Read Registers:

uint8_t readRegister(uint8_t regNumber){
  ret_code_t err_code;

  uint8_t resultsWhoAmI;
  uint8_t whoAmIPointer = regNumber;
  err_code = nrf_drv_twi_tx(&m_twi, 0x10, &whoAmIPointer, 1, true);
  err_code = nrf_drv_twi_rx(&m_twi, 0x10, &resultsWhoAmI, 1);
  APP_ERROR_CHECK(err_code);

  return resultsWhoAmI;
}



Main to test reading the Chip ID. Later on I want to use the Bosch Sensortec API. But first I want this one to work:
int main(void)
{
    ret_code_t err_code;
    uint8_t address = 0x10;
    uint8_t read_data;
    uint8_t write_data;

 
    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    NRF_LOG_INFO("Read Chip ID started");

    NRF_LOG_FLUSH();
    twi_init();

    // Read Power Control Bit
    read_data = readRegister(0x4B);
    uint8_t pwr_bit = read_data & 0b1;
    NRF_LOG_INFO("Read Power Control = %x", pwr_bit);
    NRF_LOG_FLUSH();

    write_data = read_data | 1;
    writeRegister(0x4B, write_data);
    NRF_LOG_INFO("Set Power Control Register to %x", write_data & 0b1);
    NRF_LOG_FLUSH();

    read_data = readRegister(0x4B);
    pwr_bit = read_data & 0b1;
    NRF_LOG_INFO("Read Power Control = %x", pwr_bit);
    NRF_LOG_FLUSH();


    read_data = readRegister(0x4C);
    uint8_t opMode = (read_data | 0b110) >> 1;
    NRF_LOG_INFO("Read MODE = %x", opMode);
    NRF_LOG_FLUSH();

    write_data = read_data | 0b00000110;
    writeRegister(0x4b, write_data);
    NRF_LOG_INFO("Set Mode Register to: %x", (write_data & 0b110)>>1);
    NRF_LOG_FLUSH();

    read_data = readRegister(0x4C);
    opMode = (read_data | 0b110) >> 1;
    NRF_LOG_INFO("Read MODE = %x", opMode);
    NRF_LOG_FLUSH();

    nrf_delay_ms(5000);

    read_data = readRegister(0x4B);
    pwr_bit = read_data & 0b1;
    NRF_LOG_INFO("Read Power Control = %x", pwr_bit);
    NRF_LOG_FLUSH();

    read_data = readRegister(0x40);
    NRF_LOG_INFO("Chip ID = %x", read_data);
    NRF_LOG_FLUSH();

}



This is the Output:

I've already read a couple of posts where others also had trouble reading on the bus after something was written. However, I couldn't find a solution.

Maybe somethings wrong with my code. I hope you could help me.


Thank you.







  • In the meantime I have tried all the sensors and have found the problem everywhere. 
    As soon as I write to a register, I can no longer perform read operations.
    It seems to be the same problem as in Reading and Writing to Registers using nrf52 TWI.

    Has the issue been resolved in the meantime? I'm using SDK 17.0.2

  • I just created a minimal example to reproduce the issue.

    I used the bmm150.

    In the first write operation I set the power control bit to 1 (has to be done to read the chip id). 

    When I just do this WRITE Operation the reading of the chip ID works fine.

    But if I write the mode register beforehand (without changing anything), the reading of the Chip ID doesn't work anymore.

    I hope this helps to reproduce the issue

    #include <stdio.h>
    #include "boards.h"
    #include "app_util_platform.h"
    #include "app_error.h"
    #include "nrf_delay.h"
    
    // include I2C Lib
    #include "nrf_drv_twi.h"
    
    // include LOG Libs
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    
    /* TWI instance ID. */
    #define TWI_INSTANCE_ID     0
    
    /* TWI instance. */
    static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);
    
    
    /**
     * @brief TWI initialization.
     */
    void twi_init (void)
    {
        ret_code_t err_code;
    
        const nrf_drv_twi_config_t twi_config = {
           .scl                = SCL0_PIN,
           .sda                = SDA0_PIN,
           .frequency          = NRF_DRV_TWI_FREQ_100K,
           .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
           .clear_bus_init     = true
        };
    
        err_code = nrf_drv_twi_init(&m_twi, &twi_config, NULL, NULL);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_twi_enable(&m_twi);
    }
    
    bool writeRegister(uint8_t regNumber, uint8_t value){
      ret_code_t err_code;
    
      uint8_t valueBuffer[2];
      valueBuffer[0] = regNumber;
      valueBuffer[1] = value;
      err_code = nrf_drv_twi_tx(&m_twi, 0x10, valueBuffer, sizeof(valueBuffer), false);
      APP_ERROR_CHECK(err_code);
      return 1;
    }
    
    uint8_t readRegister(uint8_t regNumber){
      ret_code_t err_code;
    
      uint8_t resultsWhoAmI;
      uint8_t whoAmIPointer = regNumber;
      err_code = nrf_drv_twi_tx(&m_twi, 0x10, &whoAmIPointer, 1, false);
      err_code = nrf_drv_twi_rx(&m_twi, 0x10, &resultsWhoAmI, 1);
      APP_ERROR_CHECK(err_code);
    
      return resultsWhoAmI;
    }
    
    
    /**
     * @brief Function for main application entry.
     */
    int main(void)
    {
        ret_code_t err_code;
        uint8_t address = 0x10;
        uint8_t read_data;
        uint8_t write_data;
        
        nrf_delay_ms(00);
     
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        NRF_LOG_INFO("Read Chip ID started");
    
        NRF_LOG_FLUSH();
        twi_init();
    
        nrf_delay_ms(500);
    
        // Read Power Control Bit
        read_data = readRegister(0x4B);
        uint8_t pwr_bit = read_data & 0b1;
        NRF_LOG_INFO("Read Power Control = %x", read_data);
        NRF_LOG_FLUSH();
    
        write_data = read_data | 1;
        writeRegister(0x4B, write_data);
        NRF_LOG_INFO("Set Power Control Register to %x", write_data & 0b1);
        NRF_LOG_FLUSH();
    
        read_data = readRegister(0x4B);
        pwr_bit = read_data & 0b1;
        NRF_LOG_INFO("Read Power Control = %x", pwr_bit);
        NRF_LOG_FLUSH();
    
    
        read_data = readRegister(0x4C);
        uint8_t opMode = (read_data | 0b110) >> 1;
        NRF_LOG_INFO("Read MODE = %x", opMode);
        NRF_LOG_FLUSH();
    
        write_data = read_data | 0b00000110;
        writeRegister(0x4b, write_data);
        NRF_LOG_INFO("Set Mode Register to: %x", (write_data & 0b110)>>1);
        NRF_LOG_FLUSH();
    
    
        while(1){
          nrf_delay_ms(500);
          read_data = readRegister(0x4B);
          pwr_bit = read_data & 0b1;
          NRF_LOG_INFO("Read Power Control = %x", pwr_bit);
          NRF_LOG_FLUSH();
    
          read_data = readRegister(0x40);
          NRF_LOG_INFO("Chip ID = %x", read_data);
          NRF_LOG_FLUSH();
       }
    }

  • Hi,

    How does your twi_init function look? If you have provided an event handler, you need some synchronization mechanism before starting the next transfer. You are also not checking the return code from the first nrf_drv_twi_tx call in readRegister(), it may report an error code.

    I do not have the sensor available, so I'm not able to try to reproduce your issue.

    Have you checked the TWI bus with a logic analyzer, to see if the commands are sent/received correctly? Please post logic traces.

    Best regards,
    Jørgen

  • Hi Jørgen, 

    thanks for your reply.

    I got the twi_init() function from an SDK example: 

    /* TWI instance ID. */
    #define TWI_INSTANCE_ID     0
    
    /* TWI instance. */
    static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);
    
    
    /**
     * @brief TWI initialization.
     */
    void twi_init (void)
    {
        ret_code_t err_code;
    
        const nrf_drv_twi_config_t twi_config = {
           .scl                = SCL0_PIN,
           .sda                = SDA0_PIN,
           .frequency          = NRF_DRV_TWI_FREQ_100K,
           .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
           .clear_bus_init     = true
        };
    
        err_code = nrf_drv_twi_init(&m_twi, &twi_config, NULL, NULL);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_twi_enable(&m_twi);
    }

    I also added an APP_ERROR_CHECK() to the first TX Operation in readRegister. It also returns NRF_SUCCESS.

    The logic analyzer returned the expected result: The SDA line stays on low level when reading the register.

    I tried the same code with an arduino and there it works without any issues.

    Could it be possible that the nRF52 doesn't release the bus and that's why it stays on low level?

    Do I have to change some configurations maybe?

  • Which pins are you using for SCL0_PIN/SDA0_PIN?

    Have you tried with ".clear_bus_init     = false"? I do not think this should make any difference, but it is not set in the twi_sensor example.

    Look like you changed the no_stop parameter to nrf_drv_twi_tx() in readRegister() between your initial post and the post with the full main.c file. I'm quite sure that this should be set to true for a read operation on this sensor.

    CMan1 said:
    The logic analyzer returned the expected result: The SDA line stays on low level when reading the register.

    Can you still post the logic trace? It may help explain what is causing this by looking at the previous transfers.

Related