teoria - Lectura/escritura del uso de I2C en Linux
uso de i2c arduino (4)
El NAK fue una gran pista: el pin WriteProtect se detuvo externamente, y tuvo que ser conducido a tierra, después de eso, una sola escritura de la dirección seguida de bytes de datos es exitosa (primer segmento de código).
Para leer, la dirección se puede escribir primero (usando escritura ()), y luego se pueden leer datos secuenciales a partir de esa dirección.
Estoy intentando leer / escribir en un FM24CL64-GTR FRAM
que está conectado a través de un bus I2C en la dirección 0b 1010 011
.
Cuando intento escribir 3 bytes (dirección de datos 2 bytes, + datos de un byte), [12406.360000] i2c-adapter i2c-0: sendbytes: NAK bailout.
un mensaje del núcleo ( [12406.360000] i2c-adapter i2c-0: sendbytes: NAK bailout.
), Así como los retornos de escritura ! = 3. Ver código a continuación:
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
int file;
char filename[20];
int addr = 0x53; // 0b1010011; /* The I2C address */
uint16_t dataAddr = 0x1234;
uint8_t val = 0x5c;
uint8_t buf[3];
sprintf(filename,"/dev/i2c-%d",0);
if ((file = open(filename,O_RDWR)) < 0)
exit(1);
if (ioctl(file,I2C_SLAVE,addr) < 0)
exit(2);
buf[0] = dataAddr >> 8;
buf[1] = dataAddr & 0xff;
buf[2] = val;
if (write(file, buf, 3) != 3)
exit(3);
...
Sin embargo, cuando escribo 2 bytes, escribo otro byte, no obtengo ningún error del kernel, pero cuando trato de leer desde el FRAM, siempre obtengo 0. Aquí está el código para leer desde el FRAM:
uint8_t val;
if ((file = open(filename,O_RDWR)) < 0)
exit(1);
if (ioctl(file,I2C_SLAVE,addr) < 0)
exit(2);
if (write(file, &dataAddr, 2) != 2) {
exit(3);
if (read(file, &val, 1) != 1) {
exit(3);
Ninguna de las funciones devuelve un valor de error, y también lo he intentado con:
#include <linux/i2c.h>
struct i2c_rdwr_ioctl_data work_queue;
struct i2c_msg msg[2];
uint8_t ret;
work_queue.nmsgs = 2;
work_queue.msgs = msg;
work_queue.msgs[0].addr = addr;
work_queue.msgs[0].len = 2;
work_queue.msgs[0].flags = 0;
work_queue.msgs[0].buf = &dataAddr;
work_queue.msgs[1].addr = addr;
work_queue.msgs[1].len = 1;
work_queue.msgs[1].flags = I2C_M_RD;
work_queue.msgs[1].buf = &ret;
if (ioctl(file,I2C_RDWR,&work_queue) < 0)
exit(3);
Lo cual también tiene éxito, pero siempre devuelve 0. ¿Esto indica un problema de hardware o estoy haciendo algo mal?
¿Hay controladores FRAM para FM24CL64-GTR sobre I2C en Linux, y cuál sería la API? Cualquier enlace sería útil.
No tengo experiencia con ese dispositivo en particular, pero en nuestra experiencia muchos dispositivos I2C tienen "caprichos" que requieren una solución alternativa, típicamente por encima del nivel del controlador.
Usamos linux (CELinux) y un controlador de dispositivo I2C con Linux también. Pero nuestro código de aplicación también tiene un módulo I2C no trivial que contiene toda la inteligencia de trabajo para manejar todos los diversos dispositivos con los que tenemos experiencia.
Además, cuando se trata de problemas de I2C, a menudo encuentro que necesito volver a familiarizarme con la especificación de origen:
http://www.nxp.com/acrobat_download/literature/9398/39340011.pdf
así como el uso de un osciloscopio decente.
Buena suerte,
El enlace de arriba está muerto, aquí hay otros enlaces:
http://www.nxp.com/documents/user_manual/UM10204.pdf y, por supuesto, wikipedia: http://en.wikipedia.org/wiki/I%C2%B2C
¡Tuviste algunos errores!
La dirección de ic
es Ax
en hexadecimal, x
puede ser cualquier cosa, pero los 4 bits superiores deben ser A=1010
!!!
Tenga en cuenta que el método que usa struct i2c_rdwr_ioctl_data
y struct i2c_msg
(es decir, la última parte de código que ha otorgado) es más eficiente que los demás, ya que con ese método ejecuta la característica de inicio repetido de I2c.
Esto significa que evita una transición STA-WRITE-STO -> STA-READ-<data>...-STO
, porque su comunicación se convertirá en STA-WRITE-RS-READ-<data>...STO
( RS
= STA-WRITE-RS-READ-<data>...STO
comienzo). Entonces, le ahorra un transitorio STO-STA
redundante.
No es que difiera mucho a tiempo, pero si no es necesario, ¿por qué perderlo?
Solo mis 2 ct.
Los mejores rgds,