MultiMote
ed2238d5a6
All checks were successful
Build and deploy mmote.ru / Build-And-Deploy (push) Successful in 21s
365 lines
17 KiB
Markdown
365 lines
17 KiB
Markdown
---
|
||
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")
|