STM32MP1: U-Boot, Buildroot, Arch Linux и немного Debian

Привет, Хабр!

Некоторое время назад компания STMicroelectronics выпустила интересные процессоры серии STM32MP1. Когда у меня наконец-то дошли руки до отладочной платы на основе этого процессора, я с некоторым удивлением обнаружил, что для нее отсутствуют какие-либо сборки на основе популярных дистрибутивов (Debian, Arch Linux и др). Оставалось только попробовать самому адаптировать какой-нибудь дистрибутив под данную плату. По результатам этого и появилась данная статья.



Что по характеристикам?


Данная статья была бы не полной без хотя бы краткого обзора характеристик процессоров серии STM32MP1. Существует три семейства процессоров серии STM32MP1: STM32MP151, STM32MP153 и STM32MP157. Их основные характеристики приведены в таблице.



Как видим из таблицы, разница между семействами заключается в том, что STM32MP151 имеет одно ядро Cortex-A7, тогда как STM32MP153 и STM32MP157 имеют два таких ядра, а STM32MP157 еще и дополнительно обладает поддержкой 3D GPU. Но в целом характеристики данных процессоров в 2020 году не производят какого-либо впечатления, они достаточно скромные. Почему же я все-таки обратил на них внимание?

Почему STM32MP1?


Действительно, может возникнуть вполне закономерный вопрос: есть же Raspberry Pi, есть Banana Pi, есть Orange Pi, наконец – зачем нужен еще какой-то STM32MP1? Тем более, что все эти платы обычно обладают заметно большей производительностью, чем объект нашего исследования. Ответ прост – пока вы делаете какие-либо поделки для домашнего использования все так и есть, вам надо брать малинку и это будет правильно. Но если же речь идет о серийно выпускаемой продукции для промышленных применений – вот тут начинает играть решающую роль другие вещи, благодаря которым STM32MP1 оказывается в выигрыше:

  • Диапазон рабочих температур. У STM32MP1 он начинается от минус 40 градусов, тогда как у многих процессоров других одноплатников хорошо если он минус 20.
  • Наличие качественной документации. У STMicroelectronics традиционно с этим все довольно неплохо, тогда как документацию на китайские процессоры часто приходится собирать по обрывкам интернетов.
  • Возможность заказать большую партию у проверенных поставщиков. Тот же DigiKey или Mouser способны без проблем отгрузит любое количество STM32MP1, тогда как китайские процессоры придется покупать на сомнительных площадках типа алиэкспресса.

Конечно, ST32MP1 не единственные на рынке процессоров для промышленных применений. Есть и NXP, и TI. Что касается TI, то у меня был проект достаточно сложного модуля на его основе, и остался осадочек от заметного числа аппаратных особенностей, которые не освещены в документации, но при несоблюдении которых процессор мог полностью выходить из строя, причем не сразу, а со временем и в самый неподходящий момент. Кроме того, это был одноядерный процессор, и с ростом числа возложенных на него задач все чаще возникали проблемы с производительностью. В то же время я имел дело с микроконтроллерами фирмы STMicroelectronics, и они зарекомендовали себя достаточно хорошо, поэтому я и решил попробовать поковырять этот их новый камешек.

Отладочная плата


Для проведения экспериментов я приобрел отладочную плату STM32MP157A-DK1. Это достаточно скромная по оснащению плата: у нее нет LCD дисплея как у STM32MP157C-DK2 или такой богатой периферии как у STM32MP157A-EV1. Однако есть разъем для microSD-карты, консоль USB-UART, несколько USB портов и Ethernet. Для первого старта более чем достаточно. А чтобы разбавить сухое повествование какой-нибудь картинкой, я прилагаю фото этой отладочной платы.



Что есть из готового софта?


У STMicroelectronics обычно все достаточно хорошо с точки зрения железа, но ужасно с точки зрения софта. Все эти модификации Atollic True Studio, CubeMX, CubeIDE, которые с каждым новым релизом глючат все больше и больше, навевают некоторую тоску. Немногим лучше дело обстоит и с поддержкой STM32MP1. STMicroelectronics предлагает только некую сборку OpenSTLinux. Эта сборка представляет собой дистрибутив, построенный с помощью Yocto Project. Безусловно, все это может существовать и в таком виде, но для меня главным минусом было отсутствие доступа к репозитариям известных дистрибутивов. Это значит, что вы не сможете поставить себе на плату какой-либо утилиту из репозиториев популярных дистрибутивов просто выполнив команду по типу apt-get install. Часто это и не требуется для встраиваемых решений, однако возможны ситуации, когда такая возможность точно не будет лишней.

Что будем делать?


Итак, задача ясна – нам надо запустить какой-либо популярный дистрибутив на нашей отладочной плате. Мой выбор пал на Arch Linux. Это не самый простой дистрибутив, однако он неплохо адаптирован под устройства на ARM: есть готовые сборки и официальный сайт, посвященный именно этому.

Первым делом я попробовал решить проблему с наскока – просто подсунул загрузчику готовое ядро из состава дистрибутива Arch Linux, собранное под armv7. Такое иногда срабатывало на других платах, однако тут меня ждало фиаско: не смотря на то, что ядро было собрано под правильную архитектуру, оно не запустилось. Ну что ж, значит, надо собрать свое ядро и заодно уж свой загрузчик. План действий у меня был такой:

  1. Собираем загрузчик U-Boot.
  2. Собираем ядро Linux.
  3. Размечаем microSD-карту.
  4. Записываем на microSD-карту загрузчик, ядро и корневую файловую систему.
  5. Profit

Подготовка к сборке


Для претворения обозначенного плана в жизнь нам понадобится компьютер с Linux и картридером для записи на microSD-карту. Я использовал ноутбук с Debian 10, но вообще это не принципиально, могут только немого отличаться названия утилит. Итак, ставим требуемые утилиты. Отмечу сразу, что сейчас и далее все команды надо выполнять под пользователем root или же через sudo.

apt-get install git
apt-get install make
apt-get install gcc
apt-get install gcc-arm-linux-gnueabihf
apt-get install bison
apt-get install flex
apt-get install g++
apt-get install rsync
apt-get install libncurses-dev

В рамках подготовки к сборке создаем в рабочей директории три директории: u-boot (для загрузчика), buildroot (для сборки системы) и archlinux (для дистрибутива):

mkdir u-boot
mkdir buildroot
mkdir archlinux

Эти директории понадобятся нам дальше. Я буду ссылаться на эти названия дальше по тексту статьи.

Сборка U-Boot


Про U-Boot написано уже достаточно много статей, и в рамках данной я не буду углубляться с пояснениями что это, для чего нужно и как работает. Скажу лишь только, что это загрузчик, обеспечивающий старт Linux на ARM устройствах. Исходный код загрузчика U-Boot доступен на GitHub.

Для того, чтобы собрать U-Boot, первым делом клонируем репозиторий U-Boot в директорию u-boot, созданную нами ранее:

git clone https://github.com/u-boot/u-boot

Для успешной сборки U-Boot нам потребуется файл дерева устройств (device tree) и файл конфигурации U-Boot.

Файл дерева устройств является аппаратно-зависимым файлом. Этот файл описывает конфигурацию процессора под конкретную плату. Если вы делаете свою железку на основе какого-либо процессора ARM и планируете запускать на ней Linux, то вам потребуется разрабатывать свой файл дерева устройств под нее (либо же адаптировать какой-то готовый). Однако на многие отладочные платы существуют уже готовые файлы: заботливые разработчики U-Boot включают их в свой репозиторий. Итак, смотрим директорию u-boot/arch/arm/dts. В ней должен быть файл stm32mp157a-dk1.dtb – это и есть файл дерева устройств под нашу отладочную плату.

UPD: Как справедливо заметили в комментариях, файл stm32mp157a-dk1.dtb появится после выполнения первой сборки U-Boot. До запуска процесса сборки в директории u-boot/arch/arm/dts содержится исходный файл stm32mp157a-dk1.dts

В файле конфигурации U-Boot прописываются основные настройки загрузчика.

Конфигурировать с нуля U-Boot – достаточно долгий и трудоемкий процесс, потому что настроек там великое множество. Для этих целей существуют как консольные, так и графические конфигураторы. Однако и тут нам повезло: в директории u-boot/configs имеется файл stm32mp15_basic_defconfig. Это файл базовой конфигурации U-Boot под отладочные платы STM32MP15. Открываем этот файл и видим, что нам для быстрого старта достаточно поменять всего одну строчку: вместо

CONFIG_DEFAULT_DEVICE_TREE=”stm32mp157c-ev1”

пишем

CONFIG_DEFAULT_DEVICE_TREE=”stm32mp157a-dk1”

Этой строчкой мы говорим загрузчику, что надо использовать файл дерева устройств под нашу плату.

Теперь все готово для сборки U-Boot. Применяем наш конфиг:

make CROSS_COMPILE=arm-linux-gnueabihf- stm32mp15_basic_defconfig

И запускаем сборку:

make CROSS_COMPILE=arm-linux-gnueabihf-

Если все прошло без ошибок, то в директории u-boot у нас должна появиться куча файлов. Из них интерес для нас представляют два: u-boot-spl.stm32 и u-boot.img.

Первый файл – это так называемый первичный загрузчик (First Stage Boot Loader – FSBL). Он находится перед U-Boot, стартует первым и инициализирует DDR3 память, которая необходима для старта U-Boot. В других платах часто FSBL объединен с U-Boot в один образ, однако здесь придется каждый образ записывать на флешку отдельно.

На этом с U-Boot пока все, сохраним обозначенные файлы и перейдем непосредственно к сборке ядра Linux.

Сборка ядра Linux


Для сборки ядра Linux я буду использовать Buildroot. Конечно, для этих целей можно использовать не менее популярный Yocto или же вообще попробовать собрать ядро из исходников с kernel.org. Однако у меня был некоторый опыт работы с Buildroot, поэтому на нем я и остановил свой выбор. Кроме того, с помощью Buildroot также собирается и корневая файловая система (rootfs) и даже загрузчик U-Boot.

Теперь любыми доступными средствами качаем архив с Buildroot с официального сайта, распаковываем в директорию buildroot и переходим в нее.

Как и в случае с U-Boot, первым делом необходимо озаботиться конфигурационным файлом под нашу железку.

Идем в директорию buildroot/configs и видим, что разработчики уже добавили конфигурационный файл под нашу плату: имеется файл stm32mp157a_dk1_defconfig (верно для сборки Buildroot-2020.05, в более ранних версиях этого файла еще не было).

Я пробовал собирать ядро 5.4.26 с использованием этого конфигурационного файла, и оно в целом успешно стартовало на моей плате. Однако по какой-то причине файл дерева устройств для Linux в данной сборке оказался урезанным: по умолчанию не было даже поддержки USB портов. Будем надеяться, что со временем этот баг починят, но что делать сейчас?

Я пошел гуглить данную проблему и наткнулся на репозитории фирмы STMicroelectronics, где и нашел исходники Linux 4.19 с патчами для их продуктов. В том числе, там же оказались и правильные файлы DTB. Осталось только указать Buildroot использовать данный репозиторий при сборке ядра. Для этого копируем файл stm32mp157a_dk1_defconfig и переименовываем его в stm32mp157a_dk1_new_defconfig. Открываем его и вносим следующие изменения:

Вместо

BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_5_4=y

Пишем

BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_4_19=y

Вместо

BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="5.4.26"

Пишем

BR2_LINUX_KERNEL_CUSTOM_TARBALL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,STMicroelectronics,linux,v4.19-stm32mp-r1.2)/linux-v4.19-stm32mp-r1.2.tar.gz"

Сохраняем и закрываем файл. Конфигурационный файл готов, давайте применим его (выполнять надо из директории buildroot):

make CROSS_COMPILE=arm-linux-gnueabihf- stm32mp157a_dk1_new_defconfig

Эта команда перенесет информацию из нашего конфигурационного файла stm32mp157a_dk1_defconfig в файл .config, который находится в директории buildroot. В дальнейшем именно на основе файла .config будет строиться сборка.

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

Здесь стоит сказать, что по умолчанию в ядро будет включен минимальный функционал. Если мы хотим его расширить, то ядро необходимо будет конфигурировать под себя. Как минимум надо будет добавить в ядро поддержку Control Group: без этого наш Arch Linux не запустится. Дополнительно в качестве примера я продемонстрирую, как добавить в ядро поддержку работы USB-flash накопителей: в результате наша отладочная плата сможем работать с флешками.
Для запуска конфигуратора ядра из директории buildroot выполняем команду

make linux-menuconfig

и идем пить чай. Данный процесс не быстрый и в зависимости от мощности вашего компьютера может занять от пятнадцати минут до нескольких часов. Важно: в процессе работы buildroot необходимо стабильное соединение с интернетом, будет скачано много разных пакетов.
Если в процессе выскочит ошибка вида

configure: error: you should not run configure as root (set FORCE_UNSAFE_CONFIGURE=1 in environment to bypass this check)
See `config.log' for more details

необходимы будет выполнить команду

export FORCE_UNSAFE_CONFIGURE=1

и повторно запустить конфигуратор ядра.

По итогу должно появиться окно конфигуратора:



Добавляем поддержку Control Group: General setup -> Control Group support и выставляем звездочку с помощью пробела:



А как добавить поддержку флешек?
Добавляем поддержку SCSI устройств. Это древнее наследие из 80-х годов, без которого, однако, не заведется работа с USB FLASH накопителями. Идем в Device Drivers -> SCSI support и выставляем звездочки в соответствии с рисунком:



Добавляем поддержку непосредственно работы с USB FLASH накопителями. Идем в Device Drivers -> USB support и ставим звездочку USB Mass Storage support:



Теперь, чтобы получилось корректно примонтировать FLASH накопитель добавляем дополнительно следующие атрибуты: File systems -> Native language support -> Codepage 437 и File systems -> Native language support -> NLS ISO 8859-1:





Этого хватило для того, чтобы USB FLASH накопители успешно определялись системой и монтировались.

После того, как все настройки в конфигураторе ядра сделаны, сохраняем их кнопкой Save и выходим из конфигуратора кнопкой Exit.

Теперь осталось только запустить процесс сборки командой:

make CROSS_COMPILE=arm-linux-gnueabihf-

и можно второй раз пойти пить чай, этот процесс тоже занимает немало времени.

Если все прошло без ошибок, то в директории buildroot/output/images должен появиться следующий набор файлов:

  • rootfs.ext2 – собранная корневая файловая система с ext2. Для нас не представляет интереса;
  • rootfs.ext4 – собранная корневая файловая система с ext4. Пригодится нам чуть позже;
  • sdcard.img – Образ microSD-карты, включающий в себя FSBL+U-Boot+zImage+rootfs. Файлик для ленивых, позволяет не утруждать себя разметкой microSD-карты и сразу залить на нее всю систему. Конечно же, это не наш путь :).
  • stm32mp157a-dk1.dtb – файл дерева устройства. Обязательно нам пригодится для запуска системы;
  • u-boot.img и u-boot-spl.stm32 – файл FSBL и U-Boot. Поскольку мы собирали их на прошлом шаге, они нам не нужны;
    А зачем мы собирали их отдельно?
    Действительно, Buildroot позволяет собрать вместе с ядром и корневой файловой системой еще и загрузчик U-Boot. Это удобно на этапе, когда уже пройдены все трудности первоначального старта. Но в самом начале пути обычно быстрее и удобнее собрать и запустить на плате только один U-Boot, и когда он уже гарантированно стабильно работает – переходить к запуску ядра Linux.
  • zImage – сердце всей системы – файл сжатого ядра Linux.

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

Разметка и разделы microSD-карты


Разметка microSD-карты и создание разделов – это очень важный этап, сильно завязанный на конкретную аппаратную платформу. К сожалению, информация по этому вопросу на конкретный процессор не всегда просто найти, а при этом даже если вы соберете полностью работоспособные U-Boot и ядро Linux, при малейшей ошибке в разметке microSD-карты ничего из этого работать не будет.

Сразу отмечу, что microSD-карта, с которой запускается система на STM32MP1, должна иметь GPT-разметку. В этом нам поможет утилита gdisk, но об этом чуть позже.

Разделы microSD-карты должны выглядеть следующим образом:



Как видно из рисунка, карта должна содержать минимум 5 разделов: fsbl1, fsbl2, ssbl, kernel, rootfs. Дополнительно можно также создать один или несколько разделов data для хранения на них какой-либо информации.

Разделы fsbl1 и fsbl2 являются полностью идентичными и на них записывается первичный загрузчик (как вы помните, это файл u-boot-spl.stm32, полученный нами в процессе сборки U-Boot). Не смотря на то, что работать все должно и только с одним таким разделом, документация на STM2MP1 рекомендует делать их два. К этим разделам предъявляются и другие требования:

  • Размер каждого раздела должен быть 256 КБ.
  • Каждый раздел должен иметь имя, включающее в себя кодовое слово fsbl (fsbl1 и fsbl2). Это очень важно: если разделу не присвоить имя в соответствии с этим правилом, то система вообще не запускается.

Раздел ssbl предназначен для записи загрузчика U-Boot (файл u-boot.img, полученный нами в процессе сборки U-Boot). Рекомендуемый размер раздела ssbl 2 МБ.
Раздел kernel предназначен для записи на него ядра Linux (файл zImage), дерева устройств (файл stm32mp157a-dk1.dtb), а также скрипта для U-Boot, с помощью которого будет произведен запуск системы. Рекомендуемый размер раздела kernel 64 МБ.

Раздел rootfs предназначен для записи корневой файловой системы. Мы попробуем записать на него корневую файловую систему, собранную Buildroot, а также корневую файловую систему Arch Linux. Рекомендуемый размер раздела rootfs – 1 ГБ или более.
Раздел data предназначен для хранения пользовательских данных. Можно сделать один такой раздел или несколько. А можно вообще обойтись без него. В рамках данной статьи я не буду создавать этот раздел.

Итак, приступаем к разметке. Вставляем microSD-карту в картридер нашего компьютера с Linux на борту и любыми доступными способами (например, с помощью dmesg) определяем имя появившегося устройства. В моем случае это /dev/sdb. В вашем случае это может быть другое имя.

Запускаем утилиту gdisk и полностью удаляем имеющуюся на microSD-карте разметку:

root@debian:/home/myuser# gdisk /dev/sdb
GPT fdisk (gdisk) version 1.0.3
Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present
Found valid GPT with protective MBR; using GPT.
Command (? for help): x
Expert command (? for help): z
About to wipe out GPT on /dev/sdb. Proceed? (Y/N): y
GPT data structures destroyed! You may now partition the disk using fdisk or
other utilities.
Blank out MBR? (Y/N): y

На всякий случай забиваем начало microSD-карточки нулями.

dd if=/dev/zero of=/dev/sdb bs=1M count=64

Теперь снова запускаем gdisk, добавляем разметку и создаем 5 разделов на microSD-карте согласно таблице, которую я приводил выше:

root@debian:/home/myuser# gdisk /dev/sdb
GPT fdisk (gdisk) version 1.0.3

Partition table scan:
  MBR: not present
  BSD: not present
  APM: not present
  GPT: not present

Creating new GPT entries.

Command (? for help): o
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): y

Command (? for help): n
Partition number (1-128, default 1): 1
First sector (34-30873566, default = 2048) or {+-}size{KMGTP}: 
Last sector (2048-30873566, default = 30873566) or {+-}size{KMGTP}: +256K
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 
Changed type of partition to 'Linux filesystem'

Command (? for help): n
Partition number (2-128, default 2): 2
First sector (34-30873566, default = 4096) or {+-}size{KMGTP}: 
Last sector (4096-30873566, default = 30873566) or {+-}size{KMGTP}: +256K
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 
Changed type of partition to 'Linux filesystem'

Command (? for help): n
Partition number (3-128, default 3): 3
First sector (34-30873566, default = 6144) or {+-}size{KMGTP}: 
Last sector (6144-30873566, default = 30873566) or {+-}size{KMGTP}: +2M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 
Changed type of partition to 'Linux filesystem'

Command (? for help): n
Partition number (4-128, default 4): 4
First sector (34-30873566, default = 10240) or {+-}size{KMGTP}: 
Last sector (10240-30873566, default = 30873566) or {+-}size{KMGTP}: +64M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 
Changed type of partition to 'Linux filesystem'

Command (? for help): n
Partition number (5-128, default 5): 5
First sector (34-30873566, default = 141312) or {+-}size{KMGTP}: 
Last sector (141312-30873566, default = 30873566) or {+-}size{KMGTP}: 
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 
Changed type of partition to 'Linux filesystem'

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/sdb.
The operation has completed successfully.

Далее добавляем имена разделам на microSD-карте. Как вы помните, это особенно критично для первых разделов, куда будет записан FSBL: если не присвоить им требуемые имена, то система не запустится:

root@debian:/home/myuser# gdisk /dev/sdb
GPT fdisk (gdisk) version 1.0.3

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.

Command (? for help): c
Partition number (1-5): 1
Enter name: fsbl1

Command (? for help): c
Partition number (1-5): 2
Enter name: fsbl2

Command (? for help): c
Partition number (1-5): 3
Enter name: ssbl

Command (? for help): c
Partition number (1-5): 4
Enter name: kernel

Command (? for help): c
Partition number (1-5): 5
Enter name: roootfs

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/sdb.
The operation has completed successfully.

В завершении работы с microSD-картой нам надо добавить атрибут legacy BIOS bootable в раздел, на котором у нас будет записано ядро Linux. Без этого атрибута ядро запускаться отказывалось:

root@debian:/home/myuser# gdisk /dev/sdb
GPT fdisk (gdisk) version 1.0.3

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.

Command (? for help): x

Expert command (? for help): a
Partition number (1-5): 4
Known attributes are:
0: system partition
1: hide from EFI
2: legacy BIOS bootable
60: read-only
62: hidden
63: do not automount

Attribute value is 0000000000000000. Set fields are:
  No fields set

Toggle which attribute field (0-63, 64 or <Enter> to exit): 2
Have enabled the 'legacy BIOS bootable' attribute.
Attribute value is 0000000000000004. Set fields are:
2 (legacy BIOS bootable)

Toggle which attribute field (0-63, 64 or <Enter> to exit): 

Expert command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/sdb.
The operation has completed successfully.

Вот и все, разметка карты памяти готова. На всякий случай проверим, что все записалось как надо. Для этого опять запустим gdisk и выполним команду p. Результат должен соответствовать рисунку:



Теперь создаем файловую систему ext4 на /dev/sdb4 и /dev/sdb5:

mkfs.ext4 /dev/sdb4
mkfs.ext4 /dev/sdb5

И прописываем метки тома, чтобы потом было проще к ним обращаться:

e2label /dev/sdb4 kernel
e2label /dev/sdb5 rootfs

На этом создание разделов карточки памяти закончено, можно переходить к записи на нее файлов.

Запись на microSD-карту


Итак, на текущем этапе все готово для записи на microSD-карту. Вставляем ее в картриред компьютера с Linux и записываем первичный загрузчик (FSBL) в первый и второй разделы mocroSD-карты:

dd if=u-boot/u-boot-spl.stm32 of=/dev/sdb1
dd if=u-boot/u-boot-spl.stm32 of=/dev/sdb2

Теперь запишем U-Boot на третий раздел microSD-карты:

dd if=u-boot/u-boot.img of=/dev/sdb3

Дальше надо скопировать ядро, файл дерева устройств и скрипт загрузки в четвертый раздел на microSD-карте.

Прежде чем приступить к копированию файлов необходимо небольшое пояснения про скрипт загрузки. В этом скрипте, собственно, указывается различная информация для U-Boot, с помощью которой он сможет загрузить систему и передать управление ядру. Существуют разные способы написания этих скриптов, однако самый простой (на мой взгляд) описан в документации на STM32MP1: необходимо в корне раздела kernel создать директорию /extlinux и в ней создать текстовый файл с именем extlinux.conf со следующим содержимым:

LABEL stm32mp157a-dk1
KERNEL /zImage
FDT /stm32mp157a-dk1.dtb
APPEND root=/dev/mmcblk0p5 rootwait rw console=ttySTM0,115200

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

Теперь копируем ядро:

cp -a buildroot/output/images/zImage /media/myuser/kernel/

Примечание: в директорию /media/myuser/ у меня происходит монтирование microSD-карточки при установке в картиридер. В вашем случае это может быть другая директория.

Копируем файл дерева устройств:

cp -a buildroot/output/images/stm32mp157a-dk1.dtb /media/myuser/kernel/

Создаем директорию:

mkdir /media/myuser/kernel/extlinux

Создаем файл:

nano /media/myuser/kernel/extlinux/extlinux.conf

и наполняем его содержимым:

LABEL stm32mp157a-dk1
KERNEL /zImage
FDT /stm32mp157a-dk1.dtb
APPEND root=/dev/mmcblk0p5 rootwait rw console=ttySTM0,115200

Сохраняем файл и закрываем редактор.

На этом четвертый раздел microSD-карты готов: ядро linux и все вспомогательные файлы для него уже записаны. Уже на этом этапе если вставить microSD-карту в отладочную плату должно загружаться ядро Linux, правда, в конечном итоге оно вылетит в kernel panic по причине того, что не удается смонтировать корневую файловую систему. Это и не удивительно, ведь мы пока что ее на записали.

Остался финальный этап, на котором мы запишем на microSD-карту корневую файловую систему. И вот здесь возможны различные варианты:

  1. Запишем корневую файловую систему, сгенерированную Buildroot
  2. Запишем корневую файловую систему Arch Linux

Сначала запишем корневую файловую систему, которую нам сгенерировал Buildroot и попробуем запустится с ней. Это не являлось целью данной статьи, однако мне показалось, что в целом это может оказаться полезным для каких-либо применений, тем более, что данное действо не займет много времени. Корневая файловая система записывается в пятый раздел нашей microSD-карты всего одной командой:

dd if=buildroot/output/images/rootfs.ext4 of=/dev/sdb5

Теперь вставим карточку памяти в отладочную плату и запустим систему. Наблюдать вывод отладочной информации мы будем через консоль USB-UART: доступ к ней обеспечивается посредством microUSB порта на плате STM32MP157A-DK1. Отображение выводимой информации возможно в любой терминальной программе, например Putty или Minicom. В рамках данной статьи я использовал последнюю, открыв еще одно окошко терминала в Debian.

Теперь вставляем microSD-карточку в отладочную плату, подаем на плату питание и смотрим в терминал. Если все было сделано правильно, то туда должны высыпаться логи FSBL, U-Boot, kernel и в конечном счете – появиться приглашение ввести логин. Вводим root и – вуаля – мы попадаем в консоль системы, которую только что собрали:



Да, в ней нет даже менеджера пакетов и вообще функционал очень скудный, но с помощью Buildroot можно очень здорово его нарастить и создать реально работающую сложную систему. Пока же ее размер составляет всего 7 мегабайт!



Убедившись, что самодельная корневая файловая система успешно запускается, пришло время запустить Arch Linux. Опять вставляем microSD-карту в картридер нашего компьютера и форматируем еще раз пятый раздел карты памяти:

mkfs.ext4 /dev/sdb5

Качаем архив с Arch Linux, собранным под armv7, с официального сайта. Распаковываем архив в директорию archlinux и с помощью команды:

cp -a archlinux/* /media/myuser/rootfs 

Копируем его в раздел rootfs microSD-карты.

Чистим директорию /media/myuser/rootfs/boot: содержимое нам не нужно, потому что ядро и дерево устройств у нас находятся в отдельном разделе microSD-карты:

rm –rf /media/myuser/rootfs/boot/*

Позже в директорию boot можно будет примонтировать раздел /dev/sdb4, где у нас хранится образ ядра.

После этого вставляем microSD-карту в отладочную плату, подаем питание и радуемся работающему ArchLinux:



После того, как Arch Linux успешно запустился, я решил попробовать запустить еще и Debian на отладочной плате. С помощью абсолютно аналогичных манипуляций с корневой файловой системой он успешно заработал:



Заключение


В ходе данной статьи мы вдоволь наигрались с отладочной платой STM32MP157A-DK1: собрали под нее U-Boot, ядро Linux, собственную корневую файловую систему, а также запустили Arch Linux и Debian. Надеюсь, данный материал окажется кому-то полезным как при работе с процессорами семейства STM32MP1, так и с любыми другими одноплатниками на ARM.

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 39

    0
    А с железом игрались? Ethernet тот же работает?
      +2
      Ethernet работает, поддержка по умолчанию включена в ядро. То есть никаких действий не надо будет производить, после загрузки плата подхватит по DHCP адрес и все. Еще проверял UART, USB, GPIO. Что касается USB — тут надо добавить в ядро поддержку того, что именно вы хотите получить. Как добавить поддержку USB-флешек я описал в статье, если вам надо, к примеру, RNDIS — это делается отдельно. Поддержку GPIO тоже добавлял сам ручками, успешно работает.
      0
      при несоблюдении которых процессор мог полностью выходить из строя, причем не сразу, а со временем и в самый неподходящий момент

      Подавали на порты напряжение раньше, чем на сам процессор?

        +2
        Я делал этот проект несколько лет назад, сейчас так сходу все и не припомню. Но из того, что осталось в памяти:
        1) Линию VBUS USB надо подключать к процессору через резистор 1 кОм. Про это нет ни слова в даташитах, но такое включение представлено в отладочных платах производителя. Я не углядел тогда этот момент и в итоге у части модулей выгорел USB. Причем выгорал он ни сразу — у некоторых модулей через месяц после начала эксплуатации, у некоторых через полгода, а некоторые вообще работают до сих пор. В новой ревизии железа я заложил этот резистор и проблем с USB больше не было.
        2) У процессора AM4376 есть один коварный вывод WARMRST. Он вроде как должен использоваться для сброса какой-то внешней периферии после инициализации процессора. Я смотрел осциллографом, на нем действительно в этот момент проскакивает импульс. Я его использовал для сброса WiFi модуля с подтяжкой к питанию WiFi модуля, и вот тут да, возможно, на этот вывод напряжение приходило на несколько десятков микросекунд раньше, чем на процессор. По итогу ситуация была аналогична USB — у одних модулей через неделю, у других через полгода этот вывод выгорал и процессор оказывался неработоспособным. Однако если оставить этот вывод вообще без подтяжки, процессор вообще не запускался. Лучшим решением стало подтянуть в глубине платы этот вывод через 100 кОм к питанию процессора и забыть про него, а для сброса модулей использовать GPIO. В новой ревизии так и было сделано, за несколько лет ни одной аналогичной проблемы не возникло.
        3) Следует помнить, что USB у техаса по умолчанию High Speed (это который 480 Мбит/с). Со всеми требованиями к разводке дифпар.
          0
          надо подключать к процессору через резистор 1 кОм

          Может быть у вас VBUS просто превысил Absolute Maximum Ratings? Резистор в таком случае не даст выпалить схему при превышении напряжения.


          на этот вывод напряжение приходило на несколько десятков микросекунд раньше, чем на процессор

          Скажем, это проблема не только Sitara, ну и камней других производителей (NXP i.MX6UL как пример). Нежный техпроцесс, все дела.


          по умолчанию High Speed

          Так отключаемый же

            +1
            Может быть у вас VBUS просто превысил Absolute Maximum Ratings? Резистор в таком случае не даст выпалить схему при превышении напряжения.

            Если мне не изменяет память, то этот параметр для VBUS техаса равен 5,5 В. Ну, то есть как у большинства других устройств, работающих с USB. Кроме обычных ПК и ноутбуков никуда девайсы больше не подключались. При этом, в эти же самые ПК и ноутбуки подключались и другие устройства. Однако сгорал только USB техаса, и все стабилизировалось после установки этого резистора. Так что склонен думать, что дело именно в нем.

            Скажем, это проблема не только Sitara, ну и камней других производителей (NXP i.MX6UL как пример). Нежный техпроцесс, все дела.

            Кстати, там напряжение даже шло не напрямую, а через 10 кОм, даже это не спасало)

            Так отключаемый же

            Да, после того как загрузилась система. Однако если вы используете загрузку прошивки через USB с использованием встроенного бутлоадера, то, если я все правильно понял, все равно придется работать с High Speed.

        0

        Apt запустили на железе?

          0
          Конечно, ради него же все и затевалось :) Apt запустился на Debian (там про него в конце статьи пару строк). На Arch Linux вместо него pacman, тоже запустился после небольшой пляски с бубном, но с ним всегда так.
          0

          Эм… как раз таки файл dtb позволяет спокойно загружать и использовать дистрибутивы linux под практически любой ARM ну при условии конечно что поддержка есть в mainline ядре. Достаточно подсунуть правильный dtb.


          А u-boot где на плате живет? Или он с sdcard подгружается? И нет ли уже собранного у производителя? А то иначе если поддержка в mainline ядре есть, то сводится к положить u-boot настроить его подпихнуть dtb kernel и rootfs

            0
            Эм… как раз таки файл dtb позволяет спокойно загружать и использовать дистрибутивы linux под практически любой ARM ну при условии конечно что поддержка есть в mainline ядре. Достаточно подсунуть правильный dtb.

            Да вот я тоже был уверен, что это так. Поэтому первым делом и попробовал взять готовый dtb и подсунуть U-Boot ядро из дистрибутива Arch Linux. Однако все зависло на этапе Statring kernel… При этом ядро, собранное Buildroot, с тем же самым dtb успешно загружалось. Подозреваю, что проблема в адресах, куда кладется dtb и ядро. Однако пока не сумел разобраться. В исходниках dts вообще этих адресов не обнаружил. Буду благодарен, если вы можете сказать, куда следует копать.
            А u-boot где на плате живет? Или он с sdcard подгружается? И нет ли уже собранного у производителя? А то иначе если поддержка в mainline ядре есть, то сводится к положить u-boot настроить его подпихнуть dtb kernel и rootfs

            Да, и u-boot, и fsbl живут на sdcard. Про это написано в статье, да и другой памяти просто нет на плате)
            У производителя есть репозиторий на GitHub, там есть исходники U-Boot. Однако я собирал U-Boot из официального репозитория, работает не хуже))
              0
              Однако все зависло на этапе Statring kernel…

              Указывает на отсутствие dtb :) Не нашло dtb вот и результат. Там надо опции крутить в u-boot. Сначала надо грузить dtb потом kernel а потом же делать boot. Иначе будет такой вот ой.

                +1
                Суда по строчкам типа «Loading Device Tree to cffec000, end cffff94a» перед Statring kernel, все-таки dtb он находит) Ну и я проводил эксперимент: брал один и тот же U-Boot, один и тот же скрипт загрузки, один и тот же dtb и менял только zImage. Если я брал zImage из дистрибутива Arch Linux, то все зависало на Starting kernel. Если брал zImage, собранный Buildroot — успешно запускалось. Подозреваю, что дело все-таки в адресах, куда грузится dtb. Возможно, ядро Arch Linux ищет дерево устройств не в том месте.
                  +1

                  Скорее всего в адресах проблема да.

            0

            Спасибо. Полезно.
            Лежит плата на STM32MP157A
            Буду на ней управление станком чпу делать. С 5" экраном где громе текстовой инфы планирую 3Д отрисовку работы. Доступ по wifi. А то готовое что предлагают китайцы либо убого, либо запредельно дорого.
            На м3 ставит ос нецелесообразно, а вот на м7 это уже может быть удобно в решении моей задачи чем писать прошивку с "0".
            Но пока даже не рыл в эту сторону. Пока делаю механику станка.

              0
                +1

                Спасибо, но цнц мне не подходит. У меня grbl.
                Распберри рассматривал, но отсутствие ацп неприемлимо. Нужно.

                  0

                  Обычно проще второй контроллер с АЦП поставить и малинку.

                    0

                    Да, ставят. Но:
                    1) Ставить более дорогой и более мощный девайс чтобы его потом еще и наращивать…
                    2) Между тем, что лежит в коробке с контроллерами "на всякий случай" и тем, что нужно покупать и ждать ещё больш_я разница.
                    3) В этой коробке еще esp пара и Atmel на Cortex-M3 лежит, но я решил иметь запас по производительности.
                    :)

                      0
                      Характеристики встроенного АЦП очень отвратные, как правило. Тогда уж поставить АЦП на SPI. Цена не сильно меняется, а плюсов много.
                        0

                        Согласен что не очень. О мерить выход датчика тока asc достаточно. Это ток шпинделя мерить, чтоб останавливать программу при закусывании и т п.

                    0
                    Математику на Малинке, а жесткий realtime — на голом железе. В принципе, как понимаю, в этом вся «фишка» главного героя статьи (я про SoC). На семерке (A7) — ось + математика крутится, на M4 — жесткий реалтайм. Давно использую такие связки ПК (все, что с полноценной ОС, от Винды до Openwrt) + контроллеры. Думаю, с 0 такой контроллер сделать почти не реально в «одни руки», очень долго. Можно взять за основу «Марлин», ту часть, которая за G-CODE отвечает. И был такой проект CNCLinux вроде назывался, не помню, лет 10 назад этим интересовался. Удачи Вам!
                      0

                      Да, оптимальный вариант.
                      С "0" можно. Библиотеки все есть. Парсер г кода, отрисовки задания, подсчет времени выполнения.
                      Я еще свое по результатам опыта хочу добавить:
                      1) Управление оборотами (а не мощностью как обычно) шпинделя
                      2) Контроль тока шпинделя. Если закусит, то экстренный стоп задания с запоминанием координат (позиционирование еще тот геморрой)
                      Ну и мого еще по мелочи.

                +1
                Вы не совсем правы. Сборки «готовых» дистров Debian есть и есть давно(и даже Ubuntu) и подробные инструкции, как их использовать :-)
                github.com/meta-debian/meta-debian
                rcn-ee.com/rootfs/eewiki/minfs
                  0
                  Не стану этого отрицать, возможно, где-то и лежать на просторах интернета, но так сходу мне найти не удалось. Да и просто было интересно поковырять поглубже этот процессор :)
                  +1
                  В таблице ошибка 151 не имеет CAN интерфейса
                    0
                    Да, действительно так. Спасибо за внимательность, таблицу подправил.
                    0
                    А как в этих процессорах организуется работа с разными архитектурами?
                    Ну, ведь М4 и А7 — весьма разные архитектуры и приемы работы с ними, соответственно, тоже разнятся. Я как привык с M4 — в CubeMX раскидать начальные настройки, а потом работать уже с bare metal, на крайняк с примитивной ОСРВ.
                    В случае же с линукс все совсем иначе. Как раз как в статье описано.
                    Вот и интересно, как работать с этими архитектурами одновременно? В статье про М4 ни слова, все про «более крутые» процессоры…
                      0

                      Ну все обычно просто: пингвин инициализирует железо, инициализирует маленькое ядро, закачивает в его оперативку программу и стартует его. Дальше по работе уже ничем не отличается. В зависимости от крутости камня сопроцессор может быть закрыт IOMMU (как DSP у TI AM5728), а может и нет (система PRU-ICSS на TI AM3358). Код от "большого" процессора для работы с периферией подходит и наоборот. А что, и то, и то — армы, и оба 32-разрядных.

                        0
                        Хороший вопрос! Здесь на Хабре была статья как раз на эту тему. Там подняли обмен между ядрами посредством виртуальных UARTов. Но у меня пока что не дошли руки это попробовать)
                          0

                          У здоровых людей для этого используется rpmsg


                          А, так в статье про него и речь. Хотя название "виртуальный UART" — это слишком

                          0
                          Доводилось работать с imx8 в котором есть m4 ядро в дополнение к A35. Там прошивка для m4 загружается u-boot в определенную область ОЗУ после чего запускается m4 ядро. Общение между ядрами через общую память. Есть модуль что может послать другому ядру прерывания. Поверх этого есть поддержка протоколоа rpmsg для обмена сообщениями через общую память. Переферия теоретически доступна обоим ядрам, есть специальный набор регистров где выставляются биты разрешения доступа к тому или иному блоку отдельно для Cortex A ядер и Cortex M ядра.
                          0
                          Итак, смотрим директорию u-boot/arch/arm/dts. В ней должен быть файл stm32mp157a-dk1.dtb


                          В этой директории есть только файлы .dts, .dtb нету. Может вы ошиблись?
                            0
                            dts — исходные файлы дерева устройств, а dtb — результат их компиляции. Попробуйте выполнить сборку U-Boot, после первой сборки у вас в этой директории появятся файлы dtb.
                              0
                              Да, после сборки он появится, но вы то описываете процесс подготовки к сборке, а на этом этапе его ещё нет. Я про это хотел сказать, и наверное стоит исправить.
                                0
                                Да, это так. Внес в статью соответствующее примечание. Спасибо.
                                  0
                                  Спасибо. И спасибо за статью, благодаря ей у меня что-то сдвинулось с мертвой точки. Сложноватая плата.

                                  Будет ли продолжение про взаимодействие с М4?
                                    0
                                    Про взаимодействие с M4 я давал ссылку на статью с Хабра чуть выше в комментариях. У меня пока что не стояло задачи работы с этим ядром, но если дойдут руки и там будет что-то интересное — возможно, об этом тоже будет статья.
                            +1
                            Отличная статья. С удовольствием ознакомился. Сам вожусь с DK2, статью мою здесь упомянули. :) <Вот эта «habr.com/ru/post/493884»> Но пока выйти на построение нормального графического интерфейса не получается. В сборке OpenLinux, которая в Стартер пакете, используется Wayland, писать графику можно на GTK. Но у меня не получилось корректно управлять положением окон на экране. Написал на Community, пока нормального ответа не пришло :( community.st.com/s/question/0D53W000004JZeGSAW/gtkwindowmove-does-not-work-
                            Поставил сборку на основе графического сервера Х11. Не получается связаться с сервером. :( community.st.com/s/question/0D53W0000080dmqSAA/i-have-2-problems-on-installed-stexampleimagex11
                            Пока в раздумьях, что же делать дальше. :)

                              0
                              Спасибо!
                              С графикой на этом процессоре пока не имел дело, у меня отладка без дисплея, но если вам удастся её поднять — с удовольствием прочитаю статью на эту тему :)

                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                            Самое читаемое