«Печенье с малиновым джемом» или чаепитие с Raspberry Pi
kayo — Втр, 30/04/2013 - 01:23
Raspberry Pi — весьма забавное устройство, с которым можно делать много интересного, прикладывая минимум усилий. У нас в распоряжении вполне зрелое для своего уровня железо со всевозможными интерфейсами (чип armv6t BCM2835), что вкупе с «родной» операционной системой Raspbian (порт Debian на официально не поддерживаемый ABI используемого процессора) делает устройство весьма привлекательным для реализации самых странных хотелок искушенного разработчика. Наибольший интерес представляют низкоуровневые интерфейсы, используемые в индустрии мобильных и встраиваемых систем: I2C, SPI, UART, а также несколько портов GPIO, которые можно использовать по своему усмотрению без всяких ограничений, как для простых операций состоянием сигналов, так и для эмуляции других интерфейсов, не поддерживаемых аппаратно используемым MCU.
Была задача сделать устройство, которое будет работать автономно долгое время без непосредственного вмешательства прочих сапиенсов, ну разве что за редким эпизодическим присутствием.
Доработка напильником
Многие низкоуровневые интерфейсы выведены на коннектор P1 (это тот, у которого больше всего ног на плате). Вся информация о выведенных портах MCU и выводах питания есть в вики. Удобно распечатать такой листик и надеть прямо на разъём, чтобы не перепутать, что куда подключать.
Аппаратные часы
Первая вещь, которой мне очень не хватало на малинке, — аппаратные часы. Казалось бы, чего стоило разработчику поставить самые стандартные копеечные часы на DS1307 с малюсенькой батарейкой непосредственно на плату. Но видимо не особо это нужно для той ЦА, на которую устройство ориентированно. Что ж, придётся доработать самим.
Часы с интерфейсом I2C я купил готовые на ebay самые дешевые на базе DS1307Z. На плате зачем-то ещё стоит AT24C32, это EEPROM на 32К, который тоже доступен по I2C, может вы придумаете, для чего его использовать?
Подключил стандартно (SDA1, SCL1 — это второй интерфейс шины I2C на MCU пи), запитка от 5V, а не 3.3V. Но что бы устройства корректно работали, пришлось выпаять лишние подтяжки на 3.3K, которые стояли на плате часов, ведь у нас уже есть на 1.5К в RPi.
Спасибо jfornango за то, что подсказал, как правильно воткнуть аппаратные часы программно:
# вычищаем фальшивые часы sudo dpkg --purge fake-hwclock sudo rm /etc/rcS.d/K0?hwclock.sh # ставим инструменты I2C sudo apt-get install i2c-tools # загружаем нужные модули sudo modprobe i2c-bcm2708 sudo modprobe i2c-dev sudo modprobe rtc-ds1307 # можем увидеть нечто интересное тут ls -al /sys/bus/i2c/devices/i2c-1 # проверяем видны ли устройства sudo i2cdetect -y 1 # пробуем забиндить часы sudo -s echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device exit # пробуем читать время sudo hwclock -r # поставим правильное время sudo hwclock -w # теперь делаем часы перманентными sudo nano /etc/modules # добавляем модули: i2c-bcm2708 i2c-dev rtc-ds1307 # удаляем из черного списка эти модули, если они там есть sudo nano /etc/modprobe.d/raspi-blacklist.conf # фиксим сервис аппаратных часов sudo nano /etc/init.d/hwclock # в зависимости для запуска (Required-Start) добавляем kmod # параметр X-Start-Before подчищаем, иначе будет конфликт # перед стартом сервиса инициализируем устройство sudo nano /etc/default/hwclock # добавляем строку: # echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device # вручную правим симлинки cd /etc/rc0.d sudo ln -s ../init.d/hwclock.sh K06hwclock.sh cd ../rc6.d sudo ln -s ../init.d/hwclock.sh K06hwclock.sh cd ../rcS.d sudo ln -s ../init.d/hwclock.sh S10hwclock.sh # разрешаем сервис sudo update-rc.d hwclock.sh enable
Если не удалить fake-hwclock, будет происходить нечто невероятное, что отъело у меня много времени.
Интерфейс 1-wire
Мне понадобилось подключить пучок термодатчиков от Dallas/Maxim DS18B20 в режиме паразитного питания. Интерфейс 1-wire на Raspberry Pi эмулируется bitbanging-ом на одном порту GPIO4. Вот что нам нужно сделать:
# загружаем модули sudo modprobe w1-gpio sudo modprobe w1-therm # подключаем датчики и проверяем, видны ли они ls /sys/bus/w1/devices # должны увидеть что-то типа: # 10-00080198b895 28-0000029fbfe8 w1_bus_master1 # первые два устройства — мои датчики # последнее — контроллер шины # пробуем считать данные cat /sys/bus/w1/devices/10-00080198b895/w1_slave # увидим что-то вроде: # 31 00 4b 46 ff ff 08 10 95 : crc=95 YES # 31 00 4b 46 ff ff 08 10 95 t=85000 # измеренная температура 85°C для комнаты? # это означает, что термометр не делал измерения # поскольку датчики у меня подключены в режиме # паразитного питания
Однако актуальное на момент написания ядро 3.6.11+ от 7 февраля 2013 не поддерживало режим паразитного питания, когда датчики при работе встроенного АЦП запитываются от сигнальной линии через резистор-подтяжку, когда нет обмена данными, и на ней высокий уровень.
Патч появился несколько позднее и активируется передачей модулю параметра pullup=1. Последняя сборка ядра находится здесь. Скрипт для автоматизированного обновления тут. После установки версии ядра с патчем, всё заработало, как надо:
# снова загружаем модули sudo modprobe w1-gpio pullup=1 sudo modprobe w1-therm # снова пробуем считать данные cat /sys/bus/w1/devices/10-00080198b895/w1_slave # увидим что-то вроде: # 31 00 4b 46 ff ff 08 10 95 : crc=95 YES # 31 00 4b 46 ff ff 08 10 95 t=24250 # измеренная температура 24.25°C вполне адекватна # прописываем модули в /etc/modules # w1-gpio pullup=1 # w1-therm
IR пульт
Если уж развлекаться, то на полную. Валялся у меня без дела ИК-пульт от TV-тюннера вместе с приёмником на шнурке. Впору пристроить его к Pi в качестве основного девайса пользовательского ввода. Подключается это дело нехитро, у приёмника три вывода: земля, питание и сигнальный. На питание подадим 3.3V, а сигнальный подключим к GPIO18. Осталось настроить софт:
# устанавливаем lircd sudo apt-get install lirc # нам поругаются, что lirc не настроен # всё в порядке, так и должно быть # загружаем модуль sudo modprobe lirc_rpi # теперь можем послушать команды с пульта sudo mode2 -d /dev/lirc0 # направляем пульт на приёмник и нажимаем кнопки # смотрим, что к нам приходит
О да, Кэп, это морзянка.
# настраиваем lirc sudo nano /etc/lirc/hardware.conf # правим DRIVER="default" # DEVICE="/dev/lirc0" # MODULES="lirc_rpi" # и LIRCD_ARGS="--uinput" # также я раскомментировал # START_LIRCMD=false # потому что буду активировать режим мыши кнопкой # находим подходящие конфиги под ваш пульт # в /usr/share/lirc/remotes # мне подошли avermedia/lircd.conf.avermedia98 # и avermedia/lircmd.conf.avermedia98 для мыши # если готовых конфигов нет, можно нагенерить # с помощью irrecord irrecord -d /dev/lirc0 ~/lirc.conf # сервис мыши запускаем при входе в сеанс sudo nano /etc/X11/Xsession.d/99lircmd # добавляем строки killall lircmd lircmd --uinput # чтобы переключать мышь например кнопкой Autoscan # добавляем в конфиг мыши TOGGLE_ACTIVATE * AUTOSCAN # запускаем сервис sudo service lirc start # смотрим, правильно ли lirc распознаёт события irw # нажимаем кнопки и смотрим вывод
Доработка наждачкой
Ну и на закуску осталось немного подтюнить ОС.
Сторожевой таймер
Поскольку моё устройство будет трудиться вдали от заботливых сисадминских рук, мне понадобилось задействовать аппаратный watchdog, дабы в случае чего система помогла себе сама. Работает это просто как бревно: аппаратный счётчик инициализируется некоторым значением и отсчитывает назад, как только значение обнулится, произойдёт аппаратный сброс процессора. Чтобы этого не произошло, мы должны программно с приемлемым интервалом реинициализировать счетчик.
Функции watchdog таймера на Raspberry Pi реализованы модулем bcm2708_wdog. А использовать его мы будем посредством сервиса watchdog:
# ставим сервис sudo apt-get install watchdog # указываем используемый модуль sudo nano /etc/default/watchdog # меняем watchdog_module="none" # на watchdog_module="bcm2708_wdog" # указываем используемое устройство sudo nano /etc/watchdog.conf # раскомментируем строку: # watchdog-device = /dev/watchdog # убедимся, что сторожевой таймер запущен в режиме # реального времени, иначе могут быть проблемы: # realtime = yes # priority = 1 # закомментируем строки, которые потенциально могут # вызвать проблемы, вроде этой: # pidfile = /var/run/syslogd.pid # как видно, здесь ещё много чего интересного # можно настроить, например реакцию на перегрузку # (строки max-load-*) # настраиваем модуль sudo nano /etc/modprobe.d/watchdog.conf # добавляем options bcm2708_wdog heartbeat=15 # параметр heartbeat указывает число секунд, # которое должно пройти до аппаратного сброса # перезапускаем сервис sudo service watchdog restart
Итак, сторожевой таймер работает, но хотелось бы как-то убедиться в этом воочию. Есть много способов проверки:
- Форк-бомба. Цепная реакция с рекурсивным порождением дочерних процессов. Классическая реализация на Bash: (: (){ :|:& };:). Будет работать только если мы науськали нашего пса дергать сброс при перегрузке системы (раскомментировали строки max-load-* в конфиге). Если нет, можно попробовать запустить вочдог не в realtime и взорвать форк-бомбу, но должного эффекта придётся прилично подождать.
- Модуль panic.ko. Более действенный способ, если не лень собирать, сработает в любом случае, ибо «убъёт систему окончательно и бесповоротно» (шутка).
- Тупо убить процесс сервиса (sudo killall watchdog). В таком случае работа с устройством /dev/watchdog будет завершена некорректно, туда просто перестанут поступать сигналы реинициализации, и через указанные нами 15 секунд произойдёт аппаратный сброс. Ввиду своей лени этот способ я и применил. Сработало.
Ещё пара слов о watchdog. Модулю ядра можно передать параметр nowayout = 0, чтобы разрешить останавливать таймер, который уже однажды был запущен. По умолчанию nowayout = 1, можно подумать, что при остановке сервиса через какоето время сработает аппаратный сброс. На самом деле это не так, потому что при остановленном watchdog работает сервис wd_keepalive, который осуществляет реинициализацию таймера.

Хочу добавить про часы.У меня
Алексей (не проверено) — Пт, 25/10/2013 - 18:13Хочу добавить про часы.
У меня алгоритм почему-то не сработал. А помогло решение с сайта:
1. Ставим инструменты I2C
sudo apt-get install i2c-tools
2. Удаляем из черного списка модули i2c-bcm2708, i2c-dev, rtc-ds1307, если они там есть
sudo nano /etc/modprobe.d/raspi-blacklist.conf
3. Правим скрипт hwclock.sh
sudo nano /etc/init.d/hwclock.sh
Добавляем в функцию hwclocksh() после строк
start)
# If the admin deleted the hwclock config, create a blank
# template with the defaults.
if [ -w /etc ] && [ ! -f /etc/adjtime ] && [ ! -e /etc/adjtime ]; then
printf "0.0 0 0.0\n0\nUTC" > /etc/adjtime
fi
строку init_rtc_device и комментируем следующие 3 строки:
init_rtc_device
# if [ -d /run/udev ] || [ -d /dev/.udev ]; then
# return 0
# fi
После функции hwclocksh() вставляем функцию
init_rtc_device()
{
[ -e /dev/rtc0 ] && return 0;
# load i2c and RTC kernel modules
modprobe i2c-dev
modprobe rtc-ds1307
# iterate over every i2c bus as we're supporting Raspberry Pi rev. 1 and 2
# (different I2C busses on GPIO header!)
for bus in $(ls -d /sys/bus/i2c/devices/i2c-*);
do
echo ds1307 0x68 >> $bus/new_device;
if [ -e /dev/rtc0 ];
then
log_action_msg "RTC found on bus `cat $bus/name`";
break; # RTC found, bail out of the loop
else
echo 0x68 >> $bus/delete_device
fi
done
}
4. разрешаем сервис hwclock и отключаем fake-hwclock
sudo update-rc.d fake-hwclock disable
sudo update-rc.d hwclock.sh enable
Очень рекомендую поставить
kayo — Вс, 27/10/2013 - 22:50Очень рекомендую поставить systemd на Raspbian, скорость загрузки возрастёт прилично.
По поводу часов, в данный момент я использую udev правила для инициализации устройства и systemd скрипт для начальной установки системных часов с аппаратных.
/etc/udev/rules.d/80-ds1307.rules:
/etc/systemd/system/hwclockinit.service:
Здравствуйте!В своей статье
Arty (не проверено) — Сб, 08/02/2014 - 05:43Здравствуйте!
В своей статье Вы пишите: "Подключил стандартно (SDA1, SCL1 — это второй интерфейс шины I2C на MCU пи), запитка от 5V, а не 3.3V. Но что бы устройства корректно работали, пришлось выпаять лишние подтяжки на 3.3K, которые стояли на плате часов, ведь у нас уже есть на 1.5К в RPi."
Я нехорошо разбираюсь в схемотехнике и не хочу ничего испортить. На плате RTC находятся 4 резистора на 3.3 кОм. Они обведены красным (R2,R3) и зеленым (R1,R8) на фотографии:
http://upyourpic.org/images/201312/21ke6sec1v.jpg
В связи с этим у меня пара вопросов:
1. Правильно ли я понял, что нужно выпаивать только два резистора R2 и R3, обведенные красным цветом?
2. После выпаивания резисторов нужно ли закоротить контакты, к которым они были припаяны, или оставить как есть?
Спасибо!
У вас модуль работает в таком
kayo — Сб, 08/02/2014 - 19:41Недавно прикрутил часы,
Гость (не проверено) — Пнд, 07/04/2014 - 02:26Недавно прикрутил часы, все нормально работало… Пока не запустил программу, использующую I2C (через библиотеку bcm2835). После первого запуска часы перестают работать. В смысле, через hwclock. При этом через библиотеку bcm2835 часы читаются и пишутся.
root@raspberrypi:/home/pi# hwclock
hwclock: ioctl(RTC_RD_TIME) to /dev/rtc0 to read the time failed
root@raspberrypi:/home/pi#
Восстанавливается только после перезагрузки. И до первого запуска моей проги.
Да, и i2cdetect перестает видеть устройства на шине. Все девайсы при этом нормально работают.
Очевидно, что библиотека
kayo — Пнд, 07/04/2014 - 11:29Очевидно, что библиотека конфликтует с драйвером в ядре. Для того собственно и нужен драйвер, чтобы организовать совместную работу нескольких устройств на шине. А библиотека bcm2835 работает с MCU напрямую, поэтому я её не использую. В общем, вам нужно выбрать один из вариантов:
Советую работать через ядро, в доке (Documentation/i2c/dev-interface) всё подробно описано.
Спасибо за статью.На одной из
Zement (не проверено) — Пт, 16/05/2014 - 16:24Спасибо за статью.
На одной из сборок Raspbian всё отлично встало (по статье). На сборке за январь 2014, при самой установке watchdog'а начали появляться ошибки выполнения конфигурации (хотя сам watchdog в системе появлялся). После правки конфигов, старта сервиса, и всяческих рестартов, проверок (форк_бомбами, или через 'killall watchdog') - результат был нулевой.
Помогли рекоммендации из последнего поста этой темы:
http://www.raspberrypi.org/forums/viewtopic.php?t=66059&p=515215
Возможно, кому-то пригодится.
Отправить комментарий