mmote.ru/content/posts/x96maxplus-armbian/index.md

14 KiB
Raw Blame History

title categories date draft featured_image
Linux на X96 Max Plus
linux
cpp
2023-11-17T21:09:25+03:00 false miniature.jpg

Сегодня будем экономить на Raspberry Pi и поставим armbian на X96 Max Plus.

Прошу обратить внимание!

Моя модификация - X96MaxPlus_2101. Соответственно, действия описаны для этой модификации. Для других модификаций действия могут отличаться.

Подробнее о модификациях 4pda.

Подготовка USB накопителя

Для начала скачиваем образ файловой системы для нужного процессора отсюда: ophub/amlogic-s9xxx-armbian.

Ищем в списке последний релиз для процессора s905x3. В момент написания статьи это был файл Armbian_23.11.0_amlogic_s905x3_lunar_6.1.62_server_2023.11.12.img.gz.

Ищем USB флешку. Моя была на 8 ГБ (успешно загружался и с 16). С помощью какой-либо программы записываем образ диска на неё. Я использовал Rufus. Можно использовать что угодно, что умеет записывать сырой образ диска на накопитель (Balena Etcher / dd / etc.).

В Rufus сразу выбираем .gz архив, программа сама его распаковывает в процессе записи.

rufus

После записи образа на накопителе открываем раздел fat32, в нём файл uEnv.txt. Меняем имя файла в параметре FDT на meson-sm1-x96-max-plus-2101.dtb.

LINUX=/zImage
INITRD=/uInitrd
-- FDT=/dtb/amlogic/meson-sm1-x96-max-plus-100m.dtb
++ FDT=/dtb/amlogic/meson-sm1-x96-max-plus-2101.dtb
APPEND=root=UUID=a40af2d2-999f-4b37-98b6-973b0e6faf52 rootflags=data=writeback rw rootfstype=ext4 console=ttyAML0,115200n8 console=tty0 no_console_suspend consoleblank=0 fsck.fix=yes fsck.repair=yes net.ifnames=0 max_loop=128 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1

Загрузка с USB накопителя

Вставляем USB накопитель в приставку с отключенным питанием, зажимаем Reset (находится внутри гнезда AV), подключаем питание, держим Reset ~5 секунд.

{{< video src="firstrun.webm" >}}

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

После запуска скрипт предложит сконфигурировать систему.

firsrun

После предложения ввести новый пароль суперпользователя лучше немного подождать, так как система всё ещё загружается и будут выводиться сообщения из журнала, сбивающие с толку.

Отвечаем на вопросы и завершаем установку.

Установка на eMMC

На данном этапе вся конфигурация сохраняется на USB накопитель. Для того, чтобы загрузить armbian нужно будет каждый раз нажимать reset при загрузке.

Чтобы установить armbian на встроенный eMMC накопитель и загружаться с него нужно выполнить

armbian-install -m yes

Без параметра -m у меня отказывалась загружаться операционная система.

Сам параметр расшифровывается как "Use Mainline u-boot" (см. тут).

При установке будет предложено выбрать устройство и файловую систему (я выбрал X96 Max Plus 2101 и ext4). После того, как скрипт завершит работу, вводим poweroff, извлекаем USB накопитель и переподключаем питание. Система теперь будет загружаться со встроенной памяти.

Если приставка к Wi-Fi не подключена, то советую это сделать (с помощью armbian-config или nmcli). Через Ethernet подключить вроде как не получится, проблемы с драйвером.

Если вы уже подключили приставку к Wi-Fi, то можно управлять ей с помощью ssh (в дистрибутиве уже настроен ssh сервер).

Решение проблем с нестабильным Wi-Fi

В процессе работы я начал наблюдать подобные сообщения ядра

[   83.751980] ------------[ cut here ]------------
[   83.754595] firmware failed to ack driver for entering Deep Power mode
[   83.760091] WARNING: CPU: 1 PID: 9 at drivers/net/wireless/realtek/rtw88/ps.c:106 rtw_power_mode_change+0x154/0x1a0 [rtw88_core]
[   83.771493] Modules linked in: cpufreq_userspace cpufreq_conservative cpufreq_powersave sunrpc hci_uart btqca btrtl btbcm btintel rtw88_8822cs rtw88_8822c rtw88_sdio rtw88_core bluetooth panfrost mac80211 gpu_sched snd_soc_meson_axg_sound_card drm_shmem_helper snd_soc_meson_card_utils snd_soc_meson_g12a_tohdmitx cfg80211 snd_soc_meson_axg_tdmout snd_soc_meson_codec_glue rfkill snd_soc_meson_axg_frddr libarc4 snd_soc_meson_axg_fifo zram ir_nec_decoder meson_gxbb_wdt meson_imeson_vdec(C) videobuf2_dma_contig v4l2_mem2mem snd_soc_meson_axg_tdm_interface snd_soc_meson_axg_tdm_formatter tcp_bbr sch_fq ip_tables x_tables hid_logitech_hidpp hid_logitech_dj
[   83.832293] CPU: 1 PID: 9 Comm: kworker/u8:0 Tainted: G         C         6.1.62-ophub #1
[   83.840398] Hardware name: AMedia X96 Max+ (DT)
[   83.844885] Workqueue: phy0 rtw_watch_dog_work [rtw88_core]
[   83.850404] pstate: 60400009 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[   83.857302] pc : rtw_power_mode_change+0x154/0x1a0 [rtw88_core]
[   83.863166] lr : rtw_power_mode_change+0x154/0x1a0 [rtw88_core]
[   83.869031] sp : ffffffc00a18bcc0
[   83.872309] x29: ffffffc00a18bcc0 x28: ffffff800005bd00 x27: ffffff800000ec00
[   83.879382] x26: ffffff80030908e0 x25: ffffff8003092080 x24: 0000000000000001
[   83.886454] x23: 0000000000068dbc x22: 00000013843748d4 x21: 0000000000000001
[   83.893527] x20: 0000000000000000 x19: ffffff8003092080 x18: ffffffffffffffff
[   83.900599] x17: 0000000000000004 x16: 0000000000000000 x15: 0000000000000006
[   83.907671] x14: 0000000000000000 x13: ffffffc009d9ce50 x12: 0000000000000648
[   83.914744] x11: 0000000000000218 x10: ffffffc009e4ce50 x9 : ffffffc009d9ce50
[   83.921816] x8 : 00000000ffffdfff x7 : ffffffc009e4ce50 x6 : 0000000000000001
[   83.928889] x5 : 0000000000000000 x4 : 0000000000000000 x3 : 0000000000000000
[   83.935961] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffffff80000a7000
[   83.943035] Call trace:
[   83.945810]  rtw_power_mode_change+0x154/0x1a0 [rtw88_core]
[   83.950970]  rtw_sdio_deep_ps+0x90/0xd0 [rtw88_sdio]
[   83.955886]  rtw_enter_lps+0xf4/0x110 [rtw88_core]
[   83.960629]  rtw_watch_dog_work+0x25c/0x270 [rtw88_core]
[   83.965890]  process_one_work+0x1dc/0x370
[   83.969858]  worker_thread+0x168/0x4e0
[   83.973567]  kthread+0xd4/0xdc
[   83.976585]  ret_from_fork+0x10/0x20
[   83.980123] ---[ end trace 0000000000000000 ]---

Связано это с проблемами входа wi-fi модуля в режим экономии энергии. Поэтому эту самую экономию мы отключим.

Открываем файл /etc/NetworkManager/conf.d/default-wifi-powersave-on.conf и значение параметра wifi.powersave изменяем с 3 на 2.

sudo nano /etc/NetworkManager/conf.d/default-wifi-powersave-on.conf
[connection]
# Values are 0 (use default), 1 (ignore/don't touch), 2 (disable) or 3 (enable).
-- wifi.powersave = 3
++ wifi.powersave = 2

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

sudo iwconfig wlan0 | grep "Power Management"

Результат должен быть Power Management:off.

Вывод произвольного текста на семисегментный дисплей

В репозитории ophub/amlogic-s9xxx-armbian описывается как включать или отключать индикаторы на дисплее.

TL;DR:

sudo armbian-openvfd

Однако нет информации как выводить произвольный текст вместо часов.

После изучения исходников сервиса openvfd стало понятно, что сервис использует канал по пути /tmp/openvfd_service. При записи в этот файл, сервис перестаёт отключает вывод по умолчанию (часы) и выводит заданную информацию. Сама информация передаётся в виде структуры vfd_display_data (openvfd_drv.h). В этой структуре достаточно установить mode = DISPLAY_MODE_TITLE и заполнить string_main.

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

Что нужно сделать?

Клонировать репозиторий arthur-liberman/linux_openvfd:

git clone https://github.com/arthur-liberman/linux_openvfd

Перейти в директорию репозитория:

cd linux_openvfd

Создаём исходный файл программы. Я назвал его set-display-text.c.

nano set-display-text.c

Код:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include "driver/openvfd_drv.h"

#define SERVICE_PIPE "/tmp/openvfd_service"

int main(int argc, char const *argv[])
{
    if (argc < 2)
    {
        fprintf(stderr, "Text not provided\n");
        exit(1);
    }

    // Открыть файл сервиса
    int service_fd = open(SERVICE_PIPE, O_RDWR);

    if (service_fd < 0)
    {
        perror("Open " SERVICE_PIPE " failed\n");
        exit(1);
    }

    // Структура данных драйвера дисплея
    static struct vfd_display_data data;

    // Инициализировать структуру пустыми значениями
    memset(&data, 0, sizeof(data));

    // Режим вывода на экран - произвольный текст
    data.mode = DISPLAY_MODE_TITLE;

    // Скопировать максимум 4 символа
    strncpy(data.string_main, argv[1], 4);
    data.string_main[5] = '\0';

    // Записать в файл сервиса
    int written = write(service_fd, &data, sizeof(data));

    if (written != sizeof(data))
    {
        perror("Write failed\n");
    }

    close(service_fd);

    return 0;
}

Компилируем:

gcc -O2 -Werror set-display-text.c -o set-display-text

На всякий случай оставлю тут собранный бинарник: set-display-text

Проверяем.

Сначала запускаем драйвер и сервис (если на экране уже что-то выводится, то сервис уже запущен!):

sudo armbian-openvfd

Или

sudo armbian-openvfd 12

Где 12 - номер модели (x96maxplus s905x3).

Далее проверяем нашу утилиту:

sudo ./set-display-text lol

lol.jpg

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

sudo cp set-display-text /usr/local/bin

Автозапуск драйвера и сервиса индикации

Открываем файл автозапуска и меняем строки:

sudo nano /etc/custom_service/start_service.sh
# Led display control
-- openvfd_enable="no"
++ openvfd_enable="yes"
-- openvfd_boxid="15"
++ openvfd_boxid="12"
[[ "${openvfd_enable}" == "yes" && -n "${openvfd_boxid}" && -x "/usr/sbin/armbian-openvfd" ]] && {
    armbian-openvfd ${openvfd_boxid} &&
        echo "[$(date +"%Y.%m.%d.%H:%M:%S")] The openvfd service started successfully." >>${custom_log}
}

openvfd_boxid можно узнать выполнив sudo armbian-openvfd.