Issue
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
Solution
Based on the device tree, the address that needs to be fed to IOCtl is the i2cswitch mux address. This address is 0x74, which can be seen in the device tree. Opening the i2c-0 device file corresponds to the i2c0 entry in the device tree which is parent to the mux. When writing to EEPROM, the first byte in the buffer should be the device address, as mentioned by @AndrewCottrell. This address is 0x54. The second byte should be the data you want to write
#define I2C_ADAPTER "/dev/i2c-0"
#define I2C_SWITHC_MUX_ADDRESS 0x74
#define DEVICE_ADDRESS 0x54
...
file = open(I2C_ADAPTER, O_RDWR); /* Check for error */
ioctl(file, I2C_SLAVE_FORCE, I2C_SWITHC_MUX_ADDRESS); /* Check for error */
uint8_t reg, value;
reg = DEVICE_ADDRESS;
buf[0] = reg;
buf[1] = value;
write(file, buf, 2); /* Check for error */
read(file, buf, 1); /* Check for error */
/* buf[0] should be value*/
Answered By - John Frye
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.