- PVSM.RU - https://www.pvsm.ru -
Cегодня редко встретишь разработчика, который хоть раз бы не слышал о Rust. После долгого хайпа и зародившегося мема RIIR (rewrite it in Rust - перепиши это на Rust) ажиотаж вокруг языка как будто бы поутих. Но оказалось, все и вправду по-тихому переписывается на Rust (если мой дебют не утонет в минусах, постараюсь написать статью-исследование на тему, где уже Rust надежно поселился в системе).
Первое, что меня впечатлило - это статья, что вся инфраструктура Cursor написана на Rust в целях экстремальной производительности, и языкс этой задачей, как видно, прекрасно справляется. Второе, что и сподвигло не только читать о Rust, но и начать на нем писать, — это, конечно же, дефицит комлектующих. «640 КБ на самом деле хватит всем» и интерес пал на братьев наших меньших — микроконтроллеров. Вот где действительно можно прочувствовать всю необходимость оптимизации.
Конечно, знакомство с Rust, как и у всех, началось с классики — Rust boo k [1] для новичков и Embedded Rust [2] для желающих окунуться вразработку встроенных систем. В Rust Book новичкам предлагается написать простую программу Guessing Game — приложение, которое загадывает число, а «игрок» должен попытаться его угадать.
Но просто читать не так интересно как набивать свои собственные шишки, поэтому, вооружившись книгами, документацией, все еще живым StackOverflow и Gemini в качестве ментора, я решила объединить эти два мира и сделать Guessing Game на STM32.
Далее хочу предложить небольшой гайд (или просто объяснение кода) из того, в чем удалось разобраться.
Первое, что нужно для реализации идеи, конечно, же сам микроконтроллер. В моем случае это STM32L476RG (Nucleo) [3].
Второе - нам нужен экран, куда мы будем выводить информацию. Еще со времен бловства с Ардуино у меня осталась целая коробка разных приблуд, в том числе и LCD с I2C адаптером [4]. Он и был выбран в качестве основного дисплея.
И последнее - возможность взаимодействовать с программой. Из того же набора я взяла IR receiver [5] и "Car MP3 [6]" пульт.
Дополнительно потребуется breadboard (Макетные платы для монтажа в гнёзда [7]) для удобного соединения IR receiver (и несколько джамперов для соединений). В моем случае борда также была в наборе Ардуино.
Для моей платы был нужен кабель USD A-mini B.
Подключаем плату черезUSB к компьютеру (не забываем, что платы чувствительны к статике, предварительно «заземляемся» об что‑то чтобы не разрядиться на плату). Я использую Linux Ubuntu, потому могу расписать алгоритм действий для этой ОС. Для других ОС алгоритм может отличаться.
Проверяем видит ли компьютер подключенную плату, для этого пишем в консоли: lsusb | grep STM. Должно быть видно что-то типо "STMicroelectronics ST-LINK/V2.1".
Устанавливаем инструмент для работы с STM32 и обновляем правила для работы с USB:
sudo apt update
sudo apt install stlink-tools
sudo udevadm control --reload-rules
sudo udevadm trigger
Быстро проверяем работает ли плата:
echo "test" > test
st-flash write test 0x8000000
Находим LD1 и LD3 на плате и смотрим за их поведением. LD3 должен гореть красным, а LD1 либо гореть красным, либо мигать пока в микроконтроллер записывается программа.
Затем отключаем плату от компьютера и переходим к подключению пинов.
Здесь имеется 4 пина: SDA (перенос данных), SCL (пин синхронизации), VCC (питание) и GND (заземление).
На STM32, как правило, пины хорошо подписаны, потому ищем такие же пины на плате: SCL/D15/PB9, SDA/D15/PB8, +3V3 и GND. Соединяем между собой:
SDA дисплея c SDA на STM32
SCL с SCL
VCC с +3V3
GND c GND
IR приемник обычно выглядит как светодиод, но черного цвета и в корпусе. Смотрим на его "лицевую сторону". Самый левый пин будет пином выхода данных, средний - GND и правый - VCC. Подключаем левый пин к PA0 на STM32 (он может еще называться A0). Средний - к GND на плате и VCC - к +3V3. Вот тут может понадобиться breadboard, чтобы использовать общий +3V3.
Репозиторий [8].
Для дальнейшей работы должен быть установлен Rust и Cargo (если нет - следуйте официальному гайду для вашей ОС тут [9]).
Первым делом мы должны обозначить build target для правильной компиляции для нашего микроконтроллера, для этого пишем в консоль rustup target add thumbv7em-none-eabihf
Что важно знать - мы работаем без std и привычного main.
В качестве основного драйвера системы я использовала Embassy [10] как асинхронный и энергоэффективный фреймворк. Возможно это и оверкилл для моей программы, но хотелось разобраться в чем то еще дополнительном по мере реализации идеи. К тому же спользование Embassy освобождает от необходимости создавать файл memory.x с указанием параметров flash и ram памяти, так как после указания в Cargo.toml файле для зависимости embassy-stm32 в features "memory-x" и своей STM32 платы (stm32l476rg) фреймворк сам создает эту информацию "под капотом".
main.rs для встроенный систем начинается со строк:
#![no_std]
#![no_main]
Что происходит в main:
инициализации периферии STM32 c конфигурацией внутренних часов, соответсвующих циклу приема-передачи IR приемника и пульта "Car MP3" (поддерживает протокол NEC), т.к. для корректного декодирования сигнала с пульта нужны корректные циклы отправки-приема сигнала с конкретными паузами. Любой рассинхрон или задержка сигнала приводит к ошибкам декордирования
инициализация модуля дисплея
инициализация модуля инфракрасного приемника
создание асинхронной задачи для декодирования полученного с пульта сигнала
запуск игры
отлов ответа "игрока" и отображения статуса игры на дисплее (запущенное в цикле)
использование Channel c мьютексом для передачи данных между командой с пульта и циклом игры (для получения и сравнения ответа от "игрока")
Далее пройдемся по файлам:
GameInput представляет собой простой enum поддерживаемого игрой ввода
Game - модуль игры, основа которого создавать случайное число и проверять статус игры
LCD - модуль инициализации hd44780 драйвера и функции взаимодействия с экраном - стирать данные, писать в первую строку, писать во вторую строку
RC - инициализация инфракрасного приемника и маппинг команд с пульта (предварительно цифровой код каждой кнопки был вручную отловлен с помощью дебага). Самая сложная функция здесь — декодирование сигнала. Используются расчеты delta time для процесса декодирования и сравнение время нажатия кнопки с некоторым временным промежутком относительно последнего нажатия для предотвращения «залипания» кнопки.
Отдельного внимания заслуживает файл .cargo/config.toml, где указывается как правильно запускать программу, с какими флагами и для какой платформы, что позволяет в дальнейшем запускать программу просто командой cargo run.
клонируем репозиторий и перемещаемся в корневую папку проекта в терминале
подключаем плату через USB
прогоняем cargo run в терминале
смотрим на LCD, где должно отобразиться «Guess 1 to 100». Если дисплей горит, но ничего не показывает, возможно необходимо подкрутить отверткой потенциометр сзади дисплея пока не станут видны буквы.
жмем кнопки 0–9 на пульте, подбирая число. Отправить — кнопка >>|, стереть одну цифру — кнопка |<<, перезапустить игру — кнопка >||.
Я новичок в Rust и Embedded и осознаю, что для более опытных разработчиков встроенных систем недочеты будут резать глаз. Надеюсь на конструктивные замечания в комментариях, а также на то, что мой краткий гайд/обзор окажется полезным для таких же новичков как и я, чтобы вдохновиться на свои проекты на Rust и Embedded.
Автор: a113ssa
Источник [11]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/guide/446035
Ссылки в тексте:
[1] Rust boo k: https://doc.rust-lang.org/book/
[2] Embedded Rust: https://docs.rust-embedded.org/book/
[3] STM32L476RG (Nucleo): https://www.st.com/en/evaluation-tools/nucleo-l476rg.html
[4] LCD с I2C адаптером: https://raw.githubusercontent.com/a113ssa/embedded-rust-guessing-game/main/doc_assets/lcd_i2c_pin_schema.png
[5] IR receiver: https://camo.githubusercontent.com/d260cd0647316df2270fe60d8ce7cd02e9a04db5d018771ea32d7e5580313815/68747470733a2f2f717866322e636f6d2f626c6f672f77702d636f6e74656e742f75706c6f6164732f323031382f30332f69722d72656365697665722e6a7067
[6] Car MP3: https://camo.githubusercontent.com/f87830a6670bc4d509ffe31e2176165b85d24edb7956366c004a0563e939c49f/68747470733a2f2f656c656374726f6e6174696f6e2e706b2f77702d636f6e74656e742f75706c6f6164732f323032332f30352f3337332d4d50332d556e6976657273616c2d52656d6f74652d312e6a7067
[7] Макетные платы для монтажа в гнёзда: https://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D0%BA%D0%B5%D1%82%D0%BD%D0%B0%D1%8F_%D0%BF%D0%BB%D0%B0%D1%82%D0%B0
[8] Репозиторий: https://github.com/a113ssa/embedded-rust-guessing-game
[9] тут: https://rust-lang.org/tools/install/
[10] Embassy: https://github.com/embassy-rs/embassy
[11] Источник: https://habr.com/ru/articles/1004996/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1004996
Нажмите здесь для печати.