I am trying to read one value from a memory location on the I2C bus after writing to it. I am getting strange output when I run it in the terminal.
Here is my program
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#define I2C_ADAPTER "/dev/i2c-0"
#define I2C_DEVICE 0x00
int main (int argc, char *argv[])
{
int file;
int addr = 0X00; /* XGPIOPS_DATA_LOW_OFFSET */
if((file = open(I2C_ADAPTER, O_RDWR)) < 0) {
printf("Failed to open the bus");
return -1;
}
if(ioctl(file, I2C_SLAVE, addr) < 0) {
printf("Unable to open device as slave %s", strerror(errno));
return -1;
}
char buf[10];
buf[0] = addr;
buf[1] = 0x10;
if(write(file, buf, 2) != 2) {
printf("Failed to write to bus %s.\n\n", strerror(errno));
}
else {
printf("Successful write\n");
printf(buf);
printf("\n\n");
}
if(read(file, buf, 2) != 2) {
printf("Failed to read from the i2c bus. %s\n\n", strerror(errno));
}
else {
printf("Successful read\n");
printf(buf);
printf("\n\n");
}
return 0;
}
The output from the program looks like this
Successful write
Successful read ��
On my terminal those blocks look more like question marks inside of diamonds. I am not sure what that corresponds to in ASCII.
Why am I not reading back that 0x10 which is the second byte after the address byte that I originally write?
Based on the first set of answers, here is the updated code:
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#define I2C_ADAPTER "/dev/i2c-0"
#define I2C_DEVICE 0x00
int main (int argc, char *argv[])
{
int file;
long addr, reg_addr;
char *end;
if(argc == 3) {
addr = strtol(argv[1], &end, 16);
printf("Value of addr is: %ld\n", addr);
reg_addr = strtol(argv[2], &end, 16);
printf("Value of reg_addr is: %ld\n", reg_addr);
}
else {
printf("arg failed\n\n.");
addr = 0x00;
}
if((file = open(I2C_ADAPTER, O_RDWR)) < 0) {
printf("Failed to open the bus\n");
return -1;
}
if(ioctl(file, I2C_SLAVE, addr) < 0) {
printf("Unable to open device as slave \n%s\n", strerror(errno));
return -1;
}
char buf[10];
buf[0] = addr;
buf[1] = reg_addr;
buf[2] = 0x10;
if(write(file, buf, 3) != 3) {
printf("Failed to write to bus %s.\n\n", strerror(errno));
}
else {
printf("Successful write\n");
printf(buf);
printf("\n\n");
}
if(read(file, buf, 3) != 3) {
printf("Failed to read from the i2c bus.\n %s\n\n", strerror(errno));
}
else {
printf("Successful read\n");
printf("Buf = [%02X,%02X,%02X]\n", buf[0], buf[1], buf[2]);
printf("\n\n");
}
return 0;
}
At this point, whenever I use 0x00 as the addr, I get FF, FF, FF as the output, no matter what argv[2] is. Here is the applicable part of the device tree file. Note that this is being emulated, so I cannot probe the physical device.
&i2c0 {
status = "okay";
clock-frequency = <400000>;
pinctrl-names = "default";
i2cswitch@74 {
compatible = "nxp,pca9548";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x74>;
i2c@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
si570: clock-generator@5d {
#clock-cells = <0>;
compatible = "silabs,si570";
temperature-stability = <50>;
reg = <0x5d>;
factory-fout = <156250000>;
clock-frequency = <148500000>;
};
};
i2c@2 {
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
eeprom@54 {
compatible = "at,24c08";
reg = <0x54>;
};
};
i2c@3 {
#address-cells = <1>;
#size-cells = <0>;
reg = <3>;
gpio@21 {
compatible = "ti,tca6416";
reg = <0x21>;
gpio-controller;
#gpio-cells = <2>;
};
};
i2c@4 {
#address-cells = <1>;
#size-cells = <0>;
reg = <4>;
rtc@51 {
compatible = "nxp,pcf8563";
reg = <0x51>;
};
};
i2c@7 {
#address-cells = <1>;
#size-cells = <0>;
reg = <7>;
hwmon@52 {
compatible = "ti,ucd9248";
reg = <52>;
};
hwmon@53 {
compatible = "ti,ucd9248";
reg = <53>;
};
hwmon@54 {
compatible = "ti,ucd9248";
reg = <54>;
};
};
};
};
Here are a couple of example tests
Try to test the SiLabs clock generator
root@plnx_arm:~# /usr/bin/i2c-test-mem-location 0x54 0x00
Value of addr is: 84
Value of reg_addr is: 0
Unable to open device as slave
Device or resource busy
Try to test the eeprom device
root@plnx_arm:~# /usr/bin/i2c-test-mem-location 0x5d 0x00
Value of addr is: 93
Value of reg_addr is: 0
Unable to open device as slave
Device or resource busy
This is my program on the third try. After taking to mind the notes made in the answers, I have this written
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#define I2C_ADAPTER "/dev/i2c-0"
#define DEVICE_ADDRESS 0x54
int main (int argc, char *argv[])
{
int file;
uint8_t reg, value;
char *end;
printf("The device address on the bus: %d", DEVICE_ADDRESS);
if(argc == 3) {
reg = strtol(argv[1], &end, 16);
printf("Value of register address: %d\n", reg);
value = strtol(argv[2], &end, 16);
printf("value to write is: %d\n", value);
}
else {
printf("arg failed\n\n.");
}
if((file = open(I2C_ADAPTER, O_RDWR)) < 0) {
printf("Failed to open the bus\n");
return -1;
}
if(ioctl(file, I2C_SLAVE, DEVICE_ADDRESS) < 0) {
printf("Unable to open device as slave \n%s\n", strerror(errno));
return -1;
}
char buf[10];
buf[0] = reg;
buf[1] = value;
if(write(file, buf, 2) != 2) {
printf("Failed to write to bus %s.\n\n", strerror(errno));
}
else {
printf("Successful write\n");
printf(buf);
printf("\n\n");
}
if(read(file, buf, 2) != 2) {
printf("Failed to read from the i2c bus.\n %s\n\n", strerror(errno));
}
else {
printf("Successful read\n");
printf("Buf = [%02X,%02X,%02X]\n", buf[0], buf[1], buf[2]);
printf("\n\n");
}
return 0;
}
Unfortunately, even still, I am getting the same error.
root@plnx_arm:~# /usr/bin/i2c-test-mem-location 0x00 0x10
The device address on the bus: 84Value of register address: 0
value to write is: 16
Unable to open device as slave
Device or resource busy
root@plnx_arm:~# /usr/bin/i2c-test-mem-location 0x30 0x10
The device address on the bus: 84Value of register address: 48
value to write is: 16
Unable to open device as slave
Device or resource busy
int main (int argc, char *argv[])
when the parameters tomain()
are not going to be used, you can avoid a couple of warnings from the compiler by using the signature:int main( void )
– user3629249printf("Failed to open the bus");
1) error messages should be output tostderr
, notstdout
. 2) when the error indication is from a system function, then should also output the text that indicates why the function failed. Suggest:perror( "open of I2C failed" );
– user3629249int addr = 0X00;
creates problems later in the posted code. Suggest:char addr = 0x00;
– user3629249