Write Issue With eeprog in EEPROM

Hello
I’m trying to write some data in a eeprom using i2c-tools eeprog but it doesn’t work.

root@colibri-imx6:~# date | eeprog -f -16 -w 0 /dev/i2c-2 0x50
eeprog 0.7.5, a 24Cxx EEPROM reader/writer
Copyright (c) 2003 by Stefano Barbato - All rights reserved.
  Bus: /dev/i2c-2, Address: 0x50, Mode: 16bit
  Writing stdin starting at address 0x0
**..Error i2c_write_3b: Input/output error
Error at line 162: write error**

The EEPROM has 16 Byte addressing (24LC64)

my question is, if someone has this problem before or if there is idea?

You can check if the eeprom is getting detected using i2cdetect -y -r 2
If i2cdetect can see it at 0x50, make sure that WP pin has a proper polarity for writing and do a quick test

i2cset -y 0 0x50 0x00 0x00 0xAA
i2cset -y 0 0x50 0x00 0x00
i2cget -y 0 0x50

I have checked.
it works with i2cset but this tool doesn’t allow me to write data sequentially like eeprog

root@colibri-imx6:~# i2cset -y 2 0x50 0x00 0x00 0xAA i
root@colibri-imx6:~# i2cset -y 2 0x50 0x00 0x00
root@colibri-imx6:~# i2cget -y 2 0x50
0xaa

i can read data from eeprom using eeprog but write is the problem

root@colibri-imx6:~# eeprog -f -16 /dev/i2c-2 0x50 -x -r 0:64
eeprog 0.7.5, a 24Cxx EEPROM reader/writer
Copyright (c) 2003 by Stefano Barbato - All rights reserved.
  Bus: /dev/i2c-2, Address: 0x50, Mode: 16bit
  Reading 64 bytes from 0x0

 0000|  aa 54 54 54 00 00 00 00   00 00 00 00 00 00 00 00 
 0010|  54 00 00 00 00 00 00 00   00 00 00 00 00 00 00 00 
 0020|  ff ff ff ff ff ff ff ff   ff ff ff ff ff ff ff ff 
 0030|  ff ff ff ff ff ff ff ff   ff ff ff ff ff ff ff ff

Is the behavior different when you are using i2cset in word mode?

I guess this is really the low level I2C ioctl which fails, can you run with strace to get more details?

date | strace eeprog -f -16 -w 0 /dev/i2c-2 0x50

Also, do you have proper pull-ups on the I2C signals?

Hey

execve("/usr/sbin/eeprog", ["eeprog", "-f", "-16", "-w", "0", "/dev/i2c-2", "0x50"], [/* 16 vars */]) = 0
brk(NULL)                               = 0x1932000
uname({sysname="Linux", nodename="colibri-imx6", ...}) = 0
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x76f6f000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=35877, ...}) = 0
mmap2(NULL, 35877, PROT_READ, MAP_PRIVATE, 3, 0) = 0x76f66000
close(3)                                = 0
open("/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0Hh\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1246972, ...}) = 0
mmap2(NULL, 1316184, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x76dff000
mprotect(0x76f2b000, 65536, PROT_NONE)  = 0
mmap2(0x76f3b000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x12c000) = 0x76f3b000
mmap2(0x76f3e000, 9560, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x76f3e000
close(3)                                = 0
set_tls(0x76f701c0, 0x76f70898, 0x76f72050, 0x76f701c0, 0x1) = 0
mprotect(0x76f3b000, 8192, PROT_READ)   = 0
mprotect(0x76f71000, 4096, PROT_READ)   = 0
munmap(0x76f66000, 35877)               = 0
write(2, "eeprog 0.7.5, a 24Cxx EEPROM rea"..., 43eeprog 0.7.5, a 24Cxx EEPROM reader/writer
) = 43
write(2, "Copyright (c) 2003 by Stefano Ba"..., 61Copyright (c) 2003 by Stefano Barbato - All rights reserved.
) = 61
write(2, "  Bus: /dev/i2c-2, Address: 0x50"..., 46  Bus: /dev/i2c-2, Address: 0x50, Mode: 16bit
) = 46
open("/dev/i2c-2", O_RDWR)              = 3
ioctl(3, _IOC(0, 0x07, 0x05, 0x00), 0x7e923b5c) = 0
ioctl(3, _IOC(0, 0x07, 0x03, 0x00), 0x50) = 0
write(2, "  Writing stdin starting at addr"..., 40  Writing stdin starting at address 0x0
) = 40
fstat64(0, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
brk(NULL)                               = 0x1932000
brk(0x1954000)                          = 0x1954000
read(0, "Thu Mar 30 15:03:07 UTC 2017\n", 4096) = 29
write(2, ".", 1.)                        = 1
ioctl(3, _IOC(0, 0x07, 0x20, 0x00), 0x7e923b20) = 0
nanosleep({0, 10000}, NULL)             = 0
write(2, ".", 1.)                        = 1
ioctl(3, _IOC(0, 0x07, 0x20, 0x00), 0x7e923b20) = -1 EIO (Input/output error)
write(2, "Error i2c_write_3b: Input/output"..., 39Error i2c_write_3b: Input/output error
) = 39
nanosleep({0, 10000}, NULL)             = 0
write(2, "Error at line 162: write error\n", 31Error at line 162: write error
) = 31
_llseek(0, -27, 0x7e923ad8, SEEK_CUR)   = -1 ESPIPE (Illegal seek)
exit_group(1)                           = ?
+++ exited with 1 +++

yes i do have 3K9.
the tool writes only the first Byte

Your trace shows that a I2C_SMBUS ioctl is used (0x0720, SMBus transfer). I quickly looked through the code, the only function returning EIO is i2c_imx_acked in drivers/i2c/busses/i2c-imx.c. The driver has quite a bit of debug messages which might help to understand what goes wrong. So one method to further debug the issue would be to add a #define DEBUG at the very top of drivers/i2c/busses/i2c-imx.c (before any includes), recompile the kernel and observe the debug messages (you might need to use ignore_loglevel or otherwise lower the log level to see the debug messages).

Another idea might be to look at the actual signals to see whether an ack is missing or similar…

I could reproduce the issue you are seeing on a Ixora V1.0 which has a ON Semiconductor CAT24C02WI-GT3 populated. It is only byte addressable, but error seems to be the same:

# date | eeprog -f -8 /dev/i2c-1 0x50 -w 0
eeprog 0.7.5, a 24Cxx EEPROM reader/writer
Copyright (c) 2003 by Stefano Barbato - All rights reserved.
  Bus: /dev/i2c-1, Address: 0x50, Mode: 8bit
  Writing stdin starting at address 0x0
..Error i2c_write_2b: Input/output error
Error at line 162: write error

Debugging into the issue shows that there is no Ack (dmesg with debugging enabled in the i2c-imx driver):

[   27.334920] i2c i2c-1: <i2c_imx_xfer>
[   27.334941] i2c i2c-1: <i2c_imx_start>
[   27.335024] i2c i2c-1: <i2c_imx_bus_busy>
[   27.335048] i2c i2c-1: <i2c_imx_xfer> transfer message: 0
[   27.335070] i2c i2c-1: <i2c_imx_write> write slave address: addr=0xa0
[   27.335248] i2c i2c-1: <i2c_imx_trx_complete> TRX complete
[   27.335281] i2c i2c-1: <i2c_imx_acked> ACK received
[   27.335302] i2c i2c-1: <i2c_imx_write> write data
[   27.335323] i2c i2c-1: <i2c_imx_write> write byte: B0=0x0
[   27.335483] i2c i2c-1: <i2c_imx_trx_complete> TRX complete
[   27.335512] i2c i2c-1: <i2c_imx_acked> ACK received
[   27.335533] i2c i2c-1: <i2c_imx_write> write byte: B1=0x54
[   27.335690] i2c i2c-1: <i2c_imx_trx_complete> TRX complete
[   27.335716] i2c i2c-1: <i2c_imx_acked> ACK received
[   27.335738] i2c i2c-1: <i2c_imx_stop>
[   27.335756] i2c i2c-1: <i2c_imx_bus_busy>
[   27.335783] i2c i2c-1: <i2c_imx_xfer> exit with: success msg: 1
[   27.336071] i2c i2c-1: <i2c_imx_xfer>
[   27.336091] i2c i2c-1: <i2c_imx_start>
[   27.336167] i2c i2c-1: <i2c_imx_bus_busy>
[   27.336189] i2c i2c-1: <i2c_imx_xfer> transfer message: 0
[   27.336210] i2c i2c-1: <i2c_imx_write> write slave address: addr=0xa0
[   27.336377] i2c i2c-1: <i2c_imx_trx_complete> TRX complete
[   27.336406] i2c i2c-1: <i2c_imx_acked> No ACK
[   27.336424] i2c i2c-1: <i2c_imx_stop>
[   27.336442] i2c i2c-1: <i2c_imx_bus_busy>
[   27.336469] i2c i2c-1: <i2c_imx_xfer> exit with: error: -5

As you observed, the first byte succeeded. So it really seems that the device is not ready to flash a second byte. The ON Semiconductor CAT24C02 data sheet, the device I could reproduce the issue with, clearly states: “While this internal cycle is in progress (tWR), the SDA output will be tri−stated and the CAT24Cxx will not respond to any request from the Master device (Figure 7).”

The Write Cycle Time (tWR) is specified as 5ms, the time-stamps in the log above shows that the application clearly does not adhere to that.

Looking into eeprog’s source code shows that the code only delays execution for 10us! Clearly too short. Attached is a patch which increases the delay to 5000us, which seems to work well here. You can use a bbappend for the i2c-tools package to append the patch and build i2c-tools with the enhanced delay.

0001-Increase-sleep-between-byte-writes.patch

Btw, there is also a kernel driver for EEPROM, see Documentation/devicetree/bindings/eeprom.txt. The driver also properly adheres to the specs and delays writes for up to 25ms, see drivers/misc/eeprom/at24.c.