Настройка чтения и записи I2C на языке c - PullRequest
0 голосов
/ 24 октября 2018

Сначала я новичок в этом, но учусь и очень хочу, чтобы это сработало.Я купил raspberrypi и акселерометр bnoch bno055.Он поставляется с файлами bno055.c, bno055.h и bno055_support.c.После того, как я начал заниматься программированием и изучал / пробовал, мне как-то нужно определить, как читать и писать в I2C.Его необходимо настроить, чтобы вы могли определить количество прочитанных / записанных байтов.Ниже вы можете найти две предустановленные функции:

/*  \Brief: The API is used as I2C bus write
 *  \Return : Status of the I2C write
 *  \param dev_addr : The device address of the sensor
 *  \param reg_addr : Address of the first register,
 *   will data is going to be written
 *  \param reg_data : It is a value hold in the array,
 *      will be used for write the value into the register
 *  \param cnt : The no of byte of data to be write
 */
s8 BNO055_I2C_bus_write(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
{
    s32 BNO055_iERROR = BNO055_INIT_VALUE;
    u8 array[I2C_BUFFER_LEN];
    u8 stringpos = BNO055_INIT_VALUE;

    array[BNO055_INIT_VALUE] = reg_addr;
    for (stringpos = BNO055_INIT_VALUE; stringpos < cnt; stringpos++)
        array[stringpos + BNO055_I2C_BUS_WRITE_ARRAY_INDEX] =
            *(reg_data + stringpos);
    }
    /*
    * Please take the below APIs as your reference for
    * write the data using I2C communication
    * "BNO055_iERROR = I2C_WRITE_STRING(DEV_ADDR, ARRAY, CNT+1)"
    * add your I2C write APIs here
    * BNO055_iERROR is an return value of I2C read API
    * Please select your valid return value
    * In the driver BNO055_SUCCESS defined as 0
    * and FAILURE defined as -1
    * Note :
    * This is a full duplex operation,
    * The first read data is discarded, for that extra write operation
    * have to be initiated. For that cnt+1 operation done
    * in the I2C write string function
    * For more information please refer data sheet SPI communication:
    */
    return (s8)BNO055_iERROR;
}

 /* \Brief: The API is used as I2C bus read
 *  \Return : Status of the I2C read
 *  \param dev_addr : The device address of the sensor
 *  \param reg_addr : Address of the first register,
 *  will data is going to be read
 *  \param reg_data : This data read from the sensor,
 *   which is hold in an array
 *  \param cnt : The no of byte of data to be read
 */
s8 BNO055_I2C_bus_read(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
{
    s32 BNO055_iERROR = BNO055_INIT_VALUE;
    u8 array[I2C_BUFFER_LEN] = {BNO055_INIT_VALUE};
    u8 stringpos = BNO055_INIT_VALUE;

    array[BNO055_INIT_VALUE] = reg_addr;

    /* Please take the below API as your reference
     * for read the data using I2C communication
     * add your I2C read API here.
     * "BNO055_iERROR = I2C_WRITE_READ_STRING(DEV_ADDR,
     * ARRAY, ARRAY, 1, CNT)"
     * BNO055_iERROR is an return value of SPI write API
     * Please select your valid return value
     * In the driver BNO055_SUCCESS defined as 0
     * and FAILURE defined as -1
     */
    for (stringpos = BNO055_INIT_VALUE; stringpos < cnt; stringpos++)
        *(reg_data + stringpos) = array[stringpos];
    return (s8)BNO055_iERROR;
}

Мой вопрос, есть ли кто-нибудь, кто может обучить меня в этом вызове?Я узнаю о https://www.kernel.org/doc/Documentation/i2c/dev-interface,, но застрял здесь на данный момент.Спасибо заранее за чтение / ответ.

1 Ответ

0 голосов
/ 24 октября 2018

Я недавно написал библиотеку , аналогичную той, которую вы описываете для акселерометра 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)

Функции, которые я дал вам выше, должны быть довольно близкими.Удачи!

...