mmote.ru/content/posts/x96maxplus-armbian/index.md
2023-11-19 18:30:45 +03:00

296 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: "Linux на X96 Max Plus"
categories: ["linux", "cpp"]
date: 2023-11-17T21:09:25+03:00
lastmod: 2023-11-19T18:27:39+03:00
draft: false
featured_image: miniature.jpg
---
Сегодня будем экономить на Raspberry Pi и поставим armbian на X96 Max Plus.
<!--more-->
> ⚠ **Прошу обратить внимание!**
>
> Моя модификация - **X96MaxPlus_2101**. Соответственно, действия описаны для этой модификации.
> Для других модификаций действия могут отличаться.
>
> Подробнее о модификациях [4pda](https://4pda.to/forum/index.php?showtopic=1013103&st=40#entry102780026).
## Подготовка USB накопителя
Для начала скачиваем образ файловой системы для нужного процессора отсюда: [ophub/amlogic-s9xxx-armbian](https://github.com/ophub/amlogic-s9xxx-armbian/releases).
Ищем в списке последний релиз для процессора s905x3. В момент написания статьи это был файл [Armbian_23.11.0_amlogic_s905x3_lunar_6.1.62_server_2023.11.12.img.gz](https://github.com/ophub/amlogic-s9xxx-armbian/releases/download/Armbian_lunar_save_2023.11/Armbian_23.11.0_amlogic_s905x3_lunar_6.1.62_server_2023.11.12.img.gz).
Ищем USB флешку. Моя была на 8 ГБ (успешно загружался и с 16). С помощью какой-либо программы записываем образ диска на неё.
Я использовал [Rufus](https://rufus.ie/ru/).
Можно использовать что угодно, что умеет записывать сырой образ диска на накопитель (Balena Etcher / dd / etc.).
В Rufus сразу выбираем .gz архив, программа сама его распаковывает в процессе записи.
![rufus](rufus.png)
После записи образа на накопителе открываем раздел fat32, в нём файл `uEnv.txt`. Меняем имя файла в параметре FDT на `meson-sm1-x96-max-plus-2101.dtb`:
```diff
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](firstrun.jpg)
После предложения ввести новый пароль суперпользователя лучше немного подождать,
так как система всё ещё загружается и будут выводиться сообщения из журнала, сбивающие с толку.
Отвечаем на вопросы и завершаем установку.
## Установка на eMMC
На данном этапе вся конфигурация сохраняется на **USB накопитель**. Для того, чтобы загрузить armbian нужно будет каждый раз нажимать reset при загрузке.
Чтобы установить armbian на встроенный eMMC накопитель и загружаться с него нужно выполнить:
```bash
armbian-install -m yes
```
Без параметра -m у меня отказывалась загружаться операционная система.
Сам параметр расшифровывается как "Use Mainline u-boot" (см. [тут](https://github.com/ophub/amlogic-s9xxx-armbian/tree/main/documents#81-installation-method-for-amlogic-series)).
При установке будет предложено выбрать устройство и файловую систему (я выбрал X96 Max Plus 2101 и ext4).
После того, как скрипт завершит работу, вводим poweroff, извлекаем USB накопитель и переподключаем питание.
Система теперь будет загружаться со встроенной памяти.
Если приставка к Wi-Fi не подключена, то советую это сделать (с помощью armbian-config или nmcli).
Через Ethernet подключить вроде как не получится, проблемы с драйвером.
Если вы уже подключили приставку к Wi-Fi, то можно управлять ей с помощью ssh (в дистрибутиве уже настроен ssh сервер).
## Решение проблем с нестабильным Wi-Fi
В процессе работы я начал наблюдать подобные сообщения ядра:
```bash
[ 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:
```bash
sudo nano /etc/NetworkManager/conf.d/default-wifi-powersave-on.conf
```
```diff
[connection]
# Values are 0 (use default), 1 (ignore/don't touch), 2 (disable) or 3 (enable).
-- wifi.powersave = 3
++ wifi.powersave = 2
```
После этого перезагружаемся (команда reboot). Проверить, отключилось ли энергосбережение можно командой:
```bash
sudo iwconfig wlan0 | grep "Power Management"
```
Результат должен быть `Power Management:off`.
## Вывод произвольного текста на семисегментный дисплей
В репозитории [ophub/amlogic-s9xxx-armbian](https://github.com/ophub/amlogic-s9xxx-armbian) описывается как включать или отключать индикаторы на дисплее
(TL;DR: `sudo armbian-openvfd`).
Однако нет информации как выводить произвольный текст вместо часов.
После изучения исходников [сервиса openvfd](https://github.com/arthur-liberman/linux_openvfd/blob/3118dda3aeb5b2f02b0ac0b5d30cbef58947a805/OpenVFDService.c#L342-L357)
стало понятно, что сервис использует канал по пути `/tmp/openvfd_service`.
При записи в этот файл, сервис отключает вывод по умолчанию (часы) и выводит заданную информацию.
Сама информация передаётся в виде структуры `vfd_display_data` (`openvfd_drv.h`). В этой структуре достаточно установить `mode = DISPLAY_MODE_TITLE` и заполнить `string_main`.
Имея всю эту информацию я сделал небольшую программку, которая устанавливает произвольный текст на дисплее.
Что нужно сделать?
Клонировать репозиторий [arthur-liberman/linux_openvfd](https://github.com/arthur-liberman/linux_openvfd):
```bash
git clone https://github.com/arthur-liberman/linux_openvfd
```
Перейти в директорию репозитория:
```bash
cd linux_openvfd
```
Создаём исходный файл программы. Я назвал его `set-display-text.c`:
```bash
nano set-display-text.c
```
Код:
```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;
}
```
Компилируем:
```bash
gcc -O2 -Werror set-display-text.c -o set-display-text
```
На всякий случай оставлю тут собранный бинарник: [set-display-text](set-display-text)
Проверяем.
Сначала запускаем драйвер и сервис (если на экране уже что-то выводится, то сервис уже запущен!):
```bash
sudo armbian-openvfd
```
Или
```bash
sudo armbian-openvfd 12
```
Где 12 - номер модели (x96maxplus s905x3).
Далее проверяем нашу утилиту:
```bash
sudo ./set-display-text lol
```
![lol.jpg](lol.jpg)
Если всё работает, то можно скопировать исполняемый файл в локальное окружение для того, чтобы можно было его выполнять из любого места:
```bash
sudo cp set-display-text /usr/local/bin
```
### Автозапуск драйвера и сервиса индикации
Открываем файл автозапуска и меняем строки:
```
sudo nano /etc/custom_service/start_service.sh
```
```diff
# 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`.