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

365 lines
17 KiB
Markdown
Raw Permalink 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
tags:
- x96 max plus
- linux
- armbian
- ender-3
- прошивка
- программирование
date: 2023-11-17T21:09:25+03:00
lastmod: 2024-04-26T23:04:24+03:00
draft: false
featured_image: miniature.jpg
telegram_entry_id: mmotium/9
---
Сегодня будем экономить на 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**.
Ищем 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
```
### Автозапуск драйвера и сервиса индикации
Открываем файл автозапуска и меняем строки:
```bash
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`.
### Вывод текста на экран без root прав
Так как каналу `/tmp/openvfd_service` не установлено никаких групп кроме root,
то ничего не остается, кроме как разрешить пользователю выполнять команду через sudo без пароля.
Для этого нужно создать файл `/etc/sudoers.d/allow-set-display-text-nopasswd` с содержимым `multimote ALL=(ALL) NOPASSWD: /usr/local/bin/set-display-text`, где:
* allow-set-display-text-nopasswd - любое имя для правила
* multimote - необходимое имя пользователя
Создать правило одной командой:
```bash
echo "multimote ALL=(ALL) NOPASSWD: /usr/local/bin/set-display-text" | sudo tee /etc/sudoers.d/allow-set-display-text-nopasswd
```
### Отображение процентов печати в Klipper
Мне не раз попадалась информация об установки klipper на тв-приставки. [Klipper](https://www.klipper3d.org) - прошивка для 3d принтеров, состоящая из двух частей.
Первая часть устанавливается на контроллер самого 3d принтера, а вторая на любой компьютер, который поддерживает установку Klipper.
Установка производится через [kiauh](https://github.com/dw-0/kiauh) и не вызывает никаких трудностей.
Для отображения прогресса печати на дисплее x96 Max Plus я использовал дополнение [G-Code Shell Command](https://github.com/dw-0/kiauh/blob/master/docs/gcode_shell_command.md).
Устанавливается дополнение тоже через kiauh. Для этого нужно перейти в меню Advanced:
![kiauh1](kiauh1.png)
И выбрать там G-Code Shell Command:
![kiauh2](kiauh2.png)
Теперь нужно добавить в printer.cfg следующее:
```yaml
# Определить команду для вывода на дисплей
# Важно! Для команды sudo set-display-text должен быть отключен ввод пароля (см. sudo NOPASSWD)
[gcode_shell_command set_display_text]
command: sudo /usr/local/bin/set-display-text
verbose: False
# Перехватить команду M73
[gcode_macro M73]
rename_existing: M73.1
gcode:
{% set P = params.P|default(0)|int %}
M73.1 {rawparams}
RUN_SHELL_COMMAND CMD=set_display_text PARAMS={P}
```
После этого можно использовать команду M73 для вывода прогресса печати на дисплей (например, для 55% - `M73 P55`).
Осталось сконфигурировать слайсер для того, чтобы он добавлял эти команды в g-код.
Для [PrusaSlicer](https://www.prusa3d.com/prusaslicer/) достаточно включить **Supports remaining times** в **настройках принтера**:
![prusaslicer](prusaslicer.png)
![printprogress](printprogress.jpg "Прогресс печати на Ender-3")