我尝试通过I2C读取和写入带有Raspberry Pi B +的Atmel 24C256 EEPROM,但是我无法正常工作。
这是我到目前为止的代码:
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <linux/i2c.h>
#define DEVICE_PATH "/dev/i2c-1"
#define PAGE_SIZE 64
#define DEVICE_ADDR 0x50 // 0b1010xxxx
int file_desc;
char buffer[PAGE_SIZE + 2]; // 64 bytes + 2 for the address
void teardownI2C()
{
int result = close(file_desc);
}
void setupI2C()
{
file_desc = open(DEVICE_PATH, O_RDWR);
if(file_desc < 0)
{
printf("%s\n", strerror(errno));
exit(1);
}
if(ioctl(file_desc, I2C_SLAVE, DEVICE_ADDR) < 0)
{
printf("%s\n", strerror(errno));
teardownI2C();
exit(1);
}
}
int write_to_device(char addr_hi, char addr_lo, char * buf, int len)
{
struct i2c_rdwr_ioctl_data msg_rdwr;
struct i2c_msg i2cmsg;
char my_buf[PAGE_SIZE + 2];
if(len > PAGE_SIZE + 2)
{
printf("Can't write more than %d bytes at a time.\n", PAGE_SIZE);
return -1;
}
int i;
my_buf[0] = addr_hi;
my_buf[1] = addr_lo;
for(i= 0; i < len; i++)
{
my_buf[2+i] = buf[i];
}
msg_rdwr.msgs = &i2cmsg;
msg_rdwr.nmsgs = 1;
i2cmsg.addr = DEVICE_ADDR;
i2cmsg.flags = 0;
i2cmsg.len = 2+len;
i2cmsg.buf = my_buf;
if(ioctl(file_desc,I2C_RDWR,&msg_rdwr)<0)
{
printf("write_to_device(): %s\n", strerror(errno));
return -1;
}
return 0;
}
int read_from_device(char addr_hi, char addr_lo, char * buf, int len)
{
struct i2c_rdwr_ioctl_data msg_rdwr;
struct i2c_msg i2cmsg;
if(write_to_device(addr_hi, addr_lo ,NULL,0)<0)
{
printf("read_from_device(): address reset did not work\n");
return -1;
}
msg_rdwr.msgs = &i2cmsg;
msg_rdwr.nmsgs = 1;
i2cmsg.addr = DEVICE_ADDR;
i2cmsg.flags = I2C_M_RD;
i2cmsg.len = len;
i2cmsg.buf = buf;
if(ioctl(file_desc,I2C_RDWR,&msg_rdwr)<0)
{
printf("read_from_device(): %s\n", strerror(errno));
return -1;
}
return 0;
}
void fill_buffer(char *buf)
{
int i = 0;
while(i < PAGE_SIZE && *buf)
{
buffer[i+2] = *buf++;
}
while(i++ < PAGE_SIZE-1)
{
buffer[i+2] = '*'; // fill the buffer with something
}
}
int main()
{
setupI2C(); //setup
fill_buffer("Here are some words.");
write_to_device(0x01, 0x00, buffer, PAGE_SIZE);
char newbuf[PAGE_SIZE];
if(read_from_device(0x01, 0x00, newbuf, PAGE_SIZE)>0)
{
printf("%s\n", newbuf);
}
teardownI2C(); //cleanup
return EXIT_SUCCESS;
}
在行write_to_device(0x01, 0x00, buffer, PAGE_SIZE);
中写入设备不会产生任何错误但是当我尝试从设备读取时,我必须根据规格表写一个“虚拟”字节,然后尝试从器件读取但由于某种原因写入虚拟字节会导致错误“输入/输出错误”。我无法弄清楚它是如何工作的。我正在使用两个资源来指导我,Linux I2C-Dev documentation以及来自similar EEPROM device.的示例我有点卡在这里,不知道该尝试什么。非常感谢任何建议或指示!
答案 0 :(得分:11)
或者,如果您能够为Raspberry Pi编译和安装不同的内核设备树,则可以通过内核at24.c
驱动程序访问它。
内核设备树需要指定EEPROM的类型和地址,以及它所连接的I²C总线。我不确定Raspberry Pi,但对于BeagleBone Black EEPROM,它是这样的:
&i2c0 {
eeprom: eeprom@50 {
compatible = "at,24c32";
reg = <0x50>;
};
};
对于您的设备,您需要指定compatible = "at,24c256";
确保内核配置指定CONFIG_EEPROM_AT24=y
(或=m
)。
然后,您应该可以通过/sys/bus/i2c/devices/0-0050/eeprom
或/sys/bus/i2c/drivers/at24/0-0050/eeprom
等用户空间访问EEPROM内存。
答案 1 :(得分:2)
也许这可能有帮助。 http://www.richud.com/wiki/Rasberry_Pi_I2C_EEPROM_Program因为它显然处理你正在尝试编程的设备,并解释了一些解决24c256的注意事项
答案 2 :(得分:1)
克雷格·麦昆(Craig McQueen)的回答使我走上了正确的轨道,但要自己弄清整个问题并不容易。
这是一个在Raspberry Pi上对我有用的AT24C256设备树覆盖:
LOBBY
将其保存到“ at24c256.dts”,使用以下命令对其进行编译(可能需要安装设备树编译器):
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target = <&i2c1>;
overlay {
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins>;
clock-frequency = <100000>;
status = "okay";
at24@50 {
compatible = "atmel,24c256","at24";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x50>;
pagesize = <64>;
size = <32768>;
address-width = <16>;
};
};
};
};
并将其保存在“ / boot / overlays”中。然后通过添加以下内容来激活叠加层:
dtc -O dtb -o at24c256.dtbo -b 0 -@ at24c256.dts
到“ /boot.config.txt”并重新启动。现在,您应该拥有一个设备文件“ / sys / class / i2c-dev / i2c-1 / device / 1-0050 / eeprom”(如果您的I2C总线号为1),可以像普通文件一样写入。
使用例如:
dtparam=i2c_arm=on
dtoverlay=at24c256
使用例如:
echo 'Hello World' | sudo tee /sys/class/i2c-dev/i2c-1/device/1-0050/eeprom
虽然不确定如何访问该设备的权限。将用户添加到i2c组无济于事...
答案 3 :(得分:0)
我的代码:
enter code here
__s32 write_eeprom(__s32 fd,__u32 offset,__u32 len,__u8 *buf)
{
__s32 ret;
struct i2c_rdwr_ioctl_data msg_set;
struct i2c_msg iomsgs;
__u32 sended, sending;
__u8 temp[ONE_PAGE + 1];
if((offset + len) > BYTES_MAX || len == 0)
{
printf("write too long than BYTES_MAX\n");
return -1;
}
sended = 0;
iomsgs.addr = DEVICE_ADDR;
iomsgs.flags = 0; //write
iomsgs.buf = temp;
msg_set.msgs = &iomsgs;
msg_set.nmsgs = 1;
while(len > sended)
{
if(len - sended > ONE_PAGE)
sending = ONE_PAGE;
else
sending = len - sended;
iomsgs.len = sending + 1;
temp[0] = offset + sended;
memcpy(&temp[1], buf + sended, sending);
//printf("sending:%d sended:%d len:%d offset:%d \n", sending, sended, len, offset);
ret = ioctl(fd, I2C_RDWR, (unsigned long)&msg_set);
if(ret < 0)
{
printf("Error dring I2C_RDWR ioctl with error code: %d\n", ret);
return ret;
}
sended += sending;
usleep(5000);
}
return sended;
}
答案 4 :(得分:0)
了解易于管理eeprom的小而简单的程序
/*
Simple program to write / read the eeprom AT24C32.
Developed and tested on the Raspberry pi3B jessie
To create the executable use the following command:
gcc -Wall -o thisprogram.exe thisprogram.c
*/
#include <stdio.h>
#include <sys/ioctl.h> // ioctl
#include <fcntl.h> // open
#include <unistd.h> // read/write usleep
#include <time.h>
#include <netinet/in.h> // htons
#include <linux/i2c-dev.h>
#pragma pack(1)
#define PAGESIZE 32
#define NPAGES 128
#define NBYTES (NPAGES*PAGESIZE)
#define ADDRESS 0x57 // AT24C32's address on I2C bus
typedef struct {
ushort AW;
char buf[PAGESIZE+2];
}WRITE;
static WRITE AT = {0};
int main() {
int fd;
char bufIN[180] = {0};
time_t clock=time(NULL);
snprintf(AT.buf, PAGESIZE+1, "%s: my first attempt to write", ctime(&clock)); // the buffer to write, cut to 32 bytes
if ((fd = open("/dev/i2c-1", O_RDWR)) < 0) { printf("Couldn't open device! %d\n", fd); return 1; }
if (ioctl(fd, I2C_SLAVE, ADDRESS) < 0) { printf("Couldn't find device on address!\n"); return 1; }
AT.AW = htons(32); // I will write to start from byte 0 of page 1 ( 32nd byte of eeprom )
if (write(fd, &AT, PAGESIZE+2) != (PAGESIZE+2)) { perror("Write error !"); return 1; }
while (1) { char ap[4]; if (read(fd,&ap,1) != 1) usleep(500); else break; } // wait on write's end
if (write(fd, &AT, 2) != 2) { perror("Error in sending the reading address"); return 1; }
if (read(fd,bufIN,PAGESIZE) != PAGESIZE) { perror("reading error\n"); return 1;}
printf ("\n%s\n", bufIN);
close(fd);
return 0;
}