I am attempting to read gyroscopic data using a raspberry pi and am having a lot of problems. I think I understand a lot of the code and it is written properly.
The problem comes in when printing it onto raspberry screen, all I get is constant numbers that don't change at all.
Everything is based off of http://ozzmaker.com/berryimu/ I know the code is provided but I wanted to learn and possibly optimize it for my purposes. I am using https://www.adafruit.com/datasheets/L3GD20H.pdf gyroscope.
The program to read values is:
#include </home/pi/gyroSetup.c>
#include <stdio.h>
int main() {
setup();
int i;
int G[3];
for(i = 0;i<=1000;i++){
readGyro(G);
printf("%d ", G[0]);
printf("%d ", G[1]);
printf("%d\n", G[2]);
}
}
The gyroSetup.c is here:
#include <stdio.h>
#include <stdint.h>
#include "fcntl.h"
#include "linux/i2c-dev.h"
#define Gyr_adress 0x6b
#define Gyr_ctrl1 0b1110100
#define Gyr_ctrl4 0b00000000
#define Gyr_odr 0b00000000
int file;
void readBlock(uint8_t command, uint8_t size, uint8_t *data) {
int result = i2c_smbus_read_i2c_block_data(file, command, size, data);
if(result != size) {
printf("Failed to read block from i2c!");
{
}
void readGyro(int *T) {
uint8_t block[6];
if(ioctl(file,I2C_SLAVE, Gyr_adress) < 0) {
printf("failed to select device!");
}
readBlock(0x80 | 0x28, sizeof(block), block);
*T = (int16_t)(block[0] | block[1] << 8);
*(T+1) = (int16_t)(block[2] | block[3] << 8);
*(T+2) = (int16_t)(block[4] | block[4] << 8);
}
void writeGyro(uint8_t location, uint8_t value, int file) {
if(ioctl(file, I2C_SLAVE, Gyr_adress) < 0) {
printf("Failed to select i2c device");
}
int result = i2c_smbus_write_byte_data(file, location, value);
if(result == -1) {
printf("Failed to write byte!");
}
}
void setup(){
__u16 block[I2C_SMBUS_BLOCK_MAX];
file = open("/dev/i2c-1", O_RDWR);
if( file < 0) {
printf("Unable to open i2c bus!");
}
writeGyro(0x20, Gyr_ctrl1, file);
writeGyro(0x23, Gyr_ctrl4, file);
writeGyro(0x39, Gyr_odr, file);
}
I have no idea why when reading the values don't change so please help. When compiling there are no errors.
Related
#include <unistd.h> //Needed for I2C port
#include <fcntl.h> //Needed for I2C port
#include <sys/ioctl.h> //Needed for I2C port
#include <linux/i2c-dev.h> //Needed for I2C port
#include <stdio.h>
#include <time.h>
int file_i2c;
int length;
unsigned char buffer[60] = {0};
unsigned char cmdbuffer[60] = {0};
//PRINTS (SENSOR STATUS) IN BINARY
void printBin(unsigned char value)
{
for (int i = sizeof(char) * 7; i >= 0; i--) {
printf("%d", (value & (1 << i )) >> i);
}
putc('\n', stdout);
}
//CREATES DELAY IN MS
void delay(int milli)
{
long pause;
clock_t now,then;
pause = milli * (CLOCKS_PER_SEC / 1000);
now = then = clock();
while ((now-then) < pause) {
now = clock();
}
}
//TIMESTAMPS OUTPUT
void timestamp()
{
time_t ltime;
ltime=time(NULL);
printf("%s", asctime(localtime(<ime)));
}
//PORT SELECT FOR TCA9548A Addresses range from 0x70-0x77
void portSelect(int port, int addressTCA)
{
if (port > 7 || port < 0)
return;
if (ioctl(file_i2c, I2C_SLAVE, addressTCA) < 0) {
printf("Failed to acquire bus access and/or talk to slave.\n");
return;
}
cmdbuffer[0] = 1 << port;
length = 1;
write(file_i2c, cmdbuffer, length);
}
int main()
{
//----- OPEN THE I2C BUS -----
char *filename = (char*)"/dev/i2c-1";
if ((file_i2c = open(filename, O_RDWR)) < 0) {
//ERROR HANDLING: you can check errno to see what went wrong
printf("Failed to open the i2c bus");
return 0;
}
portSelect(1, 0x70);
//CONFIGURE SLAVE AND ATTEMPT CONNECTION
if (ioctl(file_i2c, I2C_SLAVE, 0x28) < 0) {
printf("Failed to acquire bus access and/or talk to slave.\n");
return 0;
}
flag:
cmdbuffer[0] = 0xAA;
cmdbuffer[1] = 0x00;
cmdbuffer[2] = 0x00;
length = 3;
if (write(file_i2c, cmdbuffer, length) != length)
//write() returns the number of bytes actually written, if it doesn't match then an error occurred (e.g. no response from the device)
{
printf("Failed to write to the i2c bus.\n"); //FAILS HERE
return 0;
}
length = 7; //<<< Number of bytes to read
if (read(file_i2c, buffer, length) != length)
//read() returns the number of bytes actually read, if it doesn't match then an error occurred (e.g. no response from the device)
{
printf("Failed to read from the i2c bus.\n");
} else {
//timestamp();
printf("Status:\n");
printBin(buffer[0]);
int pressure = (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
int temperature = (buffer[4] << 16) + (buffer[5] << 8) + buffer[6];
printf("Pressure : %d\n", pressure);
printf("Temperature : %d\n\n", temperature);
}
delay(5);
goto flag;
return 0;
}
Current code shown above. I am trying to read from 8 different Honeywell pressure sensors but for the moment I am just trying to get one working. I am able to read/write just fine without the multiplexer. Documentation is unhelpful as it only references Python or Arduino. I have scanned with console and confirmed the addresses of the sensors and mux.
I need to read an eeprom in an embedded device.
So far this "almost" worked:
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#define READ_SIZE (256)
#define NB_PAGES (128)
void dump_to_file(const char *output_file_path,
const uint8_t *buffer, const int buffer_length)
{
int output_file = open(output_file_path, O_RDWR|O_APPEND|O_CREAT);
if (output_file < 0) {
printf("Failed opening output file %s\n", output_file_path);
return;
}
write(output_file, buffer, buffer_length);
}
int main(int argc, char *argv[])
{
/* got these values from i2cdetect */
const char *i2c_device = "/dev/i2c-4";
const int device_address = 0x50;
/* open the i2c device file */
int file = open(i2c_device, O_RDWR);
if (file < 0) {
printf("Failed opening %s\n", i2c_device);
return 1;
}
if (ioctl(file, I2C_SLAVE, device_address) < 0) {
printf("Failed addressing device at %02X\n", device_address);
close(file);
return 1;
}
int i = 0;
for (i = 0; i < NB_PAGES; i++) {
char buf[READ_SIZE] = {0};
if (read(file, buf, READ_SIZE) != READ_SIZE) {
printf("Failed reading\n");
close(file);
return 1;
}
dump_to_file(argv[1], buf, READ_SIZE);
}
close(file);
return 0;
}
By "almost" I mean that it dumps the full eeprom but the START depends on the last block read..
It's not always the same.
If I read 10 blocks. then run the program again I read the next ones and not the first 10.
How to set the starting address?
Update:
if I do:
i2cset -y 4 0x50 0x00 0x00
and the run the above code, it works.
so how can I put the equivalent of the i2cset command in the code?
Done!
It wasn't easy because I could not find documentations anywhere.. but I thought that since the eeprom is 32K, maybe it was "like" a 24c256. But even in that case I found nothing in userspace until I decided to go by instinct.
I studied i2cset source, understood what it did and put it in the code.
Here is the result, which dumps a full i2c 32k eprom from userspace.
Note a full backup and restore utility can be found here:
https://gist.github.com/Zibri/cf8ac0b311301aeeaa8910c7da824bff
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#define READ_SIZE (256)
#define NB_PAGES (128)
void dump_to_file(const char *output_file_path,
const uint8_t *buffer, const int buffer_length)
{
int output_file = open(output_file_path, O_RDWR|O_APPEND|O_CREAT);
if (output_file < 0) {
printf("Failed opening output file %s\n", output_file_path);
return;
}
write(output_file, buffer, buffer_length);
}
int main(int argc, char *argv[])
{
const char *i2c_device = "/dev/i2c-4";
const int device_address = 0x50;
int file = open(i2c_device, O_RDWR);
if (file < 0) {
printf("Failed opening %s\n", i2c_device);
return 1;
}
if (ioctl(file, I2C_SLAVE, device_address) < 0) {
printf("Failed addressing device at %02X\n", device_address);
close(file);
return 1;
}
int i = 0;
write(file,'\x00\x00',2); // ADDRESS
for (i = 0; i < NB_PAGES; i++) {
char buf[READ_SIZE] = {0};
if (read(file, buf, READ_SIZE) != READ_SIZE) {
printf("Failed reading\n");
close(file);
return 1;
}
dump_to_file(argv[1], buf, READ_SIZE);
}
close(file);
return 0;
}
I am unable to interface mcp 3008 with beaglebone green.trying to set communication in mode 0(CPOL =0 CPHA=0),the built in frequency in dts is set to 1Mhz.
things I have tried
1.enable device tree BB-SPI0-MCP3008-00A0.dts
on execution of
ls -al /dev/spidev1.*
I got
crw-rw---- 1 root spi 153, 0 Oct 7 16:40 /dev/spidev1.1
2.on execution of
cat /sys/kernel/debug/pinctrl/44e10800.pinmux/pingroups
group: pinmux_bb_spi0_pins pin 84 (PIN84) pin 85 (PIN85) pin 86 (PIN86) pin 87 (PIN87)
My reference code is as follow
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#define ARRAY_SIZE(array) sizeof(array) / sizeof(array[0])
static const char *DEVICE = "/dev/spidev1.1";
static uint8_t MODE = SPI_MODE_0;
static uint8_t BITS = 8;
static uint32_t CLOCK = 1000000;
static uint16_t DELAY = 5;
/* * Ensure all settings are correct for the ADC */
static int prepare(int fd)
{
if (ioctl(fd, SPI_IOC_WR_MODE, &MODE) == -1)
{
perror("Can't set MODE"); return -1;
}
if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &BITS) == -1)
{
perror("Can't set number of BITS");
return -1;
}
if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &CLOCK) == -1)
{
perror("Can't set write CLOCK");
return -1;
}
if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &CLOCK) == -1)
{
perror("Can't set read CLOCK"); return -1;
}
return 0;
}
/* * (SGL/DIF = 0, D2=D1=D0=0) */
uint8_t control_bits_differential(uint8_t channel)
{
return (channel & 7) << 4;
}
/* * (SGL/DIF = 1, D2=D1=D0=0) */
uint8_t control_bits(uint8_t channel)
{
return 0x8 | control_bits_differential(channel);
}
/* * Given a prep'd descriptor, and an ADC channel, fetch the * raw ADC
value for the given channel. */
int readadc(int fd, uint8_t channel)
{
uint8_t tx[] = {1, control_bits(channel), 0
};
uint8_t rx[3]={0,0,0};
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = DELAY,
.speed_hz = CLOCK,
.bits_per_word = BITS, };
if (ioctl(fd, SPI_IOC_MESSAGE(1), &tr) == 1)
{
perror("IO Error");
abort();
}
return ((rx[1] << 8) & 0x300) | (rx[2] & 0xFF);
}
int main(int argc, char **argv)
{
int fd = open(DEVICE, O_RDWR);
if (fd <= 0)
{
printf("Device %s not found\n", DEVICE);
return -1;
}
if (prepare(fd) == -1)
{ return -1; }
uint8_t i,radc=0;
for(i = 0;i < 8;i++)
{ printf("Channel %d: %d\n", i + 1, readadc(fd, i)); }
close(fd);
return 0;
}
after executing this code I am getting 1023 count for any applied voltage,where I am expecting count 0 for 0 input voltage and so on .
Can anybody please help me? can you tell me where I am doing wrong?what are the other things I have to consider while using SPI on beaglebone?any kind of help will be greatly appreciated!
solved it as suggested from other forum it was hardware related thing.I have to put 0.1uf capacitor between vcc and gnd,where analog ground and digital ground were common.
Hey I am trying to write a user space application to move some data to an I2C for an embedded system running PetaLinux, an operating system for embedded Linux, although I do not think that is what is affecting the issue. I am getting a Connection timeout and a segmentation fault.
The function has macros that direct it to write to the first I2C bus. I specify the data that I want to write in main and pass it to i2c_write, which then passes it to i2c_ioctl_write.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.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
#define REG_ADDR 0x00
int i2c_ioctl_write (int fd, uint8_t dev, uint8_t regaddr, uint16_t *data)
{
printf("i2c_ioctl_write\n");
int i, j = 0;
int ret;
uint8_t *buf;
buf = malloc(1 + 2 * (sizeof(data) / sizeof(data[0])));
if (buf == NULL) {
return -ENOMEM;
}
printf("\tBuffer Allocation Successful...\n");
buf[j ++] = regaddr;
for (i = 0; i < (sizeof(data) / sizeof(data[0])); i ++) {
buf[j ++] = (data[i] & 0xff00) >> 8;
buf[j ++] = data[i] & 0xff;
}
printf("\tBuffer Setup Successful...\n");
struct i2c_msg messages[] = {
{
.addr = dev,
.buf = buf,
.len = sizeof(buf) / sizeof(buf[0]),
},
};
printf("\tSetup I2C Messages...\n");
struct i2c_rdwr_ioctl_data payload = {
.msgs = messages,
.nmsgs = sizeof(messages) / sizeof(messages[0]),
};
printf("\tSetup I2C IOCTL Payload...\n");
ret = ioctl(fd, I2C_RDWR, &payload);
printf("\tWrote with IOCTL...\n");
if (ret < 0) {
ret = -errno;
}
free (buf);
return ret;
}
int i2c_ioctl_smbus_write (int fd, uint8_t dev, uint8_t regaddr, uint16_t *data)
{
printf("i2c_ioctl_smbus_write\n");
int i, j = 0;
int ret;
uint8_t *buf;
buf = malloc(2 * (sizeof(data) / sizeof(data[0])));
if (buf == NULL) {
return -ENOMEM;
}
for (i = 0; i < (sizeof(data) / sizeof(data[0])); i ++) {
buf[j ++] = (data[i] & 0xff00) >> 8;
buf[j ++] = data[i] & 0xff;
}
struct i2c_smbus_ioctl_data payload = {
.read_write = I2C_SMBUS_WRITE,
.size = I2C_SMBUS_WORD_DATA,
.command = regaddr,
.data = (void *) buf,
};
ret = ioctl (fd, I2C_SLAVE_FORCE, dev);
if (ret < 0)
{
ret = -errno;
goto exit;
}
ret = ioctl (fd, I2C_SMBUS, &payload);
if (ret < 0)
{
ret = -errno;
goto exit;
}
exit:
free(buf);
return ret;
}
int i2c_write (int fd, uint8_t dev, uint8_t regaddr, uint16_t *data)
{
printf("i2x_write\n");
uint64_t funcs;
if (ioctl(fd, I2C_FUNCS, &funcs) < 0) {
return -errno;
}
if (funcs & I2C_FUNC_I2C) {
return i2c_ioctl_write (fd, dev, regaddr, data);
} else if (funcs & I2C_FUNC_SMBUS_WORD_DATA) {
return i2c_ioctl_smbus_write (fd, dev, regaddr, data);
} else {
return -ENOSYS;
}
}
int main (int argc, char *argv[])
{
printf("main\n");
uint8_t regaddr;
int fd;
int ret = 0;
uint16_t data[] = {1, 2, 4};
fd = open(I2C_ADAPTER, O_RDWR | O_NONBLOCK);
ret = i2c_write(fd, I2C_DEVICE, REG_ADDR, data);
close(fd);
if (ret) {
fprintf (stderr, "%s.\n", strerror(-ret));
}
free(data);
return ret;
}
When I run the program on QEMU I get the following output:
main
i2x_write
i2c_ioctl_write
Buffer Allocation Successful...
Buffer Setup Successful...
Setup I2C Messages
Setup I2C IOCTL Payload
cdns-i2c e0004000.i2c: timeout waiting on completion
Wrote with IOCTL
Connection timed out.
Segmentation fault
I assume it is failing on the line
ret = ioctl(fd, I2C_RDWR, &payload);
but I am not sure why. Was the payload constructed improperly?
Update: Here is the current code:
#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 fd;
int ret = 0;
fd = open(I2C_ADAPTER, O_RDWR | O_NONBLOCK);
uint64_t funcs;
int addr = 0X00;
if (ioctl(fd, I2C_SLAVE, addr) < 0) {
/* ERROR HANDLING; you can check errno to see what went wrong */
printf("Cannot setup as slave");
exit(1);
}
if (ioctl(fd, I2C_FUNCS, &funcs) < 0) {
printf("ioctl failed");
return -errno;
}
printf("funcs & I2C_FUNC_I2C: %llu\n", funcs & I2C_FUNC_I2C);
printf("funcs & I2C_FUNC_SMBUS_WORD_DATA: %llu\n", funcs & I2C_FUNC_SMBUS_WORD_DATA);
__u8 reg = 0x10;
__s32 res;
if (funcs & I2C_FUNC_I2C) {
char buf[10];
printf("Attempting to write to I2C bus via I2C protocol...\n");
buf[0] = reg;
buf[1] = 0x43;
buf[2] = 0x65;
int bytes_written = write(fd, buf, 3);
if(bytes_written != 3) {
printf("Wrote %d bytes", bytes_written);
printf("\tFailed to write to I2C Bus\n");
close(fd);
return -1;
}
else {
printf("\tSuccesful write to I2C Bus\n");
}
char buf2[10];
printf("Attempting to read from I2C bus via I2C protocol...\n");
if(read(fd, buf2, 1) != 1) {
printf("\tFailed to do I2C read from Bus\n");
close(fd);
return -1;
}
else {
printf("\tRead successful. Comparing read results from original write buffer...");
printf("\t\tWritten value: %c", buf[0]);
printf("\t\tRead value: %c", buf2[0]);
}
return 0;
} else if (funcs & I2C_FUNC_SMBUS_WORD_DATA) {
printf("Attempting to write to I2C bus via SMBus protocol...\n");
//res = i2c_smbus_write_word_data(fd, REG_ADDR, 0x6543);
res = 1;
if(res < 0) {
printf("\tFailed to write to I2C Bus\n");
close(fd);
return -1;
}
else {
printf("\tSuccesful write to I2C Bus\n");
}
//res = i2c_smbus_read_word_data(fd, REG_ADDR);
if(res < 0) {
printf("\tFailed to read from I2C Bus\n");
close(fd);
return -1;
}
else {
printf("\tRead successful. Comparing read results from original write buffer...");
printf("\t\tWritten value: %c", 0x6543);
printf("\t\tRead value: %c", res);
}
} else {
printf("Cannot write to I2C");
return -ENOSYS;
}
close(fd);
if (ret) {
fprintf (stderr, "%s.\n", strerror(-ret));
}
return ret;
}
I was able to get rid of the seg fault by removing free(), so thanks there. I have pinpointed the exact issue of the timeout which occurs in the Cadence I2C Driver here:
https://github.com/Xilinx/linux-xlnx/blob/3f3c7b60919d56119a68813998d3005bca501a40/drivers/i2c/busses/i2c-cadence.c#L825
which is still occurring.
As mentioned, there is probably some issue with the way I am writing to slave causing the slave to not send ACK, resulting in a timeout. I am not sure which registers I will need to write what to. I have a feeling the I2C_DEVICE macro and addr and reg variables will need to be changed.
cdns-i2c e0004000.i2c: timeout waiting on completion
It seems that i2c driver (cdns-i2s) doesnt recieves the acknowledgment from the slave. It may occur as you are using I2C-slave address as 0x00 which is a general call address. While using general call address the second byte that is sent has a special purpose which is mentioned in the i2c-specification (section 3.1.13).
If you use general call address you need to follow the specification or else Try using the exact i2c slave address instead of general call address(0x00).
I trying to read and write an Atmel 24C256 EEPROM with a Raspberry Pi B+ over I2C, but I'm having trouble getting it all to work right.
Here is the code I have so far:
#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;
}
Writing to the device like in the line write_to_device(0x01, 0x00, buffer, PAGE_SIZE); doesn't generate any errors but when I try to read from the device, I have to write a "dummy" byte according to the spec sheet and then try to read from the device but for some reason writing the dummy byte results in an error "Input/output error". I can't figure out how this works. I am using two resources to guide me, the Linux I2C-Dev documentation and an example from a similar EEPROM device. I'm sort of stuck here and don't know what to try. Any suggestions or pointers are greatly appreciated!
Alternatively, you could access it via the kernel at24.c driver, if you're able to compile and install a different kernel device tree for your Raspberry Pi.
The kernel device tree needs to specify the EEPROM's type and address, and which I²C bus it's connected to. I'm not sure about Raspberry Pi, but for the BeagleBone Black EEPROM it goes like this:
&i2c0 {
eeprom: eeprom#50 {
compatible = "at,24c32";
reg = <0x50>;
};
};
For your device you'd specify compatible = "at,24c256";
Ensure the kernel config specifies CONFIG_EEPROM_AT24=y (or =m).
Then you should be able to access the EEPROM memory from userspace at something like /sys/bus/i2c/devices/0-0050/eeprom or /sys/bus/i2c/drivers/at24/0-0050/eeprom.
maybe this here might help. http://www.richud.com/wiki/Rasberry_Pi_I2C_EEPROM_Program since it handles apparently the device you are trying to program and also explains some caveats of addressing 24c256
Craig McQueen's answer got me on the right track, but it is not easy to figure the whole thing out on your own.
Here is a AT24C256 device tree overlay that works for me on the Raspberry Pi:
/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>;
};
};
};
};
Save it to "at24c256.dts", compile (might need to install the device tree compiler) it using:
dtc -O dtb -o at24c256.dtbo -b 0 -# at24c256.dts
and save it in "/boot/overlays". Then activate the overlay by adding:
dtparam=i2c_arm=on
dtoverlay=at24c256
to "/boot/config.txt" and reboot. You should now have a device file "/sys/class/i2c-dev/i2c-1/device/1-0050/eeprom" (if your I2C bus number is 1) which you can write to like a normal file.
Write to it using e.g.:
echo 'Hello World' | sudo tee /sys/class/i2c-dev/i2c-1/device/1-0050/eeprom
Read from it using e.g.:
sudo more /sys/class/i2c-dev/i2c-1/device/1-0050/eeprom
Not sure how you can get around the su-rights for accessing the device though. Adding the user to the i2c-group does not help...
Small and simple program to understand the easy management of an 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;
}
My code:
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;
}