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

Issues reading virtual registers via I2C

Hello,

I have an AMS AS7261 light sensor that I'm using with my NRF51422 DK to take a light reading, pull it using nrf_drv_twi_tx/rx, and send it over BLE. However, when I try to read from the virtual registers of interest, nearly each of the registers return 0. Below is my function:

void read_sensor(uint16_t values[], const uint8_t registers[]) {

  uint8_t reg_addr = registers[0]; //first virtual register to read
  uint8_t end_reg = registers[1];
  uint8_t buf;
  ret_code_t status;
  uint16_t value;
  int counter = 0;

  while (reg_addr < end_reg) {
    value = 0;

    //Read higher byte
    buf = 0;
    while(true){
      status = nrf_drv_twi_tx(&m_twi, AS72XX_ADDR, &reg_addr, sizeof(reg_addr), true);
      if (status == NRF_SUCCESS)
        break;
    }

    while(true) {
      status = nrf_drv_twi_rx(&m_twi, AS72XX_ADDR, &buf, sizeof(buf));
      if (status == NRF_SUCCESS)
        break;
    }
    printf("Value at register %#x: %#x\r\n", reg_addr, buf);
    value = (buf<<8); //record higher byte
    reg_addr++;

    //Read lower byte
    buf = 0;
    while(true){
      status = nrf_drv_twi_tx(&m_twi, AS72XX_ADDR, &reg_addr, sizeof(reg_addr), true);
      if (status == NRF_SUCCESS)
        break;
    }

    while(true) {
      status = nrf_drv_twi_rx(&m_twi, AS72XX_ADDR, &buf, sizeof(buf));
      if (status == NRF_SUCCESS)
        break;
    }
    printf("Value at register %#x: %#x\r\n", reg_addr, buf);
    value += buf; //record lower byte
    reg_addr++;

    values[counter] = value; //store raw value in array
    counter++;
  }
}

I want to read each of the raw data registers, which according to the datasheet are registers 0x08 to 0x13:

The only registers that return a value other than 0 are the last 4, but the values I get are also wrong (in that they do not match up with the values shown in the provided GUI to read these values).

At this point I suspect this may be more of an issue with the sensor or how I'm reading it, but if it is an issue with my code any help is appreciated!

Thank you.

Parents
  • Hi Bennett

    Could there be some init/configuration sequence that you have to run before accessing these registers?

    Are there any registers in the sensor that hold a fixed value, that you could use to debug the communication?
    Many sensors have some kind of device ID register that will never change. 

    Have you tried to scope the lines to see what happens on the bus?

    Assuming the nrf_drv_twi_tx/rx calls are blocking I can't see any issues with the code. Can you let me know which SDK version you are using?

    Best regards
    Torbjørn

  • I'm using SDK 12.03.

    I'm now noticing a few oddities when I use the scope. After doing a write (with nrf_drv_twi_tx), it mostly looks fine but SCL does not return to high at the end of the call. When I call the subsequent read, it looks like there's a NACK, but nrf_drv_twi_rx returns NRF_SUCCESS. I'll attach the scope captures below:

    Write:

    Read:

    I'm kind of new to this stuff so I'm not sure where the issue may lie, I'm thinking it's in the sensor, I've tried contacting the manufacturer. I also noticed that on the read, there isn't the "break" in the clock line between the end of the address and the start of the data like there is in the write screenshot, not sure if that's an issue or not.

    Thank you for your help,

    Bennett

  • Hi Bennett

    Thanks for the traces. 

    To me they look pretty normal. I tried running some comparable code on a nRF52DK which reads an LM75BD temperature sensor and an MMA7660 accelerometer over I2C, and the results are comparable.

    Granted it's running on a nRF52 device and not a nRF51, but the driver is the same, and I also see the 'missing' gap in the RX calls which is not there when sending data.

     I also think it's normal for the sensor to send a NACK after the last byte of information has been sent, to signal that no more data is coming. I see similar behavior from the LM75BD and MMA7660 devices. 

    Do you have a data sheet for the sensor that I could have a look at?

    Best regards
    Torbjørn

  •  I also think it's normal for the sensor to send a NACK after the last byte of information has been sent

    Yes - it is.

  • Hi Torbjørn,

    Thank you for your detailed respone. The data sheet is available here.

    Thanks,

    Bennett

  • Hi Bennett

    Thanks for sharing the data sheet. 

    Reading through the sample code for reading and writing the virtual registers this seems considerably more complicated than similar sensors I have worked with, and I am not sure the code you sent me is equivalent to the code they provided. 

    For one thing their virtual register read example starts with a read loop, to wait for the read buffer to be ready, while your code starts with a write. 

    Secondly, it is important to note that the nrf_drv_twi_rx function returns any error code returned by the TWI driver, it doesn't return the data read. The data read is stored in the buffer that you pass into the function. 

    In other words you have to implement the while(1) loops in the virtual register write/read procedures a bit different from what they do in the data sheet in order to properly check the status data returned from the sensor. 

    Best regards
    Torbjørn 

  • Hi Torbjørn,

    Thank you again for your help. I have resolved this issue by adding some extra read/writes. It looks like the main fix was changing the p_data argument in nrf_drv_twi_tx from just the virtual register address to an array holding both the HW write register and the virtual address.

    However, I'm running into a new issue now. When I read all the values from these registers, the registers seem to be "offset" by 1. For example, the value I should get for R0 is instead returned for R1, the value I should get for R1 is returned for R2, etc. My code is below, do you know why this may be happening?

    void read_sensor(uint16_t values[], const uint8_t registers[]) {
      uint8_t reg = 0;
      uint8_t read_addy = I2C_AS72XX_SLAVE_READ_REG;
      uint8_t stat_addy = I2C_AS72XX_SLAVE_STATUS_REG;
      uint8_t reg_addr[2] = {I2C_AS72XX_SLAVE_WRITE_REG, registers[0]}; //first virtual register to read
      uint8_t end_reg = registers[1];
      uint8_t buf;
      ret_code_t status;
      int counter = 0;
      FILE *fp;
      fp = fopen("./test.txt", "w");
    
      while (reg_addr[1] <= end_reg) {
        buf = 0;
    
        //Check status
        while (true) {
          nrf_drv_twi_tx(&m_twi, AS72XX_ADDR, &stat_addy, sizeof(stat_addy), true);
          status = nrf_drv_twi_rx(&m_twi, AS72XX_ADDR, &buf, sizeof(buf));
          if ((buf & I2C_AS72XX_SLAVE_TX_VALID) == 0)
            break;
        }
        buf = 0;
    
        //Write virtual address
        while(true) {
          status = nrf_drv_twi_tx(&m_twi, AS72XX_ADDR, reg_addr, sizeof(reg_addr), true);
          if (status == NRF_SUCCESS)
            break;
        }
    
        //Check status
        while(true) {
          nrf_drv_twi_tx(&m_twi, AS72XX_ADDR, &stat_addy, sizeof(stat_addy), true);
          status = nrf_drv_twi_rx(&m_twi, AS72XX_ADDR, &buf, sizeof(buf));
          if ((buf & I2C_AS72XX_SLAVE_RX_VALID) != 0)
            break;
        }
        buf = 0;
    
        //Read virtual register
        while(true) {
          status = nrf_drv_twi_tx(&m_twi, AS72XX_ADDR, &read_addy, 1, true);
          if (status == NRF_SUCCESS)
            break;
        }
    
        while(true) {
          status = nrf_drv_twi_rx(&m_twi, AS72XX_ADDR, &buf, sizeof(buf));
          if (status == NRF_SUCCESS)
            break;
        }
    
        printf("Value at register %#x: %#x\r\n", reg_addr[1], buf);
        fprintf(fp, "Value at register %#x: %#x\r\n", reg_addr[1], buf);
        reg_addr[1]++;
      }
      fclose(fp);
    }
    
    ...
    
    int main() {
    ...
        uint16_t values[6];
        const uint8_t regs[2] = {0x00, 0x13};
        read_sensor(values, regs);
    ...
    }

    Thank you again for your help,

    Bennett Sasaki

Reply
  • Hi Torbjørn,

    Thank you again for your help. I have resolved this issue by adding some extra read/writes. It looks like the main fix was changing the p_data argument in nrf_drv_twi_tx from just the virtual register address to an array holding both the HW write register and the virtual address.

    However, I'm running into a new issue now. When I read all the values from these registers, the registers seem to be "offset" by 1. For example, the value I should get for R0 is instead returned for R1, the value I should get for R1 is returned for R2, etc. My code is below, do you know why this may be happening?

    void read_sensor(uint16_t values[], const uint8_t registers[]) {
      uint8_t reg = 0;
      uint8_t read_addy = I2C_AS72XX_SLAVE_READ_REG;
      uint8_t stat_addy = I2C_AS72XX_SLAVE_STATUS_REG;
      uint8_t reg_addr[2] = {I2C_AS72XX_SLAVE_WRITE_REG, registers[0]}; //first virtual register to read
      uint8_t end_reg = registers[1];
      uint8_t buf;
      ret_code_t status;
      int counter = 0;
      FILE *fp;
      fp = fopen("./test.txt", "w");
    
      while (reg_addr[1] <= end_reg) {
        buf = 0;
    
        //Check status
        while (true) {
          nrf_drv_twi_tx(&m_twi, AS72XX_ADDR, &stat_addy, sizeof(stat_addy), true);
          status = nrf_drv_twi_rx(&m_twi, AS72XX_ADDR, &buf, sizeof(buf));
          if ((buf & I2C_AS72XX_SLAVE_TX_VALID) == 0)
            break;
        }
        buf = 0;
    
        //Write virtual address
        while(true) {
          status = nrf_drv_twi_tx(&m_twi, AS72XX_ADDR, reg_addr, sizeof(reg_addr), true);
          if (status == NRF_SUCCESS)
            break;
        }
    
        //Check status
        while(true) {
          nrf_drv_twi_tx(&m_twi, AS72XX_ADDR, &stat_addy, sizeof(stat_addy), true);
          status = nrf_drv_twi_rx(&m_twi, AS72XX_ADDR, &buf, sizeof(buf));
          if ((buf & I2C_AS72XX_SLAVE_RX_VALID) != 0)
            break;
        }
        buf = 0;
    
        //Read virtual register
        while(true) {
          status = nrf_drv_twi_tx(&m_twi, AS72XX_ADDR, &read_addy, 1, true);
          if (status == NRF_SUCCESS)
            break;
        }
    
        while(true) {
          status = nrf_drv_twi_rx(&m_twi, AS72XX_ADDR, &buf, sizeof(buf));
          if (status == NRF_SUCCESS)
            break;
        }
    
        printf("Value at register %#x: %#x\r\n", reg_addr[1], buf);
        fprintf(fp, "Value at register %#x: %#x\r\n", reg_addr[1], buf);
        reg_addr[1]++;
      }
      fclose(fp);
    }
    
    ...
    
    int main() {
    ...
        uint16_t values[6];
        const uint8_t regs[2] = {0x00, 0x13};
        read_sensor(values, regs);
    ...
    }

    Thank you again for your help,

    Bennett Sasaki

Children
Related