Подготовка к велосипедостроению.

Подготовка к велосипедостроению.


Valentyn Korniienko

Все живет тут:

https://github.com/ValentiWorkLearning/GradWork

P.S. Буду рад любым вопросам, пожеланиям, идеям по проекту. Все описать в одной статье не получится. Закрыл необходимый минимум вопросов.

Идея, которая крутилась крайне давно в голове и ждала своей реализации до момента, пока не увидел Samsung Gear и момента приближения защиты диплома. Так и появилась идея. Что если начать творить что-то похожее, но своими руками? Как раз, давно хотел разобраться с процессорами от Nordic. Слышал много, интересно было попробовать.

Задача была поставлена ясно( как оказалось в последствии, нет ). Сделать что-то около умных часов своими руками, на доступных компонентах. И сразу поставлена хотелка- круглый дисплей. Графика- LittlevGL. Языки разработки - С/С++. Система сборки- CMake. САПР- KiCAD.

Работа началась с запуска сборки под VSCode для NRF52832. Далее-трассировка и заказ печатной платы. После- написание драйверов под дисплей и разработка UI( с которым любезно помогла natali.kolesnichenko.01@gmail.com ).

Первый прототип платы выглядел как:

Собранный прототип с талисманом данного проекта

И были спешно проведены первые тесты запуска библиотеки LittlevGL и BLE-стека.

Первая картинка, нарисованная черновой версией драйвера
Первая версия интерфейса. Вдохновлен был подобным дизайном у Samsung Gear в одной из их тем.

Компоненты выбрал достаточно типовые, а именно: модуль от EByte E73NRF52832, пульсометр - MAX30102, магнитометр/акселерометр/гироскоп -MPU9250. Память - W25Q16BVS. Из интересного - круглые дисплеи на Aliexpress продаются с разными интерфейсами SPI(8-9bit). 9-bit-ный попробую запустить в ближайшее время. После сборки спешно запустил BLE стек, добавил отображение заряда батареи.

Изначально понимая, что разработку и протипирование интерфейса прийдется вести на ПК ( во избежание прошивки контроллера каждый раз при изменении координат виджетов на несколько пикселей), архитектура проекта выстраивалась с учетом данного требования. Примерную диаграмму взаимодействия компонентов рисовал в draw.io. Подробнее с ней можно ознакомиться в репозитории проекта.

К текущему моменту рассказа появились первые прототипы нормального интерфейса.

Первая версия интерфейса

Вкратце о том, что представляет из себя задача по портированию LVGL для выбранного проекта и дисплея.

1) Выбрать политику работы с буфером. LVGL поддерживает двойную буферизацию с буферами меньше, чем дисплей. Или же честная двойная буферизация, два фреймбуфера. Или же один фреймбуфер размером, соответствующим дисплею, либо меньше.[1]

2) В драйвере дисплея реализовать функцию заполнения прямоугольника заданных размеров заданным буфером цвета.

3) По окончанию заполнения дисплея вызывать lv_disp_flush_ready

4) С заданным периодом вызывать lv_tick_inc, необходимо для нужд библиотеки, таких как анимации[2]

5) Периодически вызывать lv_task_handler, период порядка 5мс[3]

Подробнее можно ознакомиться тут:

[1]https://docs.littlevgl.com/en/html/porting/display.html

[2]https://docs.littlevgl.com/en/html/porting/tick.html

[3]https://docs.littlevgl.com/en/html/porting/task-handler.html

В моем случае была необходимость запуска прошивки как на PC, для разработки UI, так и на железке. LVGL предоставляет возможность запуска на ПК, можно посмотреть в примерах.
Реализация, использованная в проекте представляет собой идею PIMPL(Pointer to Implementation), которая инкапсулирует работу с платформозависимой графикой. В случае PC графическая подсистема использует библиотеку SDL. В случае Nordic - реализацию драйвера для ST7789V дисплея.

Фрагмент реализации платформозависимой части для драйвера ST7789V
Фрагмент реализации платформозависимой части. В скриншот попал кусочек будущей части стандартной библиотеки С++20 для форматирования, а именно fmt.


Подробнее ознакомиться можно тут:

https://github.com/ValentiWorkLearning/GradWork/blob/master/Firmware/Firmware/src/graphics/gs_platform_layer.cpp

Для хранения виджетов по умолчанию Lvgl использует пул памяти, размер которого выставляется в lv_conf.h

/* Size of the memory used by `lv_mem_alloc` in bytes (>= 2kB)*/# define LV_MEM_SIZE (8U * 1024U)

Таким образом, все объекты, аллоцируемые библиотекой, будут помещены в него.

Для рационального использования пула памяти, а именно- выгрузки виджетов, если они не видны пользователю, была выдумана простая обертка поверх std::unique_ptr, а именно:

Использование крайне простое. Достаточно указать тип и функцию, необходимую для освобождения ресурсов за объектом. Таким образом, при скрытии страницы все ресурсы, занятые страницой, освобождаются автоматически.

Виджеты Health страницы

Немного о модели сервисов, использованной в проекте. В Nordic SDK есть модуль-симулятор, позволяющий эмулировать данные с периферии ( на деле это таймер + функция, отдающая значения с увеличивающимся/уменьшающимся шагом). В случае с PC- это std::thread + std::condition_variable.
Все платформо-зависимые части спрятаны за сервисами, которые могут быть либо реальными, либо заглушками/симуляторами.

Фрагмент инициализации сервисов приложения

UI и сервисы, в свою очередь общаются с помощью сообщений. Компоненты UI могут осуществить подписку на сообщения от сервисов, например:

Подписка контроллера страницы Clock Page на изменения текущей даты/времени


Инициализация виджетов и подписка BLE-виджета на сообщения от сервиса BLE.

В свою очередь, на стороне отправки сообщений механизм будет следующий:

Механизм отправки сообщений

Говоря о сервисах. Все доступные сервисы создаются через ServiceCreator. интерфейс приведен ниже:

Интерфейс IServiceCreator. Типовая AbstractFactory

В свою очередь, интерфейс сервиса выглядит как:

Интерфейс сервиса заряда батареи

Где конкретный наследник реализует его методы + инициирует вызовы сигналов. Например, как это делает FakeBatteryService:

Генерация сигнала о измененном уровне заряда батареи


</Закончить листинги кода>

Что получилось в итоге:


Главный экран
Health page


Страница плеера

Технологии, использованные в проекте:
-Nordic SDK

-C++17

-CMake

-LittlevGL

-Embedded Template Library

-SimpleSignal [https://github.com/larspensjo/SimpleSignal/blob/master/SimpleSignal.h]

-Callback Connector - wrapper for C-callbacks

[https://github.com/Toxa-man/CallbackConnector]

-SDL Library





Report Page