Search
Write a publication
Pull to refresh

Comments 45

Вы изобрели "толстую" RTOS вроде Zephyr.

Zephyr пере усложнен наличием device tree и механизмом kconfig .
Я же предлагаю взять от zephyr только методологию proxy Hal. И больше ничего.

device tree там не от сырости завёлся, но от того факта, что заметное количество блоков (IP) в контроллерах существует в двух-трёх вариантах на всех -- приходят на ум контроллеры DMA, EMAC, тот же USB в вариантах fs/hs/otg.

Собственно, на идее драйвера, привязанного к DT'шному compatible, весь arm'овый, да и не только, линукс построен.

В C++ для решения этой проблемы есть концепция zero-cost abdtractions. В 2025 писать на МК без современных плюсов как-то странно.

ну и mbed, как неплохой пример реализации этой идеи, пусть и не использующий всей новизны.

У нас, когда ещё писали мк, было принято выносить аппаратно-зависимый код в отдельную часть проекта, а в логике стоял неявный запрет на инклюды хедеров HALа.

однако, всякая тонкая оптимизация, свойственная мк проектам, быстро разрушала эту стену: тонкости dma, usb, lan-mac и can настолько отличались от мк к мк, что если мы экономили каждую мс без сна (а это важно при питании от батареи), то код всё равно был сильно привязан к архитектуре.

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

Согласен, когда в примерах указывают функцию переключения типа gpio_pin_write(), то всё прекрасно выглядит, но модули покрупнее и посложнее, внутреннее поведение которых разнится от МК к МК только усложнят жизнь по крайней мере разработчику такого MCAL.

Функция gpio_pin_write(), принимающая набор пинов и гарантирующая их одномоментный переход, чтобы не было сквозных токов или ещё каких-нибудь ненужных переходных состояний, уже усложняет жизнь разработчику такого MCAL. Или перевод двух пинов из Hi-Z в out_high. Или работа с входом-с-подтяжкой.

Забавно, но очень часто аппаратно-зависимый код приходится писать именно для мгновенной работы с пинами в прерывании, в условиях аварийного останова, где каждый такт это огромный ток, текущий накоротко или через силовые ключи.

Читал-читал и думал - ну вот сейчас автор покажет реализацию своего MCAL на гитхабе, ну или хотя бы примеры, как может быть красиво и абстрактно реализован тот же доступ к GPIO при таком зоопарке подходов. Не говоря уже о каком-нибудь CAN - там даже философия аппаратных модулей внутри микроконтроллеров разная, у кого-то есть куча ящиков, у кого-то fifo сложные и фильтры, у кого-то свой CAN-подпроцессор со своим набором команд.

Не понимаю, как можно тут придумать что-то универсальное и гибкое не получив спагетти-код или не получив ограничение функционала, где через MCAL пролезет 5% от того что умеет аппаратная часть микроконтроллера. Думал, может хоть этот момент автор рассмотрит на каком-то сложном примере, но нет... О чём тогда статья, непонятно. Я как считал что сферический в вакууме MCAL не реализуем, так и считаю.

Вот что сказал об этом ChatGPT o3

Короткий вывод

В репозитории фактически лежит лишь набор «заготовок» для системы MCAL-драйверов: несколько Makefile/CMake-скриптов и пустой read_me.txt. Исходников, которые можно прямо собрать и запустить, там нет — большинство файлов, на которые ссылаются скрипты, отсутствуют. То есть «из коробки» использовать ничего не получится: придётся либо дописывать недостающие модули, либо подключать внешний MCAL-код.

Это что-то новое - выкладывать шлак и по его мотивам писать статьи по теме микрокнтроллеров.

Откуда тогда столько файлов?

MCAL-слой часто собирают скриптом-генератором, читающим YAML/Kconfig с конфигурацией проекта. Такой скрипт:

  1. делает копии общих template-файлов в каталог проекта;

  2. проставляет нужные #define и CMake/Make-флаги;

  3. генерирует _commands.c для CLI-оболочки, _diag.c для диагностики и т. д.

В коммите как раз видны одинаково оформленные пары файлов («general», «diag», «commands») для каждого переферийного блока — это типичный вывод такого инструмента.

Да, нынче трудно стало водить за нос.

Ну мой o3 - я ему дал весь репозиторий в zip - говорит что всё настоящее, но только верхний слой абстракции, без слоёв микроконтроллеров. И частично рукописное. Цитирую o3:

  • В папке mcal_common/ лежит ≈ 30 модулей (GPIO, UART, DMA, …).
    Для каждого «живого» модуля присутствуют:

    • _general.c — основная логика (state-машины, буферы, таймауты и т.п.);

    • *_commands.c — набор CLI-команд для отладочной консоли;

    • *_diag.c — обход регистров, self-test, счётчики ошибок.
      Код этой части компилируемый и читабельный — он написан вручную (комментарии, осмыслённые имена, нет признаков автосгенерированного мусора).

  • Общие макросы COMPONENT_GET_NODE/CONFIG и ссылки на code_generator.h показывают, что к каждой сборке должен добавляться автоматически сгенерированный файл с описанием таблиц конфигурации (маску выводов, частоты, номера каналов…). Сам генератор (скрипт/утилита) в архив не положен.

  • MCU-специфичного слоя нет вообще. Нет каталогов вида mcal_stm32f4/, mcal_esp32/ и даже простых «заглушек» с прямым доступом к периферии.
    Поэтому все вызовы вида gpio_pin_set_ll(), adc_start_ll() и т.п. остаются «висящими».

  • Отдельные модули действительно пока пустые: например, mcal_common/wdg/ содержит только wdg_const.h и .mk — чистый каркас без строчки кода.

Чем уже можно пользоваться

  • Алгоритмическая «верхушка». Логика обмена по CAN (очереди, сортировка по приоритету, ожидание TX Ack), I²C-FSM, FSM для I²S full-duplex, универсальные таймерные обёртки, фоновые state-машины PWM/RTC — их можно подключить к своему проекту и «подшить» к собственным низкоуровневым вызовам.

  • CLI-команды и диагностика. Если заведёте свою систему логов (log.h) и консоль, уже готов базовый набор команд: adc_init, gpio_toggle, dma_stat, …

  • Make/CMake-инфраструктура. Файлы mcal.mk и mcal.cmake умеют по флагам подключать нужные модули, размазывать #define HAS_<MODULE> и добавлять include-пути.

Что придётся дописать

  1. Нижний уровень для каждого семейства МК.
    Создаёте папку mcal_<chip> и реализуете функции *_ll() (low level), структуру ComponentDriver_t, ISR, карту прерываний. Это 70-80 % работы.

  2. Генератор конфигурации.
    Скрипт (часто на Python) читает YAML/Excel со схемой платы и штампует code_generator.h + *_config.c. Без него даже общая часть не соберётся: массивы AdcNode[], GpioPad[], ClockDomain[] просто не объявлены.

  3. Сторонние заголовки.
    Упоминаются, но отсутствуют: convert.h, time_mcal.h, none_blocking_pause.h и др. Их нужно либо написать, либо убрать зависимости.

Сгенерировано или вручную?

  • Файлы .c / .h внутри mcal_common — рукописные. Есть авторские комментарии, LOG_INFO() расставлены выборочно, стилистика единообразна.

  • Автоген требуются только для структур данных (константные таблицы и массивы), на что прямо указывают закомментированные строки #include "c_defines_generated.h".

Итого

  • Репозиторий даёт полноценный «бизнес-слой» периферии (state-машины, очереди, CLI, диагностика).

  • Без собственных драйверов и конфигуратора он нерабочий — это половина конструкции.

  • Писать придётся много: низкоуровневые функции для каждой периферии, генератор таблиц и пару вспомогательных утилит.

Вы что купили подписку на chatGpt?

Да а как нынче жить-то без этого... это же как вторая голова. Вот пока это пишу, оно мне рассказывает как с помощью Вашего MCAL выглядел бы мой драйвер J1939. Но вообще надо клод брать, вчера вот 4й вышел.

И сколько стоит тариф?

2000-2500р в месяц примерно в зависимости через какие сервисы платить.

Ну вот, говорит, вместо использования кучи аппаратных меилбоксов, как в моём оригинальном драйвере (каждый меилбокс со своим ID и приоритетом) мне придется самому программно засовывать все сообщения в единую свою FIFO очередь и вызывать ваш can_api_transmit_data - но который может ещё и не записать данные, и надо проверять что сообщение ушло через can_wait_tx_done_ll. А оно может не уйти, потому что, скажем, линия занята низкоприоритетными сообщениями, а мне надо отправить что-то срочное. И мне придется отменять отправку текущего сообщения (которое застряло и не уходит) и проталкивать более срочное. Притом что у вас CAN_abort пока и не предусмотрено.
Итого, придется работать с CAN "через одну дырку" делая программно свою приоритизированную очередь, вместо того, чтобы натолкать новых данных в десяток аппаратных мейлбоксов и забыть - сами отправятся по своим триггерам и приоритету (сейчас у меня так). В итоге накладные расходы использования вашего MCAL это не "10-20 тактов процессора" на вызов обертки MCAL, а существенное изменение архитектуры драйвера, который вместо полагания на аппаратные возможности микроконтроллера будет вынужден пользоваться кастрированным узким API MCAL, тратить кучу ресурсов на организацию своих приоритетов, FIFO и менеджера отправки данных в сеть CAN.

Хм. У вас тот же chatgpt,но совершенно другой вывод. Как так?

Ну почему другой - и тот и этот написали что больше части файлов нет, а именно привязки к микроконтроллерам. Разнится оценка вклада имеющегося кода: один раз он написал что это только скелет с обертками, другой раз решил что это уже половина дела уже. Ну а так-то да, gpt что дышло, как спроси так и вышло

Это довольно странно качать в Zip, а потом за свои же деньги заставлять GPT это распаковывать при этом потерять историю коммитов. Лучше смотреть прямо на GitHub-е. Там GPT дополнительно посмотрит как юзер активничал.

Но мой o3 пошел дальше и все же думает, что автор втихую использовал один из корпоративных генераторов сорсов:

- Vector DaVinci Configurator Classic / Pro
- EB tresos Studio
- ETAS ISOLAR-A, Mentor VSTAR, Artop

Но только потом он исходники еще сильно кастрировал.

У меня давече с другим проектом gpt o3 имел проблемы с ориентацией по гитхабу, а zip файл он разархивировал внутри и сразу все прочитал. Да и в plus подписке ограничивается число вызовов в неделю, и там и там один - что ссылку дать, что архив. Ну да лирика все это, и так понятно.

" Vector DaVinci Configurator Classic / Pro, EB tresos Studio, ETAS ISOLAR-A, Mentor VSTAR, Artop"
Впервые узнаю, что есть такие утилиты.

Я согласен с тем, что ChatGPT написал про мой код. По сути он перефразировал заметку на habr .

Как говорил мой начальник- схемотехник
"Не нужны нам программисты микроконтроллеров, ChatGPT сам напишет нам hex файл прошивки"

ChatGPT сам напишет нам hex файл прошивки

И схему тоже нарисует. Хочешь в стиле Сальвадора Дали, хочешь под стимпанк. Схемотехники, готовьтесь :)

ChatGPT - это наркотик.
Вы осторожнее с ним, а то можно и вовсе разучиться самому работать.

Вы можете попросить нейросеть дать развернутый комментарий по исходникам FatFs?

Про принципы архитектуры файловой системы FatFs? Со схемами, текстовым описанием.

Нечто подобное есть Кристофера Корманиоса, автора кникги Real-Time C++: Efficient Object-Oriented and Template Microcontroller Programming: GitHub - ckormanyos/real-time-cpp: Source code for the book Real-Time C++, by Christopher Kormanyos

И у коллеги по работе было - набор библиотек, обеспечивающий единое API для всех используемых платформ и даже существующий в одной единственноверной версии с которой собираются все проекты.

Лютый героизм поддерживать такое, не могу сказать что в моих проектах есть нечто подобное.

Каждый начинает со своего MCAL. А получается просто CAL

Proxy MCAL это требование стандарта ISO-26262.
Стандарт требует проработки архитектуры ПО.
Причем архитектура должна быть абстрактная, простая, модульная , логичная, иерархично выстроена, конфигурируемая, ремонтопригодная.
Выстроена так, чтобы её можно было верифицировать (тестировать). Всё это приводит к решениям организовать Proxy MCAL.

-Сегодня первое, что делают люди, когда атакуют твою Темную Башню Зла - это заваливают тоннель для побега, - сказал Злобный Гарри.
-Ублюдки! - сказал Коэн. - Ты должен позволить Темному Повелителю скрыться. Все это знают.
-Это точно, - сказал Калеб. - Нужно оставлять себе немного работы на завтра.* ("Последний Герой")

Так вот надо всегда оставлять немного работы на завтра. А переписать всё под новый контроллер это замечательная работа. Если не оставить её себе, то тебе поручат другую работу, которая может быть уже далеко не такой хорошей.
С третьей стороны, переписывать каждый раз MCAL на другой контроллер тоже работа....

Когда управляешь современным самолетом, то все сигналы управления сначала поступают на компьютер.

И только потом компьютер решает, как выдавать данные на двигатели и закрылки.

Этот подход называется Fly by wire.

Так и в программировании микроконтроллеров.

Proxy MCAL конфиг проходит через proxy MCAL, чтобы корректно проинициализировать HAL от вендора. Вот так...

А я вот никогда не использую "HAL от вендора" -- у меня самописное всё, от GPIO до USB. Ну, это если про нижний уровень, работающий прямо с железом, говорить. На среднем уже возможны варианты (скажем, использую LVGL, а если потребуется прикрутить сеть, возьму lwIP).

Аналог FatFs тоже сами написали?

Да. Полностью асинхронный (а не чисто синхронный, как FatFs -- собсно, потому и написал свой). Причём использовал сопрограммы C++20 -- собсно, потренировался на кошечках :) Правда, сейчас перепишу на обычные процедуры обратного вызова, поскольку Кейловскому отладчику наличие сопрограмм начисто срывает крышу -- отлаживать можно только на уровне дизассемблера, причём не только сами сопрограммы, но и код более высокого уровня.

вот это не фига себе признание! Я тоже думаю что всегда лучше писать в рамках С++11 максимум. Кроме того что можно нормально отлаживаться, переносимость повышается туда куда последние достижения еще не завезли.

С поддержкой собственно достаточно нового стандарта (C++20, если в данном случае) со стороны компилятора проблем нет -- это ж Clang, подпиленный ARMом (вероятно, путём прицепления проверки лицензии -- вряд ли они что серьёзное меняли). Вот со стороны отладчика, а это уже ARM (Keil) -- там да. Судя по всему, он не способен корректно интерпретировать новую отладочную инфу, причём до такой степени, что теряет способность адекватно воспринимать и "классическую" (не может, например, правильно сопоставлять номера строк С++ с адресами кода).

Ну а переносимость сейчас... не особо важна, так скажем. Почти везде компилятор -- либо GCC, либо Clang, а они вполне себе следуют новым стандартам. Поэтому использовать стандартные фишки пятилетней давности, как по мне, уже вполне себе можно, если говорить именно о переносимости, а не о качестве поддержки дополнительными инструментами, а не собственно компилятором.

если говорить именно о переносимости, а не о качестве поддержки дополнительными инструментами, а не собственно компилятором.

ну у меня это было на уровне ощущений, а вы это так просто сформулировали, спасибо вам!

Но мне все-таки кажется что поддержка дополнительными инструментами это в какой-то степени тоже из области переносимости. Потом, если оно скомпилировалось не факт что этот бинарник будет корректно работать в специфической железке, то есть я боюсь там вопрос не только совтовых тулзов, но и аппаратных возможностей в железке. Я много раз занимался тем что проверял корректность даже просто своего понимания работы хитрых С/С++ конструкций на реальном железе и убеждался в том что проверяю не зря. Даже для чистого Си помнить все эти особенности с необходимой абсолютной точностью фактически не возможно, а с последними наворотами из С++ стандартов я бы не надеялся и на разработчиков компиляторов и как вы добавили: окружающих их тулзов.

Писать просто очень сложно.

Вендор вендору рознь. Вот у stm плохой Hal . Хуже st Hal ни у кого в мире нет. А у китайцев artery, yuntu , flagchip - великолепный hal.

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

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

Hal пишется для примера, чтобы продемонстрировать только основные возможности железа.

То есть HAL от вендора пишется "на выброс". Так?

ну если вы раскроете логику по которой у вас получилось что "Hal пишется для примера" превращается в "пишется "на выброс"", я смогу ответить более предметно, а пока я не понимаю как у вас получилось это превращение. Я конечно умею мысли читать, но не на расстоянии! Мне надо прикоснуться :) , ну иногда фотография помогает, но не электронная :).

Это другая сторона большой legacy. Есть же вариант когда как бы наоборот: сделали один раз (на 8051) и отказаться никак не могут, допиливают, и даже эмулируют старое, т.е. как бы даже не переписывают. потому что где то была очень тонкая фишка которой потом нигде просто нет.

В psoc сypress например много встроенного аналога, в новых attiny всякие lut элементы, ну шины событий - как раз то изза чего можно упростить и схему и код

Sign up to leave a comment.

Articles