Я недавно написал библиотеку , аналогичную той, которую вы описываете для акселерометра MMA8451 i2c.
По сути, контроллеры i2c в Linux получают назначенный узел устройства (например, /dev/i2c-1
).Вы откроете этот узел устройства как файл , подобный этому :
int file = open(path, O_RDWR); //path = /dev/i2c-1
Получив дескриптор файла, вы сможете читать и записывать регистры i2c, используя ioctl's .Модуль ядра i2c поддерживает ioctl I2C_RDWR, который позволяет вам взаимодействовать с регистрами i2c.
Чтобы прочитать регистр, вы делаете что-то вроде этого :
int mma8451_get_i2c_register(int file, unsigned char addr, unsigned char reg, unsigned char *val) {
unsigned char inbuf, outbuf;
struct i2c_rdwr_ioctl_data packets;
struct i2c_msg messages[2];
outbuf = reg;
messages[0].addr = addr;
messages[0].flags = 0;
messages[0].len = sizeof(outbuf);
messages[0].buf = &outbuf;
messages[1].addr = addr;
messages[1].flags = I2C_M_RD;
messages[1].len = sizeof(inbuf);
messages[1].buf = &inbuf;
packets.msgs = messages;
packets.nmsgs = 2;
if(ioctl(file, I2C_RDWR, &packets) < 0) {
return 0;
}
*val = inbuf;
return 1;
}
Чтобы написать регистр, вы делаете что-то вроде этого :
int mma8451_set_i2c_register(int file, unsigned char addr, unsigned char reg, unsigned char value) {
unsigned char outbuf[2];
struct i2c_rdwr_ioctl_data packets;
struct i2c_msg messages[1];
messages[0].addr = addr;
messages[0].flags = 0;
messages[0].len = sizeof(outbuf);
messages[0].buf = outbuf;
outbuf[0] = reg;
outbuf[1] = value;
packets.msgs = messages;
packets.nmsgs = 1;
if(ioctl(file, I2C_RDWR, &packets) < 0) {
return 0;
}
return 1;
}
Редактировать: I2C_RDWR
ioctl принимает структуру i2c_rdwr_ioctl_data
в качестве аргумента.Это , описанное так :
Другая распространенная структура данных: struct i2c_rdwr_ioctl_data
Эта структура используется в вызове ioctl I2C_RDWR
* 1036.*
struct i2c_rdwr_ioctl_data {
struct i2c_msg __user *msgs; /* pointers to i2c_msgs */
__u32 nmsgs; /* number of i2c_msgs */
};
(определено в linux / i2c-dev.h) Эта структура указывает на массив i2c_msg для обработки и определяет число i2c_msg в массиве.
Использование: Еслипрограмма должна записать один байт (пример - индексный байт), после чего следует чтение одного байта, потребуются две структуры данных struct i2c_msg.Один для записи, а другой для чтения.Эти две структуры данных должны быть объявлены как массив из двух структур данных i2c_msg.Они будут обработаны в порядке их появления в массиве.
Структура i2c_rdwr_ioctl_data
содержит указатель на массив структур i2c_msg
.Эти структуры содержат фактические сообщения, которые вы хотите отправить или получить.Например, для моего акселерометра, чтобы прочитать регистр, мне сначала нужно было записать регистр, который я хотел прочитать на устройство, а затем я мог прочитать его (следовательно, почему в моей функции чтения есть два i2c_msg
).Если бы я просто писал регистр, мне нужен был только один.
Вы захотите обратиться к листу данных для вашего BNO055 , чтобы выяснить, какие именно регистры делают.
Что касается вашего примера, похоже, он исходит из bno055_support.c .Похоже, это просто набор заглушек, которые вы должны реализовать.Похоже, это в основном издевательство над реальным интерфейсом.Поэтому важен интерфейс, а не сам код (поэтому не беспокойтесь о cnt
).Важные биты здесь:
s8 I2C_routine(void)
{
bno055.bus_write = BNO055_I2C_bus_write;
bno055.bus_read = BNO055_I2C_bus_read;
bno055.delay_msec = BNO055_delay_msek;
bno055.dev_addr = BNO055_I2C_ADDR1;
return BNO055_INIT_VALUE;
}
Это устанавливает указатели функций в структуре вашего устройства на функции записи, которые вы собираетесь определить, и задает адрес вашего устройства и задержку.Оттуда вам нужно реализовать функции, которые соответствуют этому интерфейсу:
#define BNO055_BUS_WRITE_FUNC(dev_addr, reg_addr, reg_data, wr_len)\
bus_write(dev_addr, reg_addr, reg_data, wr_len)
#define BNO055_BUS_READ_FUNC(dev_addr, reg_addr, reg_data, r_len)\
bus_read(dev_addr, reg_addr, reg_data, r_len)
Функции, которые я дал вам выше, должны быть довольно близкими.Удачи!