Чтение/запись с использованием 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? Любая ссылка будет полезна.


person TheSeeker    schedule 02.02.2009    source источник
comment
Вы должны использовать exit() (без начального подчеркивания), а не _exit(). _exit() не закрывает libc должным образом.   -  person Adam Rosenfield    schedule 03.02.2009
comment
Спасибо, это всего лишь тестовый код аппаратного обеспечения, но все равно спасибо за ваш отзыв.   -  person TheSeeker    schedule 03.02.2009


Ответы (4)


У меня нет опыта работы с этим конкретным устройством, но по нашему опыту многие устройства 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

person Matthew Eshleman    schedule 02.02.2009
comment
Я начну с осциллографа сегодня утром и опубликую свои выводы после того, как заставлю его работать, если только у кого-то нет драйвера FRAM I2C для Linux, но я не смог его найти. - person TheSeeker; 03.02.2009

NAK был большой подсказкой: контакт WriteProtect был поднят извне, и его нужно было заземлить, после чего успешна единственная запись адреса, за которой следуют байты данных (первый сегмент кода).

Для чтения адрес может быть сначала записан (используя write()), а затем последовательные данные могут быть прочитаны, начиная с этого адреса.

person TheSeeker    schedule 04.02.2009
comment
Что делать, если i2c i2c-1: sendbytes: спасение NAK появляется в журналах Linux? - person SimpleSpawn; 17.04.2018

Обратите внимание, что метод, использующий 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 кар.

С наилучшими пожеланиями,

person GeertVc    schedule 30.12.2013

У тебя были ошибки!

Адрес ic равен Ax в шестнадцатеричном формате, x может быть любым, но 4 старших бита должны быть A=1010 !!!

person ebi    schedule 17.01.2016