├── .gitignore ├── Makefile ├── README.md └── i2c_example.c /.gitignore: -------------------------------------------------------------------------------- 1 | i2c_example 2 | *.o 3 | *.swp 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE := arm-linux-gnueabi- 2 | 3 | CC := $(CROSS_COMPILE)gcc 4 | 5 | CFLAGS := -Wall -std=gnu11 -ggdb 6 | 7 | SRC := i2c_example.c 8 | OBJ := $(SRC:.c=.o) 9 | 10 | PROG := i2c_example 11 | 12 | all: $(PROG) 13 | 14 | $(PROG): $(OBJ) 15 | $(CC) -static $^ -o $@ 16 | 17 | clean: 18 | $(RM) $(PROG) $(OBJ) 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple Linux i2c example 2 | 3 | This is a simple program to read a byte from an i2c client under Linux. It is 4 | provided as example code; if you want a real program use 5 | [i2cget](https://linux.die.net/man/8/i2cget) from the 6 | [i2c-tools](https://github.com/groeck/i2c-tools) package. 7 | 8 | It assumes the i2c client does not have a driver bound to it. If you have a 9 | driver bound, it might look like this: 10 | 11 | ``` 12 | # i2c_example /dev/i2c-9 0x4a 0 13 | i2c_example: Tried to set device address '0x4a': Device or resource busy 14 | ``` 15 | 16 | To unbind, use sysfs: 17 | 18 | ``` 19 | # ls /sys/bus/i2c/drivers/lm75 20 | 9-004a bind uevent unbind 21 | # echo 9-004a > /sys/bus/i2c/drivers/lm75/unbind 22 | ``` 23 | 24 | If you want to go in to expert mode, change `I2C_SLAVE` to `I2C_SLAVE_FORCE` 25 | in the `ioctl` which will let you read from the client even with a driver 26 | bound. If you do this you get to keep both pieces. 27 | 28 | ## Building 29 | 30 | The program assumes you have a GCC called `arm-linux-gnueabi-gcc` in your path. 31 | On Ubuntu, this can be installed with `apt-get install gcc-arm-linux-gnueabi`. 32 | 33 | If you obtain your compiler through different means, update the `CROSS_COMPILE` 34 | prefix in `Makefile` with the prefix of your compiler. 35 | 36 | If you want to compile natively, unset the `CROSS_COMPILE` variable. 37 | 38 | 39 | ``` 40 | $ make 41 | arm-linux-gnueabi-gcc -Wall -std=gnu11 -ggdb -c -o i2c_example.o i2c_example.c 42 | arm-linux-gnueabi-gcc -static i2c_example.o -o i2c_example 43 | ``` 44 | 45 | This builds a statically linked program that you can then copy to the target machine. 46 | 47 | ## Usage 48 | 49 | ``` 50 | # i2c_example 51 | i2c_example: path [i2c address] [register] 52 | 53 | # i2c_example /dev/i2c-3 0x76 0x1 54 | /dev/i2c-3: device 0x76 at address 0x01: 0x00 55 | ``` 56 | -------------------------------------------------------------------------------- /i2c_example.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple I2C example 3 | * 4 | * Copyright 2017 Joel Stanley 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, 28 | int size, union i2c_smbus_data *data) 29 | { 30 | struct i2c_smbus_ioctl_data args; 31 | 32 | args.read_write = read_write; 33 | args.command = command; 34 | args.size = size; 35 | args.data = data; 36 | return ioctl(file,I2C_SMBUS,&args); 37 | } 38 | 39 | 40 | static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command) 41 | { 42 | union i2c_smbus_data data; 43 | if (i2c_smbus_access(file,I2C_SMBUS_READ,command, 44 | I2C_SMBUS_BYTE_DATA,&data)) 45 | return -1; 46 | else 47 | return 0x0FF & data.byte; 48 | } 49 | 50 | int main(int argc, char **argv) 51 | { 52 | uint8_t data, addr = 0x76, reg = 0x0d; 53 | const char *path = argv[1]; 54 | int file, rc; 55 | 56 | if (argc == 1) 57 | errx(-1, "path [i2c address] [register]"); 58 | 59 | if (argc > 2) 60 | addr = strtoul(argv[2], NULL, 0); 61 | if (argc > 3) 62 | reg = strtoul(argv[3], NULL, 0); 63 | 64 | file = open(path, O_RDWR); 65 | if (file < 0) 66 | err(errno, "Tried to open '%s'", path); 67 | 68 | rc = ioctl(file, I2C_SLAVE, addr); 69 | if (rc < 0) 70 | err(errno, "Tried to set device address '0x%02x'", addr); 71 | 72 | data = i2c_smbus_read_byte_data(file, reg); 73 | 74 | printf("%s: device 0x%02x at address 0x%02x: 0x%02x\n", 75 | path, addr, reg, data); 76 | 77 | } 78 | 79 | --------------------------------------------------------------------------------