Что можно собрать на основе микроконтроллеров RISC-V? Открытая архитектура уже достаточно развита, чтобы в короткие сроки реализовать с ее помощью интересные прототипы для разных сфер применения — причем с потенциалом для дальнейшего развития. В статье мы разберем несколько таких проектов, которые удалось подготовить в сжатые сроки. Каждый из них занял у создателей — еще начинающих специалистов — всего пару недель.

Эти проекты были созданы по итогам последнего потока курса YADRO по программированию микроконтроллеров на RISC-V. Программа рассчитана на студентов второго курса и старше. Для поступления требуется некоторый опыт программирования на C, владение Linux и Git, базовые знания об электронике и цифровой схемотехнике. А также свободное время — минимум 4–6 часов в неделю в течение трех месяцев.
Базовая программа лекций:
Знакомство и введение в программирование микроконтроллеров RISC-V.
Компиляция, загрузка и исполнение программ.
Регистры и периферия.
Введение в ассемблер. Основы RISC-V ISA.
Микроархитектура RISC-V.
Таймеры и прерывания.
Основы работы с аналоговыми сигналами. АЦП и ЦАП.
Цифровые интерфейсы передачи данных (в двух частях).
Системы сборки.
Тестирование и TDD.
В ходе обучения мы стремились выйти за пределы стандартных программ эдтех-курсов и дополнительно привить навыки, которые помогут в инженерной практике. Настройка linker script, код на ассемблере, мейкфайлы, организация передачи данных, обертка в протоколы, сборка ПО в отрыве от IDE — это лишь несколько из обширного списка дополнительных тем. Его формируют преподаватели курса — действующие инженеры YADRO с обширным опытом работы.
На первом занятии эксперты рассказали, какие компетенции потребуются для дальнейшей работы, и затем максимально приблизили обучение к реальной разработке с помощью Git. Так что без челленджей не обошлось: у студентов ушло немало времени, чтобы сделать реализацию 1-Wire с помощью UART. В итоге за три месяца ребята освоили основную программу, достаточную для самостоятельных проектов, и получили направления для дальнейшего развития — например, в RTOS, test-driven development и в высокоскоростных протоколах.
Теперь — к итоговым проектам курса, прототипам на контроллерах RISC-V. Для них было отведено две недели, за которые также нужно было написать тесты, так что некоторые студенты не успели реализовать все задуманное. Но как минимум получили рабочие прототипы, выполняющие все или почти все запланированные функции.
Секвенсор
Иван Тарасов собрал музыкальный секвенсор. С помощью пульта в нем можно выставить темп (от 60 до 255 bpm) и ноты в диапазоне трех октав внутри 16 ячеек. Из дополнительных функций — повтор последней добавленной ноты одной кнопкой.

В проекте Иван хотел использовать ШИМ и прерывание, но ШИМ замирала, если ноты быстро меняли высоту — причем на две-три минуты через секунд пять воспроизведения. В финальной версии секвенсор работает через синхронное прерывание, так что чем больше нот заполнено в сетке, чем сложнее остановить воспроизведение. Для отрисовки сетки нот из прямоугольников была реализована библиотека с нуля — без использования сторонних решений.
Тамагочи
Александр Сергеев создал виртуального питомца, тамагочи, реагирующего на внешнюю среду. Интересно, что проект он решил реализовать на C++ вместо C.
В C++ существует конструктор — функция, которая начинает lifetime любого объекта. При создании глобального объекта конструктор будет вызываться в секцию init, а деструктор — в секцию fini. Но в стандартной реализации linker script для MIK32 нет ни одной из этих секций. В start.c же есть init и fini, но отсутствует поддержка spi и выбора секции загрузки кода. В итоге было написано оригинальное решение на основе linker script для MIK32 и переписанных для них start.c.
После этой и нескольких других проблем по ходу проекта Александр перешел к написанию графической библиотеки, так как хотел вручную рисовать объекты на экране. Ассеты нужно было хранить, но тратить при этом по байту на каждый пиксель экрана не хотелось. Поэтому разработчик создал bitarray с помощью array и vector <bool>. Подчеркивание было определено как 0, а X — как 1. В итоге стало возможно рисовать картинки прямо в файле кода, без кодировщиков:

Canvas здесь хранит байты эффективно — по 8 пикселей на байт. Но init-list, что как раз заключен в фигурные скобки, хранится в сыром виде. Конструктор canvas вызывается только в runtime, а до этого момента init-list придется как-то хранить. Решением стал constexpr — с ним сжатый, оптимальный по размеру canvas сохраняется в памяти без оверхедов. В итоге удалось сохранять картинки разрешением вплоть до 128×64.

В графическую библиотеку также вошли:
progress_bar и indicator_bar, демонстрирующие состояние тамагочи,
image view для отрисовки ассетов на canvas,
container — тип суммы графических примитивов для группировки нескольких объектов в один более высокоуровневый,
tabs — показывает один из объектов в зависимости от своего индекса.
Последние два элемента образовали дерево вложенных объектов с позиционированием внутренних элементов относительно их родителей:

Функциональность виртуального питомца весьма богата:
Внутренние часы, реализованные через прерывания.
Датчик температуры — при слишком высокой или низкой температуре у тамагочи сокращается здоровье.
Датчик освещения — по внутренним часам днем должно быть светло, а ночью темно, иначе тамагочи теряет энергию. При нуле энергии начинает уменьшаться здоровье.
Многофункциональная кнопка для повышения счастья, которое восстанавливает здоровье.

Портативная игровая консоль
Вадим Новиков решил реализовать игровую физику в условиях bare metal, используя свой предыдущий опыт на C++/SFML. В проекте использовалась плата Elbear Ace-Uno на базе микроконтроллера MIK32 АМУР, SPI OLED-дисплей SSD1306 разрешением 128×64 и джойстик HW-504 (KY-023), а также модули SPI (цифровой интерфейс передачи данных), аналого-цифровой преобразователь для калибровки и чтения положения джойстика и GPIO для вывода настройки и ввода состояния кнопки.
Код на C включал непрозрачные типы, которые позволяют реализовать подобие инкапсуляции из ООП. С ними можно объявить в заголовочном файле указатель на некую структуру, но не определять ее. А в единственной трансляции определить структуру и статические функции для взаимодействия с внутренними полями, которые недоступны извне. И поместить туда, соответственно, реализацию открытого интерфейса. Вместо использования регистров напрямую Вадим подключил библиотеку hardware abstraction layer (HAL), чтобы впоследствии было проще портировать проект на STM32 и другие микроконтроллеры.

Результатом работы стала Asteroids — реинкарнация классической игры эпохи аркадных автоматов. Корабль игрока непрерывно выпускает снаряды. После столкновений снаряда с астероидом исчезают оба объекта, при столкновении с кораблем — только астероид. Астероиды, вышедшие за нижнюю границу, возвращаются сверху экрана. Корабль же выйти за границы экрана не может.
Радар с возможностью подключения к ПК
Проект Егора Соколова — ультразвуковой дальномер, который измеряет расстояние до объектов в диапазоне от 2 до 400 см.


Работа с сервоприводом радара организована через ШИМ. Для поддержки дальномера HC-SR04 Егор сам написал простую библиотеку. Дисплей связан по протоколу I²C, взаимодействие с ПК организовано по UART через прерывания. Возможна автономная работа и без компьютера, тогда все данные отображаются на отдельном дисплее.

Радар с выводом сектора на OLED-экран
Василий Сарапулов реализовал радар несколько иначе.

Для работы с дисплеем Василий портировал HAL-библиотеку STM32 для MIK32, написал библиотеки для датчика расстояния и сервопривода. Во время работы радара на дисплей выводится расстояние до объекта. С помощью кнопки и потенциометра в отдельном меню можно настроить дистанцию, угол, шаг сканирования и другие параметры.

Умный вентилятор
Кирилл Пановицин создал умный вентилятор, который включается сам, если температура вокруг выше заданной, а также выводит на дисплей от Nokia 5110 температуру и влажность. Вентилятор способен включаться по двойному хлопку ладоней.

Двойной хлопок засчитывается, если в течение трех секунд после первого хлопка датчик слышит «тишину – громкий звук – тишину». Поэтому иногда возможно ошибочное срабатывание по голосу. Дисплей работает по SPI протоколу, и в нем также используются две дополнительные линии — RST и DC. Первая нужна для инициализации, вторая — для разграничения команд и данных. Данные на экране обновляются каждые пять секунд, это реализовано через прерывания.
Мы уже планируем следующие потоки курса «Программирование микроконтроллеров RISC-V». Чтобы не пропустить старт сбора заявок, оставьте свою почту на странице курса. Перед новым потоком мы свяжемся с каждым, кто оставит заявку, проведем собеседование, тестирование и после обработки результатов огласим список зачисленных. Желаем удачи!