Чтение/запись с использованием I2C в Linux
Я пытаюсь читать/записывать на чип FM24CL64-GTR FRAM
, подключенный по шине I2C по адресу 0b 1010 011
.
Когда я пытаюсь написать 3 байта (адрес данных 2 байта, + данные один байт), я получаю сообщение ядра ([12406.360000] i2c-adapter i2c-0: sendbytes: NAK bailout.
), а также записи возвращается!= 3. См. код ниже:
#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);
...
Однако, когда я пишу 2 байта, а затем пишу еще один байт, я не получаю ошибки ядра, но при попытке прочитать из FRAM я всегда возвращаюсь 0. Вот код для чтения из 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);
Ни одна из функций не возвращает значение ошибки, и я также пробовал ее с помощью:
#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);
Что также удается, но всегда возвращает 0. Это указывает на аппаратную проблему, или я делаю что-то неправильно?
Существуют ли какие-либо FRAM-драйверы для FM24CL64-GTR по сравнению с I2C на Linux, и каков будет API? Любая ссылка будет полезна.
Ответы
Ответ 1
NAK был большим намеком: вывод WriteProtect был выведен извне и должен был быть приведен в действие, после чего одна запись адреса, за которой следуют байты данных, успешна (первый сегмент кода).
Для чтения адрес может быть выписан первым (с использованием write()), и после этого можно прочитать последовательные данные, начиная с этого адреса.
Ответ 2
У меня нет опыта с этим конкретным устройством, но, по нашему опыту, многие устройства I2C имеют "причуды", которые требуют обхода, обычно выше уровня драйвера.
Мы используем Linux (CELinux) и драйвер устройства I2C с Linux. Но наш код приложения также имеет нетривиальный модуль I2C, который содержит весь интеллект для работы со всеми различными устройствами, с которыми у нас есть опыт.
Кроме того, когда я сталкиваюсь с проблемами I2C, я часто обнаруживаю, что мне нужно снова ознакомиться со спецификацией источника:
http://www.nxp.com/acrobat_download/literature/9398/39340011.pdf
а также использование приличного осциллографа.
Удачи,
Выше ссылки мертвы, вот несколько других ссылок:
http://www.nxp.com/documents/user_manual/UM10204.pdf
и, конечно же, википедия:
http://en.wikipedia.org/wiki/I%C2%B2C
Ответ 3
Обратите внимание, что метод, использующий struct i2c_rdwr_ioctl_data
и struct i2c_msg
(то есть последнюю часть кода, которую вы указали) более эффективен, чем другие, поскольку с помощью этого метода вы выполняете функцию повторного запуска I2c,
Это означает, что вы избегаете перехода STA-WRITE-STO -> STA-READ-<data>...-STO
, потому что ваше сообщение станет STA-WRITE-RS-READ-<data>...STO
(RS
= повторный старт). Таким образом, сохраняется резервный переходный период STO-STA
.
Не то, чтобы он сильно отличался во времени, но если он не нужен, зачем проигрывать на нем...
Просто мой 2 ct.
Лучшие rgds,
Ответ 4
У вас были некоторые ошибки!
Адрес ic
равен Ax
в шестнадцатеричном формате, x
может быть любым, кроме 4 верхних бит должен быть A=1010
!!!