Перейти к основному содержимому

6 записей с тегом "modbus"

Посмотреть все теги

Утилита modbus-slave. Эмулятор Modbus RTU датчиков

· 4 мин. чтения
dmn
maintainer

Когда разрабатываешь систему мониторинга или SCADA, часто нужно протестировать опрос датчиков — но реального оборудования под рукой нет. Или нужно показать демо заказчику без физических устройств. Или хочется отладить логику мастера не выезжая на объект.

Именно для этого мы написали modbus_slave — эмулятор Modbus RTU slave устройств на C, который работает на Linux и Windows, не требует зависимостей и умеет отдавать реальные данные из файлов.

Что умеет​

  • Эмулирует до 30 независимых Modbus RTU устройств на одном последовательном порту
  • Каждое устройство отвечает на FC03 (Read Holding Registers), 20 регистров
  • Значения регистров — случайные (для тестирования) или из файла (реальные данные)
  • Работает на Linux x86_64, aarch64 (NAPI2, RK3568, Raspberry Pi) и Windows x64
  • Поддерживает RS-485 — RTS direction control через DTS/GPIO
  • Режим демона с логами в syslog и systemd service для автозапуска
  • Защита от устаревших данных — если скрипт-источник упал, регистры возвращают нули
  • Один статический бинарь без зависимостей — скопировал и запустил

Архитектура​

Идея простая: один процесс слушает RS-485 шину и отвечает на запросы от любого из 30 адресов. Для мастера это выглядит как несколько физических устройств на линии — он не видит разницы.

Мастер (PC/ПЛК) RS-485 шина modbus_slave (NAPI2)
mbpoll -a 1 ──────────────────────────► slave ID 1 → /tmp/cpu.dat
mbpoll -a 2 ──────────────────────────► slave ID 2 → /tmp/time.dat
mbpoll -a 3 ──────────────────────────► slave ID 3 → random

Регистры читаются из обычных текстовых файлов — одно число на строку. Файлы живут в /tmp (tmpfs — RAM диск), SD карта не изнашивается.

Быстрый старт​

Установка на NAPI2 / aarch64​

# Скачать статический бинарь
wget https://github.com/lab240/modpoll-slave/raw/main/bin/modbus_slave_aarch64
chmod +x modbus_slave_aarch64

# Запустить — 3 датчика, порт ttyS7
./modbus_slave_aarch64 -p /dev/ttyS7 -b 115200 -a 3

Запуск на Windows​

modbus_slave.exe -p COM4 -b 115200 -a 3

Проверка с mbpoll​

mbpoll -m rtu -b 115200 -P none -a 1 -r 1 -c 20 /dev/ttyUSB0

Реальные данные из файлов​

Самое интересное — каждому slave можно привязать файл с реальными значениями. Формат простой: одно целое число на строку.

# Запуск: slave 1 читает данные CPU, slave 2 — время, slave 3 — рандом
./modbus_slave -p /dev/ttyS7 -b 115200 -a 3 \
-f 1:/tmp/cpu.dat \
-f 2:/tmp/time.dat

Файл обновляется внешним скриптом атомарно через mv — никакой гонки данных:

# Температура ядер CPU (°C × 100)
while true; do
for zone in /sys/class/thermal/thermal_zone*/temp; do
val=$(( $(cat $zone) / 10 ))
echo $val
done > /tmp/cpu.tmp
mv /tmp/cpu.tmp /tmp/cpu.dat
sleep 5
done

Значение 4523 в регистре означает 45.23 °C — стандартное соглашение для передачи дробных чисел в Modbus.

Защита от падения скриптов​

Если скрипт обновления данных упал — файл перестаёт обновляться, но данные в нём остаются старые. Мастер продолжал бы читать устаревшие значения.

Параметр -t задаёт максимальный возраст файла:

./modbus_slave -p /dev/ttyS7 -b 115200 -f 1:/tmp/cpu.dat -t 10

Если файл не обновлялся более 10 секунд — все регистры возвращают 0. Это сразу видно мастеру и SCADA системе. В лог пишется предупреждение (не чаще раза в минуту чтобы не спамить):

file /tmp/cpu.dat is stale (45s > 10s), returning zeros

По умолчанию t=10. Отключить: -t 0.

Режим демона и systemd​

# Запуск как демон
./modbus_slave -d -p /dev/ttyS7 -b 115200 -a 3 -f 1:/tmp/cpu.dat

# Статус
./modbus_slave -s

# Остановка
./modbus_slave -k

# Логи
journalctl -t modbus_slave -f

Для автозапуска при загрузке — systemd service:

sudo cp modbus_slave /usr/local/bin/
sudo cp service/modbus_slave.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now modbus_slave

Статистика запросов пишется в лог каждые 60 секунд:

stats: slaves=3 total_ok=12480 total_err=0

Windows​

На Windows всё то же самое, только порт называется COM4 вместо /dev/ttyS7, файлы в C:\temp\ вместо /tmp/, и -bg вместо -d:

modbus_slave.exe -bg -p COM4 -b 115200 -a 3 ^
-f 1:C:\temp\cpu.dat ^
-f 2:C:\temp\time.dat

Логи пишутся в C:\temp\modbus_slave.log.

Сборка из исходников​

Код разделён на три файла:

ФайлСодержимое
modbus_core.hВся логика Modbus: CRC16, FC03, файлы, статистика
modbus_slave.cLinux: termios, fork, syslog, /proc
modbus_slave_win.cWindows: Win32 API, CreateFile, DCB
# Linux x86_64
gcc -O2 -Wall -o modbus_slave src/modbus_slave.c

# Linux aarch64 статический
aarch64-linux-gnu-gcc -O2 -Wall -static -o modbus_slave_aarch64 src/modbus_slave.c

# Windows .exe с Linux
x86_64-w64-mingw32-gcc -O2 -Wall -o modbus_slave.exe src/modbus_slave_win.c

Итог​

modbus_slave решает конкретную задачу — дать возможность разрабатывать и тестировать Modbus мастер без реального железа, или превратить одноплатный компьютер в многоканальный шлюз данных в Modbus.

Код открытый, собирается одной командой, работает на том же NAPI2 где и всё остальное.

Репозиторий: github.com/lab240/modpoll-slave

Утилита mbscan - быстрый поиск Modbus устройств на линии

· 5 мин. чтения
dmn
maintainer

247 адресов за 2.5 секунды, ноль зависимостей, один .c файл. Рассказываем, зачем мы написали свой сканер Modbus-шины и как он работает.


Проблема: «а что вообще висит на шине?»​

Кто работал с Modbus RTU, знает ситуацию: подключаешь шлюз к RS-485 шине, а там десяток устройств с неизвестными адресами. Или один датчик, но кто-то поставил ему адрес 117 вместо документированного 1. Или устройство просто не отвечает — и непонятно, проблема в адресе, скорости, чётности или в самом устройстве.

Стандартный подход - mbpoll или любой Modbus-клиент, которым вручную перебираешь адреса. Это работает, но медленно и неудобно: 247 возможных адресов, на каждый нужно отправить запрос, подождать таймаут, проверить ответ.

Мы решили автоматизировать это одной утилитой.

Репозиторий: github.com/lab240/mbscan


Что такое mbscan​

mbscan - консольная утилита для сканирования Modbus RTU шины. Открывает последовательный порт, последовательно опрашивает диапазон адресов функцией FC03 (Read Holding Registers) и выводит найденные устройства с содержимым регистров.

Один файл на C, никаких внешних библиотек. Встроенная реализация CRC16, POSIX-совместимый код. Работает на Linux x86_64, aarch64, OpenWrt, Raspberry Pi — везде, где есть терминальный API POSIX.

Быстрый старт​

# Сканируем всё на /dev/ttyUSB0 (по умолчанию: 115200-8N1, таймаут 100мс)
mbscan -p /dev/ttyUSB0

# Быстрый скан с таймаутом 10мс
mbscan -p /dev/ttyUSB0 -o 10

# Конкретный диапазон, читаем 4 регистра
mbscan -p /dev/ttyUSB0 -f 1 -t 30 -c 4

# 9600 бод, чётность 8E1
mbscan -p /dev/ttyS1 -b 9600 -d 8E1

Вывод выглядит так:

mbscan: scanning /dev/ttyUSB0 115200-8N1, addresses 1-247, timeout 100ms
mbscan: reading 4 register(s) starting at 0

Found slave 125: [0]=125 [1]=1 [2]=830 [3]=794

mbscan: done. Found 1 device(s).

Нашёл устройство на адресе 125, прочитал 4 регистра — готово.


Параметры​

mbscan -p PORT [опции]

-p PORT Последовательный порт (обязательный)
-b BAUD Скорость (по умолчанию: 115200)
-d PARAMS Формат данных: 8N1, 8E1, 8O1, 7E1 и т.д. (по умолчанию: 8N1)
-f FROM Начальный адрес (по умолчанию: 1)
-t TO Конечный адрес (по умолчанию: 247)
-o MS Таймаут на адрес в мс (по умолчанию: 100)
-r REG Начальный регистр, 0-based (по умолчанию: 0)
-c COUNT Количество регистров для чтения (по умолчанию: 1)
-v Подробный вывод
-h Справка

Как это работает внутри​

Алгоритм прямолинейный, но дьявол в деталях:

  1. Открывает последовательный порт, настраивает скорость, чётность, количество стоп-битов через termios.

  2. Для каждого адреса в диапазоне:

    • Сбрасывает буфер порта от предыдущих данных
    • Формирует 8-байтовый запрос Modbus RTU FC03 с CRC16
    • Отправляет запрос и ждёт ответ с настроенным таймаутом
    • Валидирует ответ: проверяет CRC, адрес slave, код функции
    • Если всё сходится — выводит найденное устройство с содержимым регистров
  3. Между запросами выдерживает межкадровую паузу Modbus (3.5 символьных времени) — это требование протокола, без него устройства могут путать конец одного кадра и начало другого.

CRC16 реализован встроенный - нет зависимости от libmodbus или других библиотек. Весь код в одном файле mbscan.c.


Скорость сканирования​

Скорость определяется таймаутом на адрес. Если устройство не отвечает — ждём полный таймаут. Если отвечает — переходим к следующему сразу после получения ответа.

ТаймаутПолный скан (1–247)Когда использовать
10 мс~2.5 секКороткие кабели, лабораторный стенд
50 мс~12 секБольшинство установок
100 мс~25 секПо умолчанию, надёжно
200 мс~50 секДлинные линии RS-485

На практике 10 мс хватает для стенда с коротким кабелем. Для промышленных линий с десятками метров RS-485 лучше ставить 50-100 мс — на длинных линиях задержки растут из-за переотражений и ёмкости кабеля.


Сборка​

Нативная компиляция​

cd src
gcc -O2 -Wall -o mbscan mbscan.c

Статическая сборка (один бинарник без зависимостей):

gcc -O2 -Wall -static -o mbscan mbscan.c

Пакет для OpenWrt​

Каталог mbscan кладётся в дерево пакетов OpenWrt:

cp -r mbscan /path/to/openwrt/package/
cd /path/to/openwrt
echo "CONFIG_PACKAGE_mbscan=y" >> .config
make package/mbscan/compile -j$(nproc)

Результат — .ipk (или .apk) пакет в bin/packages/*/base/.

Кросс-компиляция для aarch64​

Если есть тулчейн OpenWrt:

/path/to/openwrt/staging_dir/toolchain-aarch64_generic_gcc-*/bin/aarch64-openwrt-linux-gcc \
-O2 -Wall -static -o mbscan-linux-aarch64 src/mbscan.c

Готовые бинарники для x86_64 и aarch64 доступны на странице Releases.


Интеграция с luci-app-mbpoll​

mbscan - не просто самостоятельная утилита. Он используется как бэкенд для вкладки Scan Bus в веб-интерфейсе luci-app-mbpoll - нашем LuCI-приложении для опроса Modbus-устройств.

Схема простая: пользователь задаёт параметры порта и диапазон адресов в браузере, LuCI вызывает mbscan на устройстве, парсит вывод и отображает найденные устройства в таблице. Не нужно заходить по SSH, не нужно помнить синтаксис - всё через веб-интерфейс.

Репозиторий luci-app-mbpoll: github.com/lab240/luci-app-mbpoll


Где используется​

Основная платформа - промышленные IoT-шлюзы NapiLab Napi на базе Rockchip RK3308 под управлением OpenWrt. Napi имеет встроенный RS-485 на /dev/ttyS1 и два USB-порта для дополнительных адаптеров — типичная конфигурация для Modbus-шлюза.

Но mbscan работает на любом Linux с последовательным портом: обычный x86_64 с USB-RS485 адаптером (CH341, CP2102, FTDI), Raspberry Pi, любая embedded-плата.


Лицензия​

GPL-2.0 - как и OpenWrt, как и остальные наши инструменты.

Анализ сигналов Modbus RS485 на анализаторе

· 1 мин. чтения
dmn
maintainer

Анализ сигналов Modbus RS485​

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

Оборудование​

  • Хост: Napi-C с программным RTS
  • Датчик: учебный Modbus Napi-датчик

Конфигурация каналов​

  • Канал 1: RTS хоста
  • Канал 2: RX хоста
  • Канал 3: TX хоста
  • Канал 4: RX датчика
  • Канал 5: TX датчика

Последовательность обмена​

  1. Хост поднимает сигнал RTS (передача)
  2. Посылает запрос по линии TX
  3. Датчик принимает запрос через RX
  4. Датчик передает ответ через TX
  5. Хост принимает ответ через RX

#rs485 #rts

Конфигурация UART на модуле CM4 в Токосборщике

· 1 мин. чтения
dmn
maintainer

В Токосборщике на модуле CM4 UART-ы расположились следующим образом:

✔️UART3 - внешний датчик Modbus ✔️UART9 - модуль расширений (Zigbee) ✔️UART7 - встроенный датчик тока

Для корректной работе Debian, необходимо подключить оверлеи с uart7,9 в файле /boot/orangepiEnv.txt

root@orangepicm4:~# cat /boot/orangepiEnv.txt
verbosity=1
bootlogo=false
extraargs=cma=128M
overlay_prefix=rk356x
overlays=uart7-m2 uart9-m2
rootdev=UUID=a0f8ca89-7eb7-4a1e-947a-2341637b4782
rootfstype=ext4
console=serial

#fcucm4 #orangecm4 #fcu

Python-сниффер для анализа Modbus RTU трафика

· 3 мин. чтения
dmn
maintainer

Написал "на коленке" полезный сниффер modbus

modbus_sniffer_raw_pretty.py

#!/usr/bin/env python3
"""
Raw Modbus RTU Sniffer — listens to a serial port and prints decoded Modbus RTU frames.
Now includes decoding of address/count/value for popular function codes.
"""

import serial
import argparse
import time
import logging
import struct

logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.INFO)

def calculate_crc(data: bytes):
crc = 0xFFFF
for pos in data:
crc ^= pos
for _ in range(8):
lsb = crc & 0x0001
crc >>= 1
if lsb:
crc ^= 0xA001
return crc.to_bytes(2, 'little')

def validate_crc(frame: bytes):
if len(frame) < 4:
return False
data, received_crc = frame[:-2], frame[-2:]
return calculate_crc(data) == received_crc

def decode_payload(fc, payload):
if fc in [1, 2, 3, 4]: # Read coils, discrete inputs, HR, IR
if len(payload) >= 4:
address, count = struct.unpack(">HH", payload[:4])
return f"Read | Addr={address} | Count={count}"
elif fc in [5, 6]: # Write single coil/register
if len(payload) >= 4:
address, value = struct.unpack(">HH", payload[:4])
return f"Write Single | Addr={address} | Value={value}"
elif fc in [15, 16]: # Write multiple coils/registers
if len(payload) >= 5:
address, count, byte_count = struct.unpack(">HHB", payload[:5])
return f"Write Multiple | Addr={address} | Count={count} | Bytes={byte_count}"
return f"Payload: {payload.hex()}"

def print_frame_info(frame: bytes):
if not validate_crc(frame):
log.warning(f"❌ Invalid CRC: {frame.hex()}")
return
unit_id = frame[0]
function_code = frame[1]
payload = frame[2:-2]
desc = decode_payload(function_code, payload)
log.info(f"📥 Unit={unit_id} | FC={function_code} — {desc}")

def read_frames(ser):
buffer = bytearray()
last_byte_time = time.time()
inter_char_timeout = 0.01
frame_timeout = 0.1

while True:
if ser.in_waiting:
byte = ser.read(1)
now = time.time()
if now - last_byte_time > frame_timeout and buffer:
print_frame_info(bytes(buffer))
buffer.clear()
buffer.append(byte[0])
last_byte_time = now
elif buffer and time.time() - last_byte_time > frame_timeout:
print_frame_info(bytes(buffer))
buffer.clear()
else:
time.sleep(0.005)

def main():
parser = argparse.ArgumentParser(description="Raw Modbus RTU Sniffer with decoding")
parser.add_argument('--port', required=True, help='Serial port (e.g. /dev/ttyUSB0)')
parser.add_argument('--baudrate', type=int, default=9600)
parser.add_argument('--parity', choices=['N', 'E', 'O'], default='N')
parser.add_argument('--stopbits', type=int, choices=[1, 2], default=1)
args = parser.parse_args()

try:
ser = serial.Serial(
port=args.port,
baudrate=args.baudrate,
parity={'N': serial.PARITY_NONE, 'E': serial.PARITY_EVEN, 'O': serial.PARITY_ODD}[args.parity],
stopbits=args.stopbits,
bytesize=8,
timeout=0
)
log.info(f"🔍 Listening on {args.port} at {args.baudrate} bps...")
read_frames(ser)
except Exception as e:
log.error(f"Failed to open serial port: {e}")

if __name__ == "__main__":
main()

использует библиотеку pyserial

pip install pyserial

Пример:

(venv) orangepi@cm4-right:~$ python3 modbus_sniffer_raw_pretty.py --baudrate 9600 --port /dev/ttyS9
INFO:root:🔍 Listening on /dev/ttyS9 at 9600 bps...
INFO:root:📥 Unit=1 | FC=3 — Read | Addr=0 | Count=1
INFO:root:📥 Unit=1 | FC=3 — Read | Addr=10 | Count=2

Скрипт читает и распознает пакеты modbus, запросы modbus транслирует на экран.

#modbus #modbussniffer

Установка и тюнинг чистого Armbian

· 7 мин. чтения
dmn
maintainer

🔥 🔥 🔥 Эта статья устарела, у нас есть готовые образы Armbian в разделе "Скачать" 🔥 🔥 🔥

Тюнинг Armbian для работы с Napi и Сборщик-компакт

подсказка

Эта инструкция для продвинутых пользователи Linux, Вы можете скачать готовый образ, где уже проведены все операции, по ссылке: https://download.napilinux.ru/linuximg/napic/armbian-rockpi-s-snaphots/

Ставим чистый ARMbian для Rock Pi S​

Скачайте образ по ссылке​

https://download.napilinux.ru/linuximg/napic/armbian-napic-distrib/

или с сайта Armbian:

https://redirect.armbian.com/rockpi-s/Bookworm_current

Имя файла будет похоже на следующее - Armbian_23.5.2_Rockpi-s_bookworm_current_6.1.32.img.xz

Распаковать образ и записать образ на SD-карту

или

Загрузить NAPI c SD карты в NapiLinux, вставить флешку с распакованным файлом образа и записать имидж в NAND по инструкции

Загрузить ARMbian. Войти по SSH (Логин\Пароль root\1234)

При первой загрузке ARMbian задаст вопросы про язык, локаль, часовой пояс, дополнительного пользователя - надо пройти все эти вопросы (в подготовленном имидже мы уже все сделали).

Проводим тюнинг Armbian​

Проведите обновление системы​

apt update
apt upgrade

Теперь вы можете ставить любые доступные пакеты в Armbian (Debian) программой apt install packet

Поставить рекомендуемые нами пакеты​

telnet
mbpoll
snmpd
snmp
snmp-mibs-downloader
vim
cmake
pkg-config
plocate
gh
mosquitto
mosquitto-clients
python3-pip
python3-dev

Поместите данный список в файл packages.txt (nano packages.txt), выполните команду:

xargs apt-get -y install < packages.txt

Все пакеты должны установиться автоматически !

Теперь у вас есть утилита mbpoll для работы с modbus, pip3 - система установки пакетов для python3, средства для работы с git, средства для компилирования программ (понадобиться ниже).

Перегрузка при панике ядра​

Заставим систему перегружаться при панике ядра (маловероятно, но все-таки)

Открыть файл /etc/sysctl.conf

Добавить или раскомментировать строчку

kernel.panic = 5

Сохранить файл

Добавление аппаратных интерфейсов​

В Armbian (и других современных Linux) включение аппаратных и нестандартных интерфейсов (uart, i2c, spi) работает через систему подключаемых оверлеев (файлы в формате dtbo - device tree binary). Это бинарные файлы, которые компилируются из исходных текстовых файлов dts (data tree source).

В Armbian есть утилита, которая компилирует и добавляет оверлей из пользовательского файла dts.

Общий алгоритм такой. Нужно скачать или другим образом (через копи\паст) сформировать файл dts (название лучше делать по смыслу файла, например rk3308-spi2.dts) и далее выполнить команду

armbian-add-overlay <файл.dts>

Обязательно перегрузиться.

После этого должно заработать устройство, которое Вы подключили, если оно не конфликтует с другими устройствами. Конфликты зависят от включенных устройствах по умолчанию, от аппаратной конфигурации устройства.

подсказка

Например, в NAPI не может работать одновременно UART1,2 и SPI2 а также UART3 и SPI1

Файлы dts для rk3308 (всех NAPI) доступны по ссылке: https://gitlab.nnz-ipc.net/pub/napilinux/kernel/-/tree/linux6.6/arch/arm64/boot/dts/rockchip/overlay

Список файлов

rk3308-console-on-uart0.dts
rk3308-console-on-uart1.dts
rk3308-console-on-uart2.dts
rk3308-i2c0.dts
rk3308-i2c1-ds1307.dts
rk3308-i2c1-ds3231.dts
rk3308-i2c1.dts
rk3308-i2c2.dts
rk3308-i2c3-m0.dts
rk3308-i2c3-m1.dts
rk3308-i2c3.dts
rk3308-pwm1.dts
rk3308-pwm2.dts
rk3308-pwm3.dts
rk3308-spi-spidev.dts
rk3308-spi1-spidev.dts
rk3308-spi2-spidev.dts
rk3308-uart0.dts
rk3308-uart1.dts
rk3308-uart2.dts
rk3308-uart3.dts
rk3308-usb-pcie-modem.dts
rk3308-usb20-host.dts
rk3308-w1-gpio.dts

rockpis-i2s-out.dts
rockpis-spdif-out.dts
rockpis-v11-spi2-waveshare35b-v2.dts

rockpis-v11-spi2-waveshare35c.dts
rockpis-v12-spi2-waveshare35b-v2.dts
rockpis-v12-spi2-waveshare35c.dts
i2c1-hym8563.dts

Из этого списка примерно понятно какие устройства могут быть добавлены.

подсказка

В Armbian устройства uart0 (консоль), uart1, uart2 добавлены по умолчанию.

Добавим поддержку UART3​

подсказка

В "Сборщик-компакт" порт RS485 работает через UART3. Поэтому его надо добавить в ArmBian.

Создадим файл rk3308-uart3.dts (скопируем его содержания из файла по ссылке или ниже)

/dts-v1/;
/plugin/;

/ {
compatible = "rockchip,rk3308";

fragment@0 {
target = <&i2c3>;
__overlay__ {
status = "disabled";
};
};

fragment@1 {
target = <&spi1>;
__overlay__ {
status = "disabled";
};
};

fragment@2 {
target = <&uart3>;
__overlay__ {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&uart3_xfer>;
};
};
};

Сохраним файл и выполним команду

armbian-add-overlay rk3308-uart3.dts

Эта команда автоматически скомпилирует и добавит overlay для UART3 (/dev/ttyS3 в системе).

Проверить что все корректно скомпилировалось, можно проверив каталог /boot/overlay-user, там должен быть соответствующий файл rk3308-uart3.dtbo

root@napi-armbian:~# ls /boot/overlay-user/
rk3308-i2c3-m0.dtbo rk3308-spi2-spidev.dtbo rk3308-uart1.dtbo rk3308-uart3.dtbo
root@napi-armbian:~#

В файле /boot/armbianEnv.txt объявление устройства должно появиться в разделе user-overlays=

root@napi-armbian:~# cat /boot/armbianEnv.txt
verbosity=1
extraargs=swiotlb=1024
overlay_prefix=rk3308
fdtfile=rockchip/rk3308-rock-pi-s.dtb
rootdev=UUID=5ef25166-64ed-4920-8994-f233ab2771c7
rootfstype=ext4
console=serial
user_overlays=rk3308-uart3 rk3308-i2c3-m0 rk3308-spi2-spidev
ethaddr=02:AE:83:87:2D:A0
usbstoragequirks=0x2537:0x1066:u,0x2537:0x1068:u

Не забудьте перегрузиться !

Теперь должен корректно работать порт UART3, устройство - /dev/ttyS3. Чтобы проверить порт, нужно подсоединить к GPIO UART3 какое либо устройство.

Добавим поддержку SPI2​

Особенности оверлея spi2 под ARMbian

Для того, чтобы в модуле NAPI работал SPI2, необходимо отключить uart1 и uart2. Так как в ARMbian они включены в основном файле дерева устройств, то в оверлее spi2 необходимо отключить явным образом uart1, uart2. Правильный файл dts для SPI2 приводим ниже.

  1. Сделайте файл rk3308-spi2-spidev.dts такого содержания:

/dts-v1/;
/plugin/;

/ {
compatible = "rockchip,rk3308";

fragment@0 {
target = <&spi2>;
__overlay__ {
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
spidev@0 {
compatible = "rohm,dh2228fv";
status = "okay";
reg = <0>;
spi-max-frequency = <10000000>;
};
};
};

fragment@1 {
target = <&uart1>;
__overlay__ {
status = "disabled";
};
};
fragment@2 {
target = <&uart2>;
__overlay__ {
status = "disabled";
};
};

};

  1. Выполните команду
armbian-add-overlay rk3308-spi2-spidev.dts

Эта команда автоматически скомпилирует и добавит overlay для SPI2.

  1. Перезагрузитесь. Должно появиться устройство /dev/spidev2.0
Нюансы NAPI

Следует обратить внимание на нюансы:

⚠️ Обратите внимание, что некоторые интерфейсы нельзя использовать одновременно. При использовании шины SPI2, необходимо отключить UART2 и UART1.

⚠️ Шина SPI1 в настоящий момент не работает, при необходимости подключения устройств по SPI, используйте SPI2.

подсказка

Установка системного и прикладного ПО​

Установим утилиту modpoll​

⚠️ Несмотря на то, что в системе присутствует практически такая же утилита mbpoll аргументы у них немного различаются. Мы можем давать примеры на основе утилиты modpoll, поэтому рекомендуем ее тоже установить.

Скачать архив командой

wget https://www.modbusdriver.com/downloads/modpoll.tgz

Распаковать полученный архив

https://www.modbusdriver.com/downloads/modpoll.tgz

Скопировать файл

cp modpoll/arm-linux-gnueabihf/modpoll /usr/bin/

Убедиться, что утилита доступна и запускается

modpoll -h

Скомпилируем mbusd​

Mbusd - открытый шлюз Modbus RTU - Modbus TCP

Стянем исходный код с github

git clone https://github.com/3cky/mbusd.git mbusd.git

Проведем компилирование

cd mbusd.git
mkdir -p build && cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr ..
make
sudo make install

Проверим, что пакет установился через команду mbusd

Настроим snmpd​

Устройство начнет отдавать стандартную информацию о сбе по протоколу SNMP (в дальнейшем это можно использовать, добавив устройства в Zabbix).

Редактируем файл /etc/snmp/snmpd.conf

Находим строку

agentaddress 127.0.0.1,[::1]

Меняем на строку

agentaddress 0.0.0.0,[::1]

Или выполняем команду

sed -i "s/agentaddress 127.0.0.1,[::1]/agentaddress 0.0.0.0,[::1]/g" /etc/snmp/snmpd.conf

Перезапускаем сервис snmpd

service snmpd restart

Убедиться, что он работает можно командой

service snmpd status

Добавим работу с GPIO через gpiod​

К сожалению, по умолчанию в Armbian довольно старая версия gpiod, поэтому мы написали статью, как установить свежую версию gpiod и работать с командами пакета.

Как работать с gpio через систему sysfs можно прочитать по ссылке: https://developer.technexion.com/docs/using-gpio-from-a-linux-shell#using-legacy-sysfsbased-gpio