LINUX.ORG.RU

I2C сенсор как файл

 


0

1

Есть сенсор, подключенный к шине I2C и мне нужно мониторить его значение.

Существет ли возможность как-то через универсальный модуль ядра спроецировать i2c-адрес/регистр на файл, прописав его в дерево устройств, т.е. получить что-то типа /sys/class/hwmonN/inM_input?

Или придётся свой модуль писать?

P.S. Через юзер-модный i2c-tools не вариант (процессов-мониторов может быть несколько).

Добрый день. Попробую ответить на ваш вопрос. 1. Вам нужно запустить утилиту i2cdetect -i. 2. В даташите устройства, что вы хотите посмотреть, находите адрес устройства к которому прикреплен ваше устройство, это константа, жестко прописана в даташите. 3. Прописать номер устройства в дереве /dev/i2c-0,i2c-1... и.т.д. 4. написать программу которая открывает файл устройства на чтение этого файла. Там вы и сможете узнать данные с вашего датчика.

charly_one
()
Ответ на: комментарий от charly_one

Адреса шины и регистров мне известны и само устройство есть (/dev/i2c-...), но нет отдельного драйвера, который мапит регистр на файл.

Т.е. через i2cget я его могу получить значение регистра, но в пользовательском режиме его опрашивать «не камильфо», т.к. между записью адреса регистра и его чтением проходит какое-то время, в течение которого второй процесс может запросить другой регистр.

Нужна блокировка, что бы запись-чтение были атомарными для user mode.

artemsen
() автор топика

/sys/class/hwmon - папка содержит данные на устройства, значения датчиков, таких как например - нижняя и верхняя границы температуры, напряжения и прочее. Linux при загрузке сам, автоматические создает и присваивает имена устройствам, что находит их и помещает их в эту самую папку. Вы можете найти подробную документацию в папке дерева ядра. /Documentation. Почитайте о назначении файловой системы sysfs.

charly_one
()
Ответ на: комментарий от artemsen

Ясно... Я у меня не было разделения на режим пользователя или ядра. На шине i2c висело 4 устройства по разным адресам. Я просто по ключу в своей проге выводил любое устройство. Все просто было.

charly_one
()
Ответ на: комментарий от charly_one

Драйвера у вас нет для работы сенсоров.. ТОгда придется написать. Попробуйте на гитхабе найти, или в самом ядре... у меня был драйвер lm90.c , lm75.c lm75.h. Если нет то можете легко его написать по уже существующим. Шаблон один у них.

charly_one
()
Ответ на: комментарий от charly_one

Нужно сравнить свою микросхему с теми устройствами, что уже реализованы в виде драйверов уже в линухе. Сравнить их даташиты. Скорее всего уже все есть и ваш драйвер тоже.

charly_one
()
Ответ на: комментарий от artemsen

Еще нужно права раздать на чтение/запись устройств i2c-x. Чтобы ваша утилита могла их открывать и читать open(«/dev/i2c-x», rw); В рэмдиске - легко делается... Там есть такой файл написания рэмдиск-файла, в папке с документацией.

charly_one
()
Ответ на: комментарий от artemsen

Откройте файл lm90.c. Там вы найдете как api функцию как создавать в sysfs ваше устройство.

charly_one
()
Ответ на: комментарий от charly_one

Драйвера у вас нет для работы сенсоров

Нет, в том-то и проблема. Я про это и спрашиваю, есть ли какой-то универсальный драйвер для чтения i2c и как прописать устройство в дереве со ссылкой на него. Что бы не писать свой модуль.

P.S.

Linux при загрузке сам, автоматические создает и присваивает имена устройствам

Не совсем )) В дереве устройств ставится ссылка на совместимый модуль, а модуль уже регистриует устройства класса I2C_CLASS_HWMON (как пример - https://github.com/torvalds/linux/blob/master/drivers/hwmon/w83795.c#L2276).

artemsen
() автор топика
Ответ на: комментарий от artemsen

Нет, драйвер на вашу микросхему нужно писать самому, если его конечно нет в дереве, но это не проблема.

charly_one
()
Ответ на: комментарий от artemsen

smbus сама адреса раздает автоматически, у микросхем целый диапазон адресов бывает.

charly_one
()
Ответ на: комментарий от artemsen

при конфигурации и сборки прошивки выставите у линуха во вкладке шины и2с режим дебаг. Полезно будет.

charly_one
()
Ответ на: комментарий от charly_one

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

Это не всегда так. Есть микросхемы (например, термодатчик LM75AD), у которых адрес задаётся через специальные ножки. Тогда, чтобы определить этот адрес, надо смотреть схему.

akk ★★★★★
()
Ответ на: комментарий от charly_one

как микросхема называется у вас?

AST2400

К ней подключён датчик состояния PSU, который доступен мне через i2c.

artemsen
() автор топика
Ответ на: комментарий от akk

Да я знаю... Это ds1775 - типа такой.., реализован в lm75. Dallas Semiconducter. Значит нужно реализовать драйвер на базе его... структура i2c_struct - это структура для описания устройства.. Апи там одинаковый у всех устройств, что работают на и2с. Если желаете записать инфу о вашей микросхеме в sysfs, то подключите хидеры соответсвенно с этой фс. Ну а далее работа с данными и обработка данных с микросхемы сами напишите.. функция detect - для определения и выбора микрухи из списка с инициализацией... probe - включает уже потом...

По памяти пишу вам... Не все помню..

charly_one
()
Ответ на: комментарий от artemsen

Хорошо, гляну вашу микруху.. завтра напишу вам... пора домой уже.

charly_one
()
Ответ на: комментарий от artemsen

Доброе утро. Держите устарелый код утилиты, которая считывает данные температуры с двух термодатчиков ds1775 и max6649. Не реализована работа с isl12023ivz. Данного кода достаточно, чтобы вы поняли принцип работы утилиты работающей с устройствами на шине i2c. Можете детально ознакомиться с микросхемами и посмотреть код. У вас скорее всего тоже самое, вероятность 99%.

#include <linux/errno.h> #include <time.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h>

#include <linux/ioctl.h> #include <linux/rtc.h> #include <linux/i2c.h> #include <linux/i2c-dev.h> #include <sys/stat.h> #include <sys/types.h> //#include <regex.h>

#include <sys/time.h> #include <dirent.h> #include <stdio.h> #include <string.h>

#include <stdlib.h> #include <errno.h>

#define BCD2BIN(val) (((val)&15) + ((val)>>4)*10) #define BIN2BCD(val) ((((val)/10)<<4) + (val)%10)

void stat_info(const char *filename, struct stat *buf);

int search_i2c_dev(const char *filename, unsigned int addr, unsigned char reg);

static int get_i2c_register(int file, unsigned char addr, unsigned char reg, unsigned char *val);

int main(int argc, char *argv[]) { struct dirent *_dirent; char const i2c_buf[] = {«This program is for work with i2c bus\n»}; struct stat _buf; int buffer[100], cmd = 0; const char *filename1 = «/dev/i2c-4»; const char *filename2 = «/dev/rtc0»; int result; unsigned day_time; while ((cmd = getopt(argc, argv, «ltfiv»)) != -1) { switch(cmd) { case 'l': //max6649 puts(«max6649 sensor»); result = search_i2c_dev(filename1 ,0x4c, 0x01); printf(«Remote sensor temperature is: %d\n», result); result = search_i2c_dev(filename1, 0x4c, 0x00); printf(«Local sensor temperature is: %d\n», result); //ds1775 puts(«ds1775 sensor»); result = search_i2c_dev(filename1, 0x49, 0x00); printf(«Local sensor temperature is: %d\n», result); break; case 't': // show_time(filename); //isl12023ivz rtc clock puts(«Intersil 12023ivz real time clock»); day_time = search_i2c_dev(filename1, 0x57, 0x05);//year day_time = BCD2BIN((day_time)+100); //day_time = BIN2BCD((day_time)+100); printf(«The Year is: %d \n», day_time); day_time = search_i2c_dev(filename1, 0x57, 0x04); //month day_time = BCD2BIN((day_time)-1); //day_time = BIN2BCD((day_time)-1); printf(«The Month is: %d \n», day_time); day_time = search_i2c_dev(filename1, 0x57, 0x03); //day //0x57 addr day_time = BCD2BIN(day_time); //day_time = BIN2BCD(day_time); printf(«The Day is: %d \n», day_time); day_time = search_i2c_dev(filename1, 0x57, 0x00); day_time = BCD2BIN(day_time); //day_time = BIN2BCD(day_time); printf(«time sec % i\n», day_time); day_time = search_i2c_dev(filename1, 0x57, 0x01); day_time = BIN2BCD(day_time); //day_time = BCD2BIN(day_time); printf(«time minutes % i\n», day_time); day_time = search_i2c_dev(filename1, 0x57, 0x02); //day_time = BIN2BCD(day_time); day_time = BCD2BIN(day_time); printf(«time hours % i\n», day_time); //search_i2c_dev(0x57, 0x04);//month //search_i2c_dev(0x57, 0x03);//day printf(«printed rtc - time output\n\r»); break; case 'f': if(!stat(«temp_utility», &_buf)) { puts(«Unable to get stat inf about file»); } // stat_info(filename, &_buf); break; case 'i': printf («\t -l\t - key prints temperature data\n\r» «\t -t\t - key prints rtc - time\n\r» «\t -f\t - key prints full information about output file\n\r» «\t -v\t - key prints a utility version\n\r» «\t -i\t - key shows information about keys\n\r»); break; case 'v': printf(«Utility version is 1.0\n\r»); break; default: printf(«No argument, type -i\n»); break; } } return (0); }

void stat_info(const char *filename, struct stat *buf) { printf(«I-node number: %ld\n», (long) buf->st_ino); printf(«Mode: %lo(octal)\n», (unsigned long)buf->st_mode); printf(«User: %s\n», buf->st_uid); printf(«Size: %d\n», buf->st_size); printf(«Blocks allocated: %d\n», (long long)buf->st_blocks); printf(«Group: %s\n», buf->st_gid); printf(«Name: %s\n», filename); printf(«Last file access: %s\n», ctime(buf->st_atime)); printf(«Last file modification: %s\n», ctime(buf->st_mtime)); }

int 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; // The data will get returned in this structure // messages[1].addr = addr; messages[1].flags = I2C_M_RD; // | I2C_M_NOSTART//; messages[1].len = sizeof(inbuf); messages[1].buf = &inbuf; // Send the request to the kernel and get the result back // packets.msgs = messages; packets.nmsgs = 2; if(ioctl(file, I2C_RDWR, &packets) < 0) { perror(«Unable to send data»); return 1; } *val = inbuf; return 0; }

int search_i2c_dev(const char *filename, unsigned int addr, unsigned char reg) { int file = open(filename, O_RDONLY); unsigned char value; if(!file) { puts(«Can't open device»); return -EFAULT; } if(get_i2c_register(file, addr, reg, &value)) { puts(«Unable to get register!»); } close(file); return (int)value; }

charly_one
()
Ответ на: комментарий от charly_one

А теперь то же самое, но в тегах [code]

anonymous
()
Ответ на: комментарий от artemsen

Доброе утро. Как успехи в реализации драйвера и приложения? Есть у вас вопросы?

charly_one
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.