Расширение языка C для MicroPython на Raspberry Pi Pico
Это руководство о том, как написать и запустить базовое расширение на языке C для MicroPython на Raspberry Pi Pico. Я расскажу о причинах расширения MicroPython, о том, как написать модуль расширения, как его скомпилировать и как установить на Pico. Если вы хотите прочитать больше об этой теме, пожалуйста, обратитесь к разделу https://docs.micropython.org/en/latest/develop/extendingmicropython.html
Введение
Зачем расширять MicroPython?
Причин, по которым вам может понадобиться расширение MicroPython, может быть несколько. Поскольку это урезанная версия Python, MicroPython не очень хорошо справляется с тяжелыми вычислительными задачами (как и Python). С другой стороны, язык C действительно хорошо подходит для таких задач. Расширение C для Micropython позволяет выполнять такие вычисления на языке C и использовать результаты в MicroPython. Это может ускорить некоторые процессы на порядок.
Вторая причина может заключаться в том, что вы хотите взаимодействовать с каким-либо оборудованием, использующим API на языке C, из MicroPython.
Типы расширений MicroPython C
Существует несколько различных способов расширения MicroPython: внешние модули на языке C и собственный машинный код в файлах .mpy.
Чтобы запустить внешний модуль на языке C, необходимо перекомпилировать его в микропрограмму MicroPython. Это довольно сложный процесс, поэтому в данном руководстве мы остановимся на втором варианте. Если вас заинтересовал этот подход, вы можете прочитать о нем подробнее на этих веб-страницах: https://docs.micropython.org/en/latest/develop/cmodules.html https://www.raspberrypi.org/forums/viewtopic.php?t=300352
Файл .mpy - это файл, который хранит скомпилированный собственный машинный код и может быть скомпонован динамически. Это делает его гораздо более гибким, поскольку вам не нужно перекомпилировать всю прошивку MicroPython.
Напишите модуль расширения
Написание модуля расширения - это самая простая часть расширения MicroPython. Я покажу вам, как это сделать, на простом примере. Для начала мы создадим новый каталог под названием фактфиб. Откройте новое окно терминала, перейдите в новый каталог и создайте новый файл с именем factfib.c. Если вы создали каталог на Raspberry Pi под Dekstop, команда выглядит следующим образом.
cd ~/Desktop/factfib
touch factfib.c
Открыть factfib.c в вашем любимом текстовом редакторе и введите следующий код:
#include "py/dynruntime.h
STATIC mp_int_t factorial_helper(mp_int_t x) {
if (x < 1) {
return 1;
}
return x*factorial_helper(x-1);
}
STATIC mp_obj_t factorial(mp_obj_t x_obj) {
mp_int_t x = mp_obj_get_int(x_obj);
mp_int_t rslt = factorial_helper(x);
return rslt;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial);
STATIC mp_int_t fibonacci_helper(mp_int_t x) {
if (x <= 0) {
return 0;
}
else if (x == 1) {
return 1;
}
else {
return (fibonacci_helper(x-1) + fibonacci_helper(x-2));
}
}
STATIC mp_obj_t fibonacci(mp_obj_t x_obj) {
mp_int_t x = mp_obj_get_int(x_obj);
mp_int_t rslt = fibonacci_helper(x);
return mp_obj_new_int(rslt);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fibonacci_obj, fibonacci);
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
MP_DYNRUNTIME_INIT_ENTRY
mp_store_global(MP_QSTR_factorial, MP_OBJ_FROM_PTR(&factorial_obj));
mp_store_global(MP_QSTR_fibonacci, MP_OBJ_FROM_PTR(&fibonacci_obj));
MP_DYNRUNTIME_INIT_EXIT
}
Позвольте мне объяснить приведенный выше код: В MicroPython и Python каждая переменная является объектом. Поэтому в Си мы представляем их как mp_obj_t. Но программа на языке Си может работать только с переменными типа Си, поэтому нам нужно преобразовать объект в тип Си. Это называется Marshalling, и MicroPython предоставляет функции для извлечения любого C-типа из объекта.
Эта веб-страница Оливера Робсона очень полезна для маршалинга https://mpy-c-gen.oliverrobson.tech/. Кроме того, вы можете найти примеры маршалинга в документации MicroPython https://docs.micropython.org/en/latest/develop/natmod.html. Я советую вам прочитать эту статью, если вам нужны дополнительные объяснения.
Постройте пристройку
Мы собираем расширение в файл .mpy с помощью Makefile. Но сначала нам нужно настроить несколько вещей. Убедитесь, что ваш терминал все еще открыт в фактфиб каталог. Затем клонируйте репозиторий MicroPython на GitHub.
sudo apt-get install build-essential libreadline-dev libffi-dev git pkg-config gcc-arm-none-eabi libnewlib-arm-none-eabi
git clone --recurse-submodules https://github.com/micropython/micropython.git
pip3 install 'pyelftools>=0.25'
Эти установки займут некоторое время, но если вы хотите сэкономить время и знаете, что делаете, вам нужно только клонировать директории /py и /tools из репозитория micropython и поместить их в папку micropython папку внутри фактфиб папку (пропустите вторую команду).
Пока идет установка, мы можем использовать это время для написания Makefile. Просто выполните
touch Makefile
и откройте только что созданный файл в текстовом редакторе.
MPY_DIR = micropython
MOD = factfib
SRC = factfib.c
ARCH = armv7m
include $(MPY_DIR)/py/dynruntime.mk
Вы могли заметить, что мы установили ARCH переменная для armv7m хотя пико - это armv6m. Мы должны это сделать, потому что armv6m архитектура (на момент написания этой статьи) не поддерживается программой dynruntime.mk инструмент.
Но, к счастью, мы все еще можем скомпилировать рабочее расширение для Pico. Нам просто нужно изменить dynruntime.mk файл, который должен быть расположен в разделе micropython/py/dynruntime.mk. Откройте его и в разделе Architecture configuration в armv7m найдите переменную CFLAGS (это должна быть строка 64). Измените -mcpu=cortex-m3 на -mcpu=cortex-m0 и сохраните файл.
Затем, после того как все будет установлено, выполните
make
и фактфиб.мпи будет создан файл.
Установите и протестируйте расширение
Последний шаг - установка и тестирование. Для этого мы используем файловую систему, которую Micropython создает на Raspberry Pi Pico. Сначала нам нужно прошить Pico прошивкой MicroPython. Самый простой способ сделать это - использовать Thonny IDE (предустановленную на Raspbian/Raspberry Pi OS).
Если вы не используете Raspberry Pi для программирования Pico или если вы никогда раньше не использовали MicroPython на Pico, обратитесь к руководству по началу работы с MicroPython от Raspberry Pi. https://www.raspberrypi.org/documentation/rp2040/getting-started/#getting-started-with-micropython
Если вы используете Windows, вам стоит ознакомиться с этой статьей блога о Raspberry Pi Pico и MicroPython под Windows https://picockpit.com/raspberry-pi/raspberry-pi-pico-and-micropython-on-windows/
Закройте Thonny после прошивки Pico прошивкой MicroPython и установите rshell. Мы используем rshell для доступа к файловой системе из командной строки.
sudo pip3 install rshell
rshell --version
Это выведет версию rhsell, если все настроено правильно. Затем отключите pico и подключите его снова (не удерживая кнопку BOOTSEL), чтобы убедиться, что ничто не пытается получить доступ к файловой системе. Теперь нам нужно выполнить
rshell -p /dev/ttyACM0 --buffer-size 512
cp factfib.mpy /pyboard/factfib.mpy
Для проверки установки можно использовать либо rshell, либо Thonny IDE для сохранения вашего .py файлы на Pico, но я продемонстрирую, как использовать интерпретатор MicroPython на minicom.
Поэтому сначала нажмите Ctrl+c выйти из rshell и затем установить minicom через
sudo apt install minicom
теперь мы можем получить доступ к Picos REPL (цикл чтения-вычисления-печати)
minicom -o -D /dev/ttyACM0
Три закрывающие угловые скобки >>> указывают на то, что запущен интерпретатор MicroPython. Теперь мы можем импортировать наше расширение и работать с ним как обычно.
>>> import factfib as ff
>>> ff.factorial(5)
>>> 120
>>> ff.fibonacci(7)
>>> 13
Поздравляем! Вы создали свое первое расширение MicroPython C для Pico! Следующий шаг - научиться писать и компилировать более сложные модули. Хороший способ начать - проверить, как работает маршаллинг списков и массивов (см. веб-страницу "Маршаллинг" выше).
Если у вас возникли вопросы по поводу этой заметки, не стесняйтесь написать комментарий.
Если не считать ошибки в программе на c, все работает отлично. Спасибо.
STATIC mp_obj_t factorial(mp_obj_t x_obj) {
mp_int_t x = mp_obj_get_int(x_obj);
mp_int_t rslt = factorial_helper(x);
return mp_obj_new_int(rslt);
}
Спасибо за ваш отзыв 🙂
Как настроить joomla так, чтобы она могла получать данные из mysql?
Я пытался сделать вышеописанное, но разные вещи не работают так, как описано:
- Я следовал инструкциям выше, получил micropython, изменил makefile как описано
- Я делаю (но получаю файл factfib.native.mpy вместо factfib.mpy)
- Я копирую файл factfib.native.mpy в pico как factfib.mpy
(Я попробовал rshell, но получил "timed out or error in transfer to remote: b"", но я смог скопировать его с помощью Thonny)
- Я могу импортировать модуль (в thonny или rshell - одно и то же) без ошибок
- Я пытаюсь запустить "ff.fibonacci(5)", но затем получаю:
" Traceback (последний последний вызов):
Файл "", строка 1, в
AttributeError: объект 'module' не имеет атрибута 'fibonacci'".
Что я делаю не так?
В конце концов, вам удалось заставить его работать?
Теперь вы можете компилировать под armv6, поэтому просто измените эту строку в Makefile и не нужно менять код micropython
ARCH = armv6m
У меня возникло несколько ошибок при компиляции factfib.c, где есть исправления:
// не хватает " в конце.
#include "py/dynruntime.h"
// преобразуйте возвращаемое значение в mp_obj_t
STATIC mp_obj_t factorial(mp_obj_t x_obj) {
mp_int_t x = mp_obj_get_int(x_obj);
mp_int_t rslt = factorial_helper(x);
return mp_obj_new_int(rslt);
}
Спасибо за информацию, Пауло!
Я следовал всем инструкциям и в итоге получил собранный файл facfib.mpy. Я использовал
ARCH = armv6m
При загрузке в Pico я получаю эту ошибку:
ValueError: несовместимый файл .mpy
Для моего Pico требуются следующие значения mpy:
версия mpy: 6
mpy sub-version: 2
Флаги mpy: -march=armv6m
Проверка первых двух байтов файла дает версию 6 и подверсию 6.
Есть ли способ исправить это, пожалуйста?