Наконец дошли руки до 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.








