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