Вопрос или проблема
На моем Beaglebone Black я добавил I2C реальное время, чтобы не зависеть от ntpd для поддержания точного времени. В итоге в /dev
появились два специальных файла устройств. Это /dev/rtc0
и /dev/rtc1
, но также есть /dev/rtc
, который является символической ссылкой на /dev/rtc0
.
/dev/rtc0
— это часы реального времени в ARM SOC на плате, /dev/rtc1
— это I2C устройство. В настоящее время я использую скрипты, которые вручную читают и записывают время в I2C часы, но я бы предпочел, чтобы символическая ссылка /dev/rtc
указывала на /dev/rtc1
.
Следовательно, вопрос, как это можно сделать? Линукс-дистрибутив на моем beaglebone black — это Arch Linux, который использует systemd для управления системой.
Когда я удаляю символическую ссылку и создаю новую, указывающую на /dev/rtc1
, неудивительно, что она сбрасывается после следующей перезагрузки, и я пока не нашел никаких конфигурационных файлов или юнитов systemd.
Буду признателен за помощь.
Указание на правило udev направило меня в правильном направлении. После быстрого изучения написания udev правил я сделал следующее.
udevadm info -a -p /sys/class/rtc/rtc1
Вывод (сокращенный) показал некоторые полезные свойства для определения правила udev.
посмотрим на устройство '/devices/platform/ocp/4802a000.i2c/i2c-1/1-0068/rtc/rtc1':
KERNEL=="rtc1"
SUBSYSTEM=="rtc"
DRIVER==""
ATTR{date}=="2015-12-04"
ATTR{hctosys}=="0"
ATTR{max_user_freq}=="64"
ATTR{name}=="ds1307"
ATTR{since_epoch}=="1449230817"
ATTR{time}=="12:06:57"
...
Итак, файл правил должен находиться в /etc/udev/rules.d/
с принципом именования, например 99-rtc1.rules
.
Содержимое файла:
KERNEL=="rtc1", SUBSYSTEM=="rtc", DRIVER=="", ATTR{name}=="ds1307", SYMLINK="rtc", MODE="0666"
Для тех, у кого другая система/настройка, самая важная часть этого правила — это ATTR{name}
. Вы можете легко найти это, выполнив:
udevadm info -a -p /sys/class/rtc/rtc1 | grep "ATTR{name}"
# где вывод может быть таким, как на Raspberry Pi5:
ATTR{name}=="rtc-rv3028 1-0052"
Для проверки правила вы можете выполнить
udevadm test /sys/class/rtc/rtc1
и важные строки в выводе следующие
...
создание ссылки '/dev/rtc' на '/dev/rtc1'
атомарная замена '/dev/rtc'
...
Результат в /dev
— это желаемая конфигурация.
После множества попыток заставить мои I2C RTC часы работать на Orange Pi PC плюс со встроенными RTC, я (не самым элегантным образом) добился успеха.
- Выясните путь к встроенным rtc:
#>find /sys | egrep 'rtc$'
/sys/bus/platform/drivers/sun6i-rtc/1f00000.rtc
Вы, вероятно, получите много строк, просто сосредоточьтесь на строках с “/sys/bus…”
- Создайте udev для управления созданием устройства и ссылок на устройство
#>nano /etc/udev/rules.d/99-rtc1.rules
Вставьте это содержимое:
KERNEL=="rtc1", SUBSYSTEM=="rtc", DRIVER=="", ATTR{name}=="rtc-ds1307 0-0068", ATTR{hctosys}=="0", SYMLINK+="rtc", SYMLINK+="rtc0", MODE="0666"
- Теперь нужно создать службу systemd:
#>nano /etc/systemd/system/rtc.service
Следующее содержимое должно быть отредактировано в соответствии с вашими встроенными rtc0 и I2C устройствами на линии ExecStart
:
[Unit]
Description=Initialize ds1307 RTC and sincronize system clock
DefaultDependencies=no
Requires=systemd-modules-load.service
After=systemd-modules-load.service
#Before=sysvinit.target
ConditionPathExists=/sys/class/i2c-adapter
#Conflicts=shutdown.target
[Service]
Type=oneshot
RemainAfterExit=yes
User=root
WorkingDirectory=/root
ExecStart=/bin/sh -c "echo -n "1f00000.rtc" > /sys/bus/platform/drivers/sun6i-rtc/unbind && echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-0/new_device && hwclock --rtc /dev/rtc --hctosys --utc"
[Install]
WantedBy=multi-user.target
- Активируйте службу:
#>systemctl enable rtc.service
- Запустите службу:
#>systemctl start rtc.service
- Вы можете проверить, изменились ли устройства
/dev/rtc*
соответственно, используяls -lah /dev/rtc*
, и у вас должно быть что-то подобное:
lrwxrwxrwx 1 root root 4 Apr 3 18:19 /dev/rtc -> rtc1
lrwxrwxrwx 1 root root 4 Apr 3 18:19 /dev/rtc0 -> rtc1
crw-rw-rw- 1 root root 253, 1 Apr 3 18:19 /dev/rtc1
Теперь rtc и rtc0 указывают на rtc1!
- Проверьте, работает ли hwclock с помощью
hwclock --verbose
hwclock from util-linux 2.37.2
System Time: 1680548612.161304
Trying to open: /dev/rtc0
Using the rtc interface to the clock.
Last drift adjustment done at 1680540088 seconds after 1969
Last calibration done at 1680540088 seconds after 1969
Hardware clock is on UTC time
Assuming hardware clock is kept in UTC time.
Waiting for clock tick...
ioctl(4, RTC_UIE_ON, 0): Invalid argument
Waiting in loop for time from /dev/rtc0 to change
...got clock tick
Time read from Hardware Clock: 2023/04/03 19:03:33
Hw clock time : 2023/04/03 19:03:33 = 1680548613 seconds since 1969
Time since last adjustment is 8525 seconds
Calculated Hardware Clock drift is 0.000000 seconds
2023-04-03 19:03:32.766066+00:00
Чтобы обновить ваши часы по системному времени, просто используйте hwclock -w
, чтобы обновить их от rtc, используйте hwclock -s
Вам нужно добавить ваш модуль в /etc/modules
echo "rtc-ds1307" >> /etc/modules
.
Ответ или решение
Для решения проблемы изменения цели символической ссылки /dev/rtc
на вашей плате Beaglebone Black с операционной системой Arch Linux и использованием systemd, вам необходимо создать правило udev. Это позволит сделать изменения устойчивыми к перезагрузке. Использование udev позволит автоматически создавать и настраивать ссылки при каждом запуске системы.
Теория
Одной из основных задач системы udev является управление созданием и изменением устройств в каталоге /dev
, когда ядро Linux обнаруживает новое оборудованное устройство. Устройства как /dev/rtc0
и /dev/rtc1
обычно создаются автоматически системой, и для управления их поведением (например, создания специфической символической ссылки) нужно настроить правило udev.
Пример
Каждое устройство в /dev
связано с объектами в /sys
, структура которых образует иерархию всех подключенных устройств. Чтобы понять структуру вашего I2C RTC устройства, вы можете использовать команду udevadm info
. Например:
udevadm info -a -p /sys/class/rtc/rtc1
Эта команда предоставляет информацию обо всех атрибутах устройства, таких как KERNEL, SUBSYSTEM и другие, которые можно использовать в правилах udev. Выделенная часть—атрибут ATTR{name}
—в нашем случае является ключевой для идентификации устройства.
Применение
Чтобы применить теорию на практике и изменить символическую ссылку /dev/rtc
, выполните следующие шаги:
-
Создание правила udev
Создайте новый файл правила udev в каталоге
/etc/udev/rules.d/
, например, назовите его99-rtc1.rules
. Содержимое этого файла может выглядеть так:KERNEL=="rtc1", SUBSYSTEM=="rtc", DRIVER=="", ATTR{name}=="ds1307", SYMLINK+="rtc", MODE="0666"
В этом правиле:
KERNEL=="rtc1"
указывает на устройство, имя которого должно бытьrtc1
.SUBSYSTEM=="rtc"
иDRIVER==""
уточняют тип устройства.ATTR{name}=="ds1307"
использует идентифицирующий атрибут для устройства.SYMLINK+="rtc"
создает символическую ссылку/dev/rtc
, указывающую на/dev/rtc1
.MODE="0666"
обеспечивает открытый доступ к устройству (чтение и запись для всех).
-
Тестирование правила
Протестируйте правило без перезагрузки системы:
udevadm test /sys/class/rtc/rtc1
В выходных данных вы должны увидеть строки, указывающие на создание и замену ссылки
/dev/rtc
на/dev/rtc1
. -
Применение изменений
Перезагрузите udev для применения изменений:
udevadm control --reload-rules udevadm trigger
Это заставит udev пересканировать устройства и применить новые правила.
-
Проверка результата
Проверьте, что ссылка
/dev/rtc
теперь указывает на правильное устройство:ls -lah /dev/rtc*
Вы увидите, что
/dev/rtc
теперь является ссылкой на/dev/rtc1
. -
Настройка службы Systemd
Для обеспечения еще большей надежности создания и настройки устройств на ранних этапах загрузки, вы можете создать службу systemd:
Создайте новую службу в каталоге
/etc/systemd/system/rtc.service
:[Unit] Description=Initialize I2C RTC and synchronize system clock After=udev.service [Service] Type=oneshot ExecStart=/usr/bin/hwclock --hctosys --utc [Install] WantedBy=multi-user.target
Активируйте и запустите службу:
systemctl enable rtc.service systemctl start rtc.service
Заключение
Этот подход, использующий правила udev и службу systemd, позволяет надежно и последовательно настраивать привязки устройства и символические ссылки при каждом запуске системы Arch Linux на вашей плате Beaglebone Black. Таким образом, вы освобождаете себя от необходимости ручной настройки при каждой перезагрузке, и ваш сценарий работы с устройствами RTC через I2C становится более устойчивым к изменениям и обновлениям системы.