I2c в Linux из пространства пользователя

Наконец дошли руки до i2c в raspberry pi. Шина i2c в Linux доступна из ядра и из пространства пользователя благодаря модулю i2c-dev.
Как работать с i2c устройствами в linux рассмотрим на примере часов реального времени DS1307.
У меня модуль Tiny I2C Clock.

Стоит модуль копейки, но мне с ним очень не фортануло. Получил бракованную плату. Под батарейкой 3 закороченные дорожки.

Пришлось резать.

Все, пожаловался.

У часов есть такие регистры:

Дальше в памяти расположен RAM, который можно использовать под собственные нужды.
Не забываем включить i2c на raspberry. Для этого в файле /boot/config.txt раскоментируйте строки:

dtparam=i2c_arm=on
dtparam=i2c=on

Для работы с i2c уже есть специальные утилиты i2c-tools.
Для установки на raspberry pi:

sudo apt-get install i2c-tools

Теперь можно найти все устройства на шине 1:

i2cdetect -y 1

Результат:

Обнаружены часы и модуль eeprom памяти с той же платы.
Сосредоточимся на часах. Согласно карте регистров выше видим, что нас интерисуют 6 первых регистров.

Вычитаем данные устройства с адресом 0x68:

i2cdump -y 1 0x68

Получаем:

Также в наличии команда i2cget. Вычитаем 0 байт.

i2cget -y 1 0x68 0

Получаем:

Это все очень весело и интересно, но мы же и сами программы писать умеем.
Почитаем 6 байт из i2c устройства.
Для этого открываем файл /dev/i2c-1 (или 0, если у вас старая малина).
Указываем адрес устройства (у меня 0x68)
Дабы установить указатель чтения в начало, нужно записать 0.
Читаем данные.

#include <unis?d.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>

#define DEV_ADDRESS 0x68
#define DEV_REGISTERS_NUM 6
int main()
{
    char i;
    char buf[10];
    const char * devName = "/dev/i2c-1";

    // Open up the I2C bus
    int file = open(devName, O_RDWR);
    if (file == -1)
    {
        perror(devName);
        exit(1);
    }

    // Specify the address of the slave device.
    if (ioctl(file, I2C_SLAVE, DEV_ADDRESS) < 0)
    {
        perror("Failed to acquire bus access and/or talk to slave");
        exit(1);
    }

    // Write a byte to the slave.
    buf[0] = 0;
    if (write(file, buf, 1) != 1)
    {
        perror("Failed to write to the i2c bus");
        exit(1);
    }

    // Read a byte from the slave.
    if (read(file,buf,DEV_REGISTERS_NUM) != DEV_REGISTERS_NUM)
    {
        perror("Failed to read from the i2c bus");
        exit(1);
    }
    for(i=0;i<6;i++)
        printf("0x%02X ", buf[i]);
    printf("\n");
    return 0;
}

Компилируем:

gcc i2c_example.c -o i2c_example

Запускаем:

В первом байте хранятся секунды, так-что не обращайте внимание, что он отличается.
Вот так можно читать.

Как же записать данные в часы?
Все еще проще, вместо записи нуля, пишем 0 (это адрес регистра, если что), а затем данные.

#include <unis?d.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>

#define DEV_ADDRESS 0x68
#define DEV_REGISTERS_NUM 6

int main()
{
    char i;
    char buf[10];
    const char * devName = "/dev/i2c-1";

    // Open up the I2C bus
    int file = open(devName, O_RDWR);
    if (file == -1)
    {
        perror(devName);
        exit(1);
    }

    // Specify the address of the slave device.
    if (ioctl(file, I2C_SLAVE, DEV_ADDRESS) < 0)
    {
        perror("Failed to acquire bus access and/or talk to slave");
        exit(1);
    }

    // Write a byte to the slave.
    buf[0] = 0;
    buf[1] = 0x00;
    buf[2] = 0x01;
    buf[3] = 0x02;
    buf[4] = 0x03;
    buf[5] = 0x04;
    buf[6] = 0x05;
    if (write(file, buf, DEV_REGISTERS_NUM) != DEV_REGISTERS_NUM)
    {
        perror("Failed to write to the i2c bus");
        exit(1);
    }

    return 0;
}

Результат записи:

Готово.
Помните, что работа с большинством i2c устройств таким образом — сущий изврат! В linux уже есть готовые драйвера для большинства устройств. И вам не нужно изобретать велосипед. Но об этом в следующей статье. Там мы посмотрим как скормить эти часы linux ядру и драйверу ds1307.

 

Похожий код:

Фото аватара
Алексей Петров

Программист, разработчик с 5 летним опытом работы. Учусь на разработчика игр на Unity и разработчика VR&AR реальности (виртуальной реальности). Основные языки программирования: C#, C++.

Оцените автора
Бла, бла код
Добавить комментарий