В прошлой статье, мы с вами рассмотрели на что способен одноплатный компьютер, который стоит всего 1.000 рублей. Как мы выяснили, перспективы у данного девайса весьма неплохие, однако по факту, Orange Pi продаёт практически голую железку, которую нужно дорабатывать самому. Да, тут есть Ubuntu/Fedora, да, тут выведена гребенка с I2C/SPI — однако из коробки это всё работает криво-косо, либо не работает совсем. Даже обещанные шины SPI/I2C фактически не доступны в системе «из коробки». Материалов о доработке этого одноплатника в сети мало, поэтому я решил довести его до ума сам и поделится с вами — в том числе, готовыми бинарными образами! Интересно, на что способен доработанный одноплатник по цене ящика пива? :)
Над чем будем работать
В прошлой статье, мы с вами определились с потенциальными перспективами такого устройства. По цене 3х ESP32, производитель предлагает нам два полноценных вычислительных ARM-ядра, 256 мегабайт оперативной памяти, 512 мегабайт встроенной NAND-памяти, контроллер питания с возможностью работы от литий-ионных АКБ и 3G модем. Но в бочке меда нашлась ложка дегтя: никто не собирался это всё поддерживать и Orange Pi практически сразу «забили» на поддержку устройства, ограничившись портом Debian/Ubuntun на устройство.
Более того, производитель даже не описал как работать с GPIO и шинами устройства — что фактически превращало его из одноплатника в обычную ТВ-приставку, только без нормального видеовыхода. Меня крайне удивило, почему над такой дешевой платой не хотело работать коммьюнити — большинство людей только видели всю ситуацию и шли оставлять негативный отзыв, не попытавшись даже разобраться. А ведь для опытного линуксоида-эмбеддера здесь работы на день-два!
Ко всему прочему, в Linux не работает GSM-стек. Да, совсем. Производитель даже не стал кооперироваться с MediaTek, чтобы попытаться реализовать работу с модемом на уровне системы. А ведь фактически, вся работа с модемом происходит лишь на уровне AT-команд. Так в чем же проблема была?
Со всем этим мне и предстоит разобраться! Клонируем репозиторий с исходниками ядра и бежим собирать!
Собираем ядро. I2C и SPI
Вместо типичного Buildroot, Orange Pi использует свою собственную простую систему сборки на shell-скриптах: в качестве тулчейна используется уже готовый linaro. Отчасти, это связано с самими чипами, на которых работают их устройства — MediaTek, например, не использует Mainline ядро и в процессе сборке имеет ещё кучу шагов для подготовки финального образа. Там даже menuconfig не работает и все изменения приходится делать в уже сгенерированной когда-то конфигурации.
Клонируем репозиторий с системой сборки и запускаем скрипт:
git clone https://github.com/orangepi-xunlong/OrangePi_Build
cd OrangePi_Build
./Build_OrangePi.sh
Выбираем нашу плату — 3G IoT и ждем, пока система сборки фактически скачает все необходимое для сборки — исходный код ядра, папки external (драйвера, загрузчик и порт linux MediaTek). Обратите внимание, OrangePi даже систему сборки завязали на конкретной версии системы: только Ubuntu 18.04, но на самом деле, ядро соберется без проблем практически где угодно. После того, как все было скачано, переходим в папку с скриптом сборки и запускаем скрипт сборки:
cd ../OrangePi3G_iot/
./build.sh
А нет, не запускаем — скрипт жалуется на то, что не может поставить некоторые пакеты. Не беда — ставим bsdtar и python minimal вручную и идем править код скрипта. Находится в он scripts/general.sh: убираем оттуда устаревшие имена пакетов.
После этого, компиляция ядра должна пройти успешно. Обратите внимание на версию вашей платы — те, что продают сейчас — именно A. Если пытаться подкинуть им ядро для B, то они будут уходить в kernel panic из-за отсутствия eMMC.
Если mkbootimg будет жаловаться на libstdc++6, то ставим его x86 версию из репозиториев.
Готовое ядро будет лежать в output/kernel/boot.img, которое можно прошить на устройство. С одним маленьким нюансом — оно рассчитано на загрузку из внутренней памяти, которой критически мало для дистрибутива Linux! У нас нет boot_sd.img, который есть в оригинальном дистрибутиве. Попытка разобрать образ стандартным AndImgTool не увенчалась успехом — рамдиск встроен прямо в образ zImage, а не отдельно, как это обычно бывает у Android-образов.
Покопавшись в скриптах сборки, я так и не понял логику создания boot_sd, ничего связанного с sd я не нашел даже grep'ом по всей папке. Ну что-ж, тогда попробуем обходным путем: скомпилируем нужные драйвера в виде загружаемых модулей (ko). Идём в наш конфиг, расположенный в linux/arch/arm/configs/3giot_defconfig и меняем CONFIG_I2C_CHARDEV и CONFIG_SPI_SPIDEV на m. Пояснение: y заставит систему сборки скомпоновать драйвер статически с ядром, а m выделит его в виде отдельного модуля ko, который затем можно загрузить через insmod.
Снова собираем ядро, на этот раз компиляция занимает не больше минуты. Нужные нам файлы появятся в linux/drivers/spi/spidev.ko и linux/drivers/i2c/i2c-d-ev.ko. Переносим их на хост-пк, а затем и на само устройство с помощью SSH:
Загружаем модули ядра:
insmod i2c-dev.ko
И та-дам! Целых две i2c шины появилось в системе (/dev/i2c-0, /dev/i2c-1). Устанавливаем i2c-tools и идем проверять с помощью i2cdetect: первая шина полностью свободна под наши проекты, а на второй по некоторым адресам висит периферия (FM-радио как вариант):
I2C теперь точно работает! Но как насчет SPI?
insmod spidev.ko
Device or resource busy.
Увы! spidev нельзя подгружать динамически, только статически линковать с ядром, чего мы сделать пока не можем. Однако техническая возможность заставить работать SPI есть: например, написать свой драйвер, который транслирует команды из юзерспейса в SPI API, которое работает на уровне ядра.
GPIO
В прошлой статье, я вкратце рассказал, как работать с gpio из user-space на уровне терминала. Однако, большинство разработчиков потенциально будет пользоваться нативным API для GPIO — ну не всерьез же им парсить вывод состояния в консоль? Поэтому я решил написать крошечную библиотеку для работы с GPIO, такую же простую, как и DigitalWrite/DigitalRead!
Давайте сначала разберемся, как именно работать с драйвером GPIO. Для этого открываем исходники ядра и смотрим внимательно, что нам предлагает драйвер: в нашем случае, это вызовы IOCTL, да еще и простые и понятные. Это просто отлично! Я написал single-header библиотеку минут за 10: без проверки ошибок, но работоспособная.
void gpioInit();
void gpioSetDir(int num, byte dir);
byte gpioGetDir(int num);
void gpioWrite(int num, byte value);
byte gpioGetState(int num);
byte gpioRead(int num);
void gpioSetPullState(int num, byte enabled, byte up);
Пример использования (141 — крайний пин на гребенке):
#define GPIO_IMPL
#include "gpio.h"
#include <stdio.h>
void testPin(int pin)
{
printf("Pin state %i is %i\n", pin, gpioGetState(pin));
gpioSetDir(pin, 1);
gpioWrite(pin, 0);
printf("Pin state %i is %i\n", pin, gpioGetState(pin));
gpioWrite(pin, 1);
printf("Pin state %i is %i\n", pin, gpioGetState(pin));
}
int main(int argc, char** argv)
{
gpioInit();
testPin(141);
}
Модем
Скажу сразу: пока что завести модем мне не удалось, но я активно работаю над этим. В этой части статьи я распишу свои находки и догадки касательно модемов на чипах MediaTek.
В устройствах MediaTek, драйвер для общения с GPS, A-GPS и модемом один — ccci, судя по всему cross chip communication interface. Именно ccci создает устройства, с в которые поступает вход с микрофона и выход на динамики, а также он создает управляющие интерфейсы для общения с различными модулями этого SoC.
При старте ядра, ccci создаёт много устройств — ccci_ioctl, ccci_ipc, ccci_fs и самое нужное нам — ttyC0/ttyC1/ttyC2 — в зависимости от количества СИМ-карт в системе. Кроме ccci, в системе есть некий 6620_launcher — бинарник, который загружает прошивку Wi-Fi и gsm0710muxd — специальный сервис, который позволяет в GPRS-сетях одновременно разговаривать и сидеть в интернете.
На смартфонах MTK есть factory mode — так называемый тестовый режим, который гоняют на заводах. Вы, вероятно, когда-то видели китайские меню похожее на рекавери — это и есть factory mode. Из этого режима можно дозвонится в 911 и активировать модем без запуска Android и RIL. Как это работает? Идём читать исходники ядра!
В factory-режиме, для каждого теста, программа активирует модем заново. Для этого есть функции тестового режима для работы с AT-командами и для инициализации модема. Сначала, она открывает терминал /dev/ttyC0 — именно там происходит общение с модемом с помощью AT-команд:
После этого, программа выводит модем из режима сна с помощью команды «AT+ESLP=0», инициализирует СИМ-карту с помощью команды «AT+ESIMS» и задает режим работы с помощью «AT+EFUN=1» и «AT+CREG=1». После этого, модем начинает искать сеть и доступен для обычного общения с помощью AT-команд. Однако, написав тестовую софтину для общения с модемом из под Debian, я получал ошибки вида Device not found. Почему? Пока не знаю. Однако я продолжаю изучать данный вопрос!
Заключение
Подготовленные мною файлы вы можете скачать на диске. Там скомпилированные модули ядра, библиотека для работы с GPIO и пару тестовых программ в качестве примеров.
К счастью, довести гаджет до ума мы смогли своими силами. Весьма странно, что такой крупный и уважаемый производитель как Orange Pi, банально решил «забить» на поддержку собственного устройства. И я лично считаю, что не стоит закидывать в долгий ящик их тем читателям, которые купили когда-то себе подобный девайс и забили, смирившись с отсутствием гайдов.
Немного энтузиазма, опыта и видения будущего проекта — и все получится :)
Комментарии (16)
Worky
25.07.2023 08:24Обьясните, в чем смысл производителю изготовить плату и "кинуть" с поддержкой? или его "кинул" прозводитель чипа?
MDXE1337 Автор
25.07.2023 08:24Потому что это очень дешевая плата, и потому что ее проектировали с косяками изначально:
Чипы MediaTek поддерживают параллельный, MIPI и RGB интерфейсы дисплеев, но не умеют хдми, а оранжи решили специально сделать MIPI и продавать дисплей отдельно втридорога (на которые особо никто не "клевал"). Так и получилось, что одноплатник остался без возможности вывода картинки.
Плюс изначально не было поддержки i2c/spi, но они были разведены на гребенке. Почему так? Я хз.
Сейчас в похожем ценовом сегменте есть платы Lctech. Их не особо поддерживают, однако производитель поступил проще: сразу добавил поддержку своей платы в мейнлайн ядро и теперь нет никаких проблем с запуском актуальной версии линуха :)
NutsUnderline
25.07.2023 08:24нажежда что пипл схавает и своими силами допилит, бесплатно, да еще и добавки попросит. это не единтвенная у них такая плата. на плате с процом H6 сделали pci который толком запустить не смогли (был костыль с гипервизором). были вроде вполне ниче платы но исчезли из производства. нам никогда не узнать каким местом они там думали, но вероятно - считали деньги
FirstEgo
25.07.2023 08:24Я крайний раз с таким удовольствием наблюдал за проектом, наверное, во времена плеера из журнала vogue))
Спасибо за старания!!!))
Paskin
25.07.2023 08:24я получал ошибки вида Device not found.
Я бы в этом случае смотрел бы в сторону device tree. Драйверы ядра работают с абстракциями типа "пин_RxD" и "пин_ТxD" - а соответствие физическим "ножкам" микроконтроллера и параметрам конкретной платы задается именно там.
MDXE1337 Автор
25.07.2023 08:24В том и суть, что ядро старое - там нет devicetree. 3.4.67 если не ошибаюсь, все настройки через machine-файлы.
Godless
Это чудо можно относительно несложно превратить в сетевую колонку ? Не пробовали ?
Чтобы пачку таких можно было по квартире раскидать для одновременного вывода звука ?
Я так понял для звука тоже надо или готовую плату брать, или паять что-то...
MDXE1337 Автор
Да, подойдет, тут есть ЦАП и готовый звуковой тракт. Здесь уже даже джек распаян! Если под линух есть нужный софт или запилите сами - будет работать без проблем.
vviz
Вполне работают колонки на основе KaRadio+icecast+mpd+RompR
DmSting
Гуглите LMS - LogitechMediaServer и плеер squeeze, ну а следом esp-squeeze