Skip to main content

Диагностика занятости GPIO пинов в Linux

· 3 min read
dmn
maintainer

Диагностика занятости GPIO

В Linux можно посмотреть чем заняты все GPIO:

cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins

Пример вывода на NAPI-C

root@rockpi-s:~# cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins
Pinmux settings per pin
Format: pin (name): mux_owner gpio_owner hog?
pin 0 (gpio0-0): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 1 (gpio0-1): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 2 (gpio0-2): sdio-pwrseq gpio0:2 function sdio-pwrseq group wifi-enable-h
pin 3 (gpio0-3): ff480000.mmc (GPIO UNCLAIMED) function sdmmc group sdmmc-det
pin 4 (gpio0-4): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 5 (gpio0-5): leds gpio0:5 function leds group heartbeat-led
pin 6 (gpio0-6): leds gpio0:6 function leds group green-led
pin 7 (gpio0-7): stmmac-0:01 gpio0:7 function gmac group mac-rst
pin 8 (gpio0-8): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 9 (gpio0-9): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 10 (gpio0-10): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 11 (gpio0-11): ff050000.i2c (GPIO UNCLAIMED) function i2c1 group i2c1-xfer
pin 12 (gpio0-12): ff050000.i2c (GPIO UNCLAIMED) function i2c1 group i2c1-xfer
pin 13 (gpio0-13): ff180000.pwm (GPIO UNCLAIMED) function pwm0 group pwm0-pin-pull-down
pin 14 (gpio0-14): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 15 (gpio0-15): (MUX UNCLAIMED) (GPIO UNCLAIMED)

Пример занятого GPIO

Например, GPIO0-A5 занят и мы не можем его использовать, например как DE для UART без лишних "процедур" по его освобождению:

root@rockpi-s:~/S4-GPIO2_A5# cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins | grep gpio0-5
pin 5 (gpio0-5): leds gpio0:5 function leds group heartbeat-led
root@rockpi-s:~/S4-GPIO2_A5#

Пример свободного GPIO

А вот GPIO2-B4 выглядит как свободный:

root@rockpi-s:~/S4-GPIO2_A5# cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins | grep gpio2-12
pin 76 (gpio2-12): (MUX UNCLAIMED) (GPIO UNCLAIMED)

И мы можем его программно "дергать":

root@rockpi-s:~/S4-GPIO2_A5# gpioset gpiochip2 12=1
root@rockpi-s:~/S4-GPIO2_A5# gpioset gpiochip2 12=0
root@rockpi-s:~/S4-GPIO2_A5#

Использование GPIO в DTS

А теперь "захватим" пин GPIO2_A5 для DE в UART1 таким DTS:

 /dts-v1/;
/plugin/;

/ {
compatible = "rockchip,rk3308";

fragment@0 {
target = <&uart1>;
__overlay__ {
status = "okay";

pinctrl-names = "default";
pinctrl-0 = <&uart1_xfer>;

linux,rs485-enabled-at-boot-time;
rs485-rts-active-high;
rs485-rts-delay = <0 0>;
rts-gpios = <&gpio2 5 0>;
};
};
};

Проверка захвата GPIO

Посмотрим как выглядит пин:

root@rockpi-s:~/S4-GPIO2_A5# cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins | grep gpio2-5
pin 69 (gpio2-5): (MUX UNCLAIMED) gpio2:69
root@rockpi-s:~/S4-GPIO2_A5#

Тут не слишком понятно захватился он драйвером RS485 или нет. Но что важно, Linux не даст больше им "мигать", если он занят драйвером ядра:

root@rockpi-s:~/S4-GPIO2_A5# gpioset gpiochip2 5=0
gpioset: error setting the GPIO line values: Device or resource busy
root@rockpi-s:~/S4-GPIO2_A5# gpioset gpiochip2 5=1
gpioset: error setting the GPIO line values: Device or resource busy
root@rockpi-s:~/S4-GPIO2_A5#

Тестирование UART1

Осталось убедиться, что мы получаем данные через UART1:

root@rockpi-s:~/S4-GPIO2_A5# mbpoll -m rtu -P none -b 115200 -a 125 -r 1 -c 4 -t4   /dev/ttyS1
mbpoll 1.0-0 - FieldTalk(tm) Modbus(R) Master Simulator
Copyright © 2015-2019 Pascal JEAN, https://github.com/epsilonrt/mbpoll
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions; type 'mbpoll -w' for details.

Protocol configuration: Modbus RTU
Slave configuration...: address = [125]
start reference = 1, count = 4
Communication.........: /dev/ttyS1, 115200-8N1
t/o 1.00 s, poll rate 1000 ms
Data type.............: 16-bit register, output (holding) register table

-- Polling slave 125... Ctrl-C to stop)
[1]: 125
[2]: 1
[3]: 851
[4]: 772

Overlay для RS485 на UART1 с GPIO управлением направления

· One min read
dmn
maintainer

Оверлей для RS485 на UART1

Оверлей для RS485 на UART1 (Napi-C) c контролем направления через GPIO (DE=GPIO2_B4)

Конфигурация DTS

root@rockpi-s:~/S3# cat uart1-de.dts
/dts-v1/;
/plugin/;

/ {
compatible = "rockchip,rk3308";

fragment@0 {
target = <&uart1>;
__overlay__ {
status = "okay";

pinctrl-names = "default";
pinctrl-0 = <&uart1_xfer>;

linux,rs485-enabled-at-boot-time;
rs485-rts-active-high;
rs485-rts-delay = <0 0>;
rts-gpios = <&gpio2 12 0>;
};
};
};

#rs485 #napic

Получение текущего DTS из загруженной системы

· One min read
dmn
maintainer

Получить текущий dts из dtb, с которой загрузилась система:

dtc -I fs -O dts /sys/firmware/devicetree/base > /tmp/running.dts

Это ключевой файл, отображающий как система "понимает" всю перефирию и интерфейсы.

Внимательно изучайте файл running.dts через текстовый редактор - он ключ к пониманию как система интерпретирует интерфейсы.

И, кстати, этот dts можно "скормить" в ChatGPT и задавать вопросы или сформировать просьбу сделать overlay.

#kernel #dts

Программное включение аппаратного reset в eMMC

· One min read
dmn
maintainer

Продолжаем исследовать удивительный мир EMMC/SD

Столкнулись с удивительной ситуацией на Napi Slot - при нажатии кнопки MaskRom. Эта кнопка переводит процессор в режим прошивки (на самом деле кнопка подтягивает MMC_RESET к GND и отключает EMMC, чтобы процессор не нашел с чего грузить систему и вошёл в режим прошивки).

Проблема

Так вот процессор никак не реагировал!

Выяснилось, что в некоторых EMMC аппаратный reset включается ПРОГРАММНО!

Рецепт команд Linux

Считать текущий статус

sudo mmc extcsd read /dev/mmcblk0 | grep -i RST_N_FUNCTION

Включить аппаратный reset у eMMC

Операция необратимая:

sudo mmc hwreset enable /dev/mmcblk0

Проверить результат

sudo mmc extcsd read /dev/mmcblk0 | grep -i RST_N_FUNCTION

Должно поменяться на RST_N_FUNCTION: 0x01

#emmc #hard #napi

Компиляция ядра NapiLinux - быстрый метод

· 2 min read
dmn
maintainer

Как скомпилировать только ядро NapiLinux

Это "грязный" быстрый метод, который позволяет не компилировать всю систему, а быстро включить какие-то опции ядра и проверить новое ядро в системе.

Правильный способ компиляции NapiLinux — через пакет Yocto.

1. Сделать клон ядра с нужной ветки (branch)

Бранч — это версия репозитория ядра. Для разных платформ она разная, и нужно выбрать ту, которая вас интересует:

  • rk-6.1
  • orange-pi-6.6
  • rk35xx

и т. п. (выбирайте на сайте GitLab)

git clone https://gitlab.nnz-ipc.net/pub/napilinux/kernel.git --branch=rk-6.1 --depth=1
cd kernel/

2. Настроить переменные для архитектуры (ARM64)

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

3. Подготовить конфиг

  • Конфиги лежат в папке /arch/arm64/configs
  • В каждой ветке нужно выбрать свой конфиг:

Для Napi:

make napi_defconfig

Для CM4:

make opi_cm4_defconfig

4. Настройка конфигурации

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

5. Запускаем компиляцию ядра

make -j10

6. Результаты сборки

  • Имидж ядраarch/arm64/boot/Image
  • Главная DTB (дерево устройств) — arch/arm64/boot/<файл>.dtb
  • Оверлеиarch/arm64/boot/dts/rockchip/

7. Замена ядра в системе

Теперь можно заменить файлы Image и .dtb в /boot, затем перезагрузить систему.

8. Важно про overlay root!

NapiLinux использует root (/) как виртуальную партицию overlay, поэтому просто переписать ядро и другие файлы из системы не получится (на деле вы запишете их в overlay, и u-boot их не увидит).

Что делать?

  • Если работаете на SD-карте — выньте SD, примонтируйте обе физические партиции и запишите новые файлы в их /boot

  • Если работаете с NAND/eMMC — загрузитесь с SD, примонтируйте обе партиции и запишите туда файлы вручную

Просмотр структуры партиций

Посмотреть структуру партиций можно командами:

lsblk
lsblk -f

#napilinux #napikernel

Просмотр опций компиляции ядра Linux

· One min read
dmn
maintainer

Как посмотреть с какими опциями скомпилировано ядро Linux ?

zcat /proc/config.gz

Так же можно поставить фильтр - например, посмотрим все что касается последовательных портов

zcat /proc/config.gz | grep -E 'CONFIG_SERIAL_8250_NR_UARTS|CONFIG_SERIAL_8250|CONFIG_SERIAL_'

#linuxkernel #kernel #napikernel #uart

Перенос blue-led на GPIO2B4 в Armbian

· One min read
dmn
maintainer

Перевод blue-led на GPIO2B4

Перевод blue-led на GPIO2B4 (Аrmbian). (В предыдущем примере GPIO3B3 попало на SPI1-CLK)

Файл конфигурации


root@rockpi-s:~# cat blue-led-gpio2b4-1.dts

/dts-v1/;
/plugin/;

/ {
fragment@0 {
/* у вас узел именно под /leds */
target-path = "/leds/blue-led";
__overlay__ {
gpios = <&gpio2 12 0>; /* GPIO2_B4, ACTIVE_HIGH */
linux,default-trigger = "heartbeat";
default-state = "on";
status = "okay";
};
};
};

#napi #dts

Восстановление повреждённых series в InfluxDB

· 2 min read
dmn
maintainer

Как "починить" сломанные series в InfluxDB

Неожиданно при отладке датчиков influxdb перестал запускаться с такой ошибкой.

Ошибка запуска

root@napi-playfulokapi:~# /usr/lib/influxdb/scripts/influxd-systemd-start.sh
Command "print-config" is deprecated, use the influx-cli command server-config to display the configuration values from the running server
2025-09-16T08:54:29.621708Z info Welcome to InfluxDB {"log_id": "0z0RZky0000", "version": "v2.7.1", "commit": "407fa622e9", "build_date": "2023-04-28T13:24:42Z", "log_level": "info"}
2025-09-16T08:54:29.677535Z info Resources opened {"log_id": "0z0RZky0000", "service": "bolt", "path": "/root/.influxdbv2/influxd.bolt"}
2025-09-16T08:54:29.680849Z info Resources opened {"log_id": "0z0RZky0000", "service": "sqlite", "path": "/root/.influxdbv2/influxd.sqlite"}
2025-09-16T08:54:29.754889Z info Checking InfluxDB metadata for prior version. {"log_id": "0z0RZky0000", "bolt_path": "/root/.influxdbv2/influxd.bolt"}
2025-09-16T08:54:29.756722Z info Using data dir {"log_id": "0z0RZky0000", "service": "storage-engine", "service": "store", "path": "/root/.influxdbv2/engine/data"}
2025-09-16T08:54:29.773043Z info Compaction settings {"log_id": "0z0RZky0000", "service": "storage-engine", "service": "store", "max_concurrent_compactions": 2, "throughput_bytes_per_second": 50331648, "throughput_bytes_per_second_burst": 50331648}
2025-09-16T08:54:29.774155Z info Open store (start) {"log_id": "0z0RZky0000", "service": "storage-engine", "service": "store", "op_name": "tsdb_open", "op_event": "start"}
2025-09-16T08:54:29.780689Z error Unable to open series file {"log_id": "0z0RZky0000", "service": "storage-engine", "path": "/root/.influxdbv2/engine/data/50d1dfc5f00c762d/_series", "partition": 0, "error": "invalid series segment"}
2025-09-16T08:54:29.781180Z info Open store (end) {"log_id": "0z0RZky0000", "service": "storage-engine", "service": "store", "op_name": "tsdb_open", "op_event": "end", "op_elapsed": "7.046ms"}
2025-09-16T08:54:29.781345Z error Failed to open engine {"log_id": "0z0RZky0000", "error": "invalid series segment"}
Error: invalid series segment

Как видно в логе - у нас сломался series. Очистка базы мне не помогла, поэтому чистил вручную.

Проверить series

root@napi-playfulokapi:~# influxd inspect   verify-seriesfile
2025-09-16T09:00:55.486187Z error Error opening segment {"log_id": "0z0RwJBW000", "path": "/root/.influxdbv2/engine/data/50d1dfc5f00c762d/_series", "partition": "01", "segment": "0000", "error": "invalid series segment"}
2025-09-16T09:00:55.497022Z error Error opening segment {"log_id": "0z0RwJBW000", "path": "/root/.influxdbv2/engine/data/50d1dfc5f00c762d/_series", "partition": "00", "segment": "0000", "error": "invalid series segment"}
2025-09-16T09:00:55.507980Z error Error opening segment {"log_id": "0z0RwJBW000", "path": "/root/.influxdbv2/engine/data/50d1dfc5f00c762d/_series", "partition": "02", "segment": "0000", "error": "invalid series segment"}

Видим поломанный series. Удалим его и перестроим

Удаление повреждённых series

mv /root/.influxdbv2/engine/data/50d1dfc5f00c762d/_series/ /root/.influxdbv2/engine/data/50d1dfc5f00c762d/_series.bad/

Перестроим series

influxd inspect build-tsi

Результат

После этого "шаманства" у меня influx запустился корректно.

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

#influxdb

Перенос heartbeat диода на пользовательский GPIO через overlay

· 2 min read
dmn
maintainer

Как перенести "софтовым" методом heartbit (диод активности) с встроенного GPIO на свободный  

По умолчанию диод на GPIO находится на  GPIO0A5, у нас в NAPI его нет на "гребёнке",  подтому мы его перекинем на GPIO3B3, который есть на "гребёнке" и ничем не занят.

Научимся делать user-overlay к ядру 

Добавляем оверлей в Armbian

Сделать файл blue-led-gpio3b3-2.dts и добавить его как оверлей 

armbian-add-overlay blue-led-gpio3b3-2.dts

Команда сама скомпилирует dtbo, перенесем его в нужную папку и добавит запись в файл armbianEnv.txt.

Останется только перегрузится и убедиться, что диод "прикрепился" к нашему пину (визуально он станет сразу помигивать). Как проверить на каком GPIO оказался диод - в конце поста.

Файл dts для Armbian

/dts-v1/;
/plugin/;

/ {
fragment@0 {
     /* у вас узел именно под /leds */
     target-path = "/leds/blue-led";
     __overlay__ {
         gpios = <&gpio3 11 0>;      /* GPIO3_B3, ACTIVE_HIGH */
         linux,default-trigger = "heartbeat";
         default-state = "on";
         status = "okay";

         /* убрать pinctrl у конкретного LED, чтобы не валилось на -22 */
         /delete-property/ pinctrl-names;
         /delete-property/ pinctrl-0;
     };
};
};

Добавляем оверлей NapiLinux

Необходимо скомпилировать из dts файла, dtbo файл через утилиту dtc на любом Linux-хосте.

dtc -@ -I dts -O dtb -o blue-led-gpio3b3.dtbo blue-led-gpio3b3.dts

Делаем папку 

mkdir /boot/overlay-user Получившийся файл dtbo (blue-led-gpio3b3.dtbo) закинуть  в  /boot/overlay-user

Добавить строчку в файл /boot/uEnv.txt

user_overlays=blue-led-gpio3b3 Файл dts для NapiLinux

/dts-v1/;
/plugin/;

/ {
fragment@0 {
     /* у вас узел именно под /leds */
     /* target-path = "/leds/blue-led"; */
     target-path = "/gpio-leds/blue-led";
     __overlay__ {
         gpios = <&gpio3 11 0>;      /* GPIO3_B3, ACTIVE_HIGH */
         linux,default-trigger = "heartbeat";
         default-state = "on";
         status = "okay";

     };
};
};

Проверка на каком gpio blue-led 

hexdump -v -e '1/4 "0x%08X "' -e '"\n"' /proc/device-tree/gpio-leds/blue-led/gpios
Должно выдать: <phandle gpio3, 0x0000000B, 0x00000000>

#gpio #napi #dts

Диагностика SD-NAND карт в Linux - получение регистров

· 2 min read
dmn
maintainer

Пришлось глубоко копнуть в часть SD-NAND, так как некоторые карты Zetta не инициализировались в ядрах 6.х Linux.

Полезные факты и приемы

Получаем данные регистров SD (SD-NAND) карт

Карта 1.

root@napi-rk3308b-s:~# cat /sys/bus/mmc/devices/mmc0\:1388/cid
ba2345534134474206071c06fe016945
root@napi-rk3308b-s:~# cat /sys/bus/mmc/devices/mmc0\:1388/csd
400e00325b5900001cdf7f800a4000d7
root@napi-rk3308b-s:~# cat /sys/bus/mmc/devices/mmc0\:1388/ocr
0x00300000
root@napi-rk3308b-s:~# cat /sys/bus/mmc/devices/mmc0\:1388/rca
0x1388
root@napi-rk3308b-s:~# cat /sys/bus/mmc/devices/mmc0\:1388/scr
0235000e00000000
root@napi-rk3308b-s:~#

Карта 2

root@napi-nightstarfish:~# cat /sys/bus/mmc/devices/mmc0\:1388/cid
e700115a6574746101b135ee4a719523
root@napi-nightstarfish:~# cat /sys/bus/mmc/devices/mmc0\:1388/csd
400e00325b5900001d177f800a40008d
root@napi-nightstarfish:~# cat /sys/bus/mmc/devices/mmc0\:1388/ocr
0x00300000
root@napi-nightstarfish:~# cat /sys/bus/mmc/devices/mmc0\:1388/rca
0x1388
root@napi-nightstarfish:~# cat /sys/bus/mmc/devices/mmc0\:1388/scr
0205848f33333039
root@napi-nightstarfish:~#

В uboot

=> mmc info
Device: mmc@ff500000
Manufacturer ID: 3
OEM: 5344
Name: SA04G
Bus Speed: 50000000
Mode : SD High Speed (50MHz)

Расшифровка SCR (чатгпт)

1) SCR contents (from Linux):

SCR = 02 05 84 8F 33 33 30 39

Decoded:

SCR Structure = 0 (v1.0)

SD Spec = 2.0 + Spec3 → SD 3.0 (UHS-I)

Bus widths = 1-bit and 4-bit supported

Security = CPRM supported

Byte 3 = 0x8F → according to the SD spec, bits indicate:

bit0 = CMD20 supported

bit1 = CMD23 supported

bit2 = CMD48 supported

bit3 = CMD49 supported

Расшифровка CID (чатгпт)

CID #1

ba2345534134474206071c06fe016945

MID: 0xBA

OID: 0x23 0x45 → «#E» (непечатный/нестандартный OID, трактую как hex)

PNM: SA4GB

PRV: 0.6

PSN: 119277310 (0x071C06FE)

MDT: 2022-09 (разбор по формуле: ((cid[13]&0x0F)<<8)|cid[14]) → год=2000+((mdt>>4)&0xFF), месяц=mdt&0xF)
CID #2

e700115a6574746101b135ee4a719523

MID: 0xE7 (похоже на Zetta)

OID: 0x00 0x11 → непечатный (оставляем в hex)

PNM: Zetta

PRV: 0.1

PSN: 2973101642 (0xB135EE4A)

MDT: 2025-05

Что по факту отличается

Производитель/бренд:

— #1: MID=0xBA, имя продукта SA4GB (выглядит как «4GB» линейка). — #2: MID=0xE7, имя продукта Zetta (бренд Zetta виден прямо в PNM).

Версия продукта (PRV):

— #1: 0.6 (более поздняя ревизия конкретной линейки), — #2: 0.1 (самая ранняя ревизия).

Серийный номер (PSN): разные (ожидаемо), у #2 — существенно большее значение.

Дата производства (MDT): — #1: 2022-09, — #2: 2025-05 (свежее).

OID: у обеих — непечатные/нестандартные коды (это нормально: поле OEM/Application ID не обязано быть ASCII).

Место в ядре где идёт чтение регистров карты

https://github.com/torvalds/linux/blob/07d9df80082b8d1f37e05658371b087cb6738770/drivers/mmc/core/sd.c#L1279

#sdnand #kernel #linuxkernel #sys #uboot