How to read 16 bit hardware register

1.1k views Asked by At

I am working on VEML7700 Lux Sensor.datasheet link. I can detect the sensor and read/write data using i2c-tool. I2C address of sensor is 0x10. Here I am getting correct reading of 0x04 result register.

apalis-imx8-06852506:~$ i2cdetect -y -r 4
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: 10 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: 30 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         
apalis-imx8-06852506:~$ i2cget -y 4 0x10 0x00 w
0x0000
apalis-imx8-06852506:~$ i2cget -y 4 0x10 0x00 w
0x0000
apalis-imx8-06852506:~$ i2cget -y 4 0x10 0x04 w
0x0930
apalis-imx8-06852506:~$ i2cget -y 4 0x10 0x04 w
0x093c
apalis-imx8-06852506:~$ i2cget -y 4 0x10 0x04 w
0x0939
apalis-imx8-06852506:~$ 

When I am trying to read the register in c program i am getting constant 0 value. But I can write the configuration register using write command in c program also.

Here is my c program.

#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

//sensor i2c address is 0x44
#define SLAVE_ADDR 0x10

void main()
{
    // Create I2C bus
        int file;
        char *bus = "/dev/apalis-i2c1";
        if((file = open(bus, O_RDWR)) < 0) 
        {
                printf("Failed to open the bus. \n");
                exit(1);
        }
        // Get I2C device, VEML7700 I2C address is 0x10-7BIT
        ioctl(file, I2C_SLAVE, SLAVE_ADDR);

        //unsigned char reg[1] = {0};
        //unsigned char data[2] ;
        __uint16_t reg_data;

        //configuring the register 0x00
        char config[3] = {0};
        config[0] = 0x00;
        config[1] = 0x00;
        config[2] = 0x00;
        write(file,config,3);
        sleep(1);

        unsigned char reg[1] = {0x04};
        write(file, reg, 1);
        sleep(1);
        unsigned char data[2] = {0};
        if(read(file, data, 2) != 2)
        {
                printf("Erorr : Input/output Erorr \n");
                exit(1);
        }
        printf(" data[0] %x\n data[1] %x\n",data[0],data[1]);

        close(file);
}

root@apalis-imx8-06852506:/bhagwatws# gcc light_sensor.c -o light_sensor
root@apalis-imx8-06852506:/bhagwatws# ./light_sensor
 data[0] 0
 data[1] 0
root@apalis-imx8-06852506:/bhagwatws# ./light_sensor
 data[0] 0
 data[1] 0
root@apalis-imx8-06852506:/bhagwatws# ./light_sensor
 data[0] 0
 data[1] 0

1

There are 1 answers

0
Alexander On

Your attempt to read register 0x04 fails, because your write transaction to select register 0x04 and the following word read are not preformed within the same I2C transaction, but as separate transactions.

From https://www.kernel.org/doc/Documentation/i2c/dev-interface:

Note that only a subset of the I2C and SMBus protocols can be achieved by the means of read() and write() calls. In particular, so-called combined transactions (mixing read and write messages in the same transaction) aren't supported. For this reason, this interface is almost never used by user-space programs.

Instead use the following access method:

ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)