Как стать автором
Обновить

Использование библиотеки stm32cube для создания платформо независимых драйверов

Время на прочтение18 мин
Количество просмотров15K
Всего голосов 21: ↑19 и ↓2+17
Комментарии33

Комментарии 33

Индивидуальным разработчикам наличие мультиплатформенности в исходниках поддержки железа только мешает разобраться в коде и вынуждает дополнительно изучать некий чужой HAL.

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

Еще несколько странно выглядят отсылки к линуксу.
Почему подражание программному интерфейсу настольной системы может быль каким-то плюсом для малой RTOS?
Спасибо за вопрос!

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

Если Вы идеально знаете HAL какого то микроконтроллера, до такой степени, что способны написать свою реализацию, которая лучше (быстрее, надежнее, ...) чем версия производителя, то наверное Вам стоит предложить ее этому производителю, или хотя бы сделать открытый проект. Поскольку сейчас, на мой взгляд, платформы меняются очень быстро, и поддерживать свой велосипед, гораздо труднее чем его сделать.

По поводу отсылки к Линуксу. Я буду выступать на OSDAY и как раз коснусь этой темы. Если кратко, то у Линукса, на сегодняшний день, самая большая и прилично отлаженная (в популярных приложениях и библиотеках) кодовая база. Если Вам требуется помигать светодиодом, то достаточно и работы с регистрами напрямую, но, если Вам нужны какие нибудь общепринятые штуки, типа http сервера, то лучше взять готовую стороннюю библиотеку причем желательно изменения по адаптации внести в основную ветку разработки. Конечно есть вариант взять какую нибудь популярную ОСРВ, тот же FreeRTOS и ориентироваться на его API, но мне кажется это может оказаться ошибочным если проект умрет, и точно более накладным, поскольку количество приложений сильно меньше.

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

У вас может быть архитектор сверху, кодер снизу и хардварщик сбоку. А может это все помещаться в вас одном.
И мне кажется ардуинщики, т.е. самая массовая аудитория — это люди где все в одном.

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

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

Тут я вижу принципиальный конфликт интересов.

Как Вы жестко и даже принципиально:)

Мне кажется, что Вы противоречите себе.
Во первых, если разрабочик делает все, то ему тем более стоит пользоваться готовыми частями. Те же упомянутые ардуинщики, пользуются ардуино студио, в которой есть огромное количество готовых библиотек.
Во вторых, 2-3 года, которые есть на освоение чипа, на мой взгляд недостаточно, чтобы досконально изучить его потроха ориентируясь исключительно на мануал к чипу. Точнее достаточно, но на функционал уже времени не останется.

Мне кажется, наше с Вами непонимание в другом!
А именно, как я уже сказал, что если нужна мигалка светодиодов, то конечно всего перечисленного в статье не требуется. В этом случае следует взять имеющийся в stm32cube, или в другой поддерживаемой производителем или сообществом систему, пример и быстро сваять устройство. Я же говорю о довольно функциональных системах, которые написать с нуля, наверное можно, но непонятно зачем и стоить это будет ну очень много, ведь в этом случае разработчику прийдется изачать не только чип, но и сетевые технологии, системное программирование, файловые системы и еще ворох специализированных задач.
Тут вы смешиваете в кучу фреймворк, промежуточное ПО и то что у ST называется HAL.
О роли фреймворков и middleware я наслышан.
Но HAL это прежде всего средство привязать пользователей к определенной платформе, а заодно и способ реюзинга во внутрикорпоративной разработке у самого ST.

Я не знаю как вы задокуметировали свой HAL, но документация на HAL от ST не намного легче того же мануала на чип или даташита. По сути в любом случае юзер должен изучать работу периферии чипа по мануалу, на если RTOS работает через HAL то он еще вынужден тратить время на изучение HAL.
От этого у разработчика падает производительность.

Я скажем доволен, что в своем фреймворке мне удалось RTOS MQX практически очистить от всяких абстракций и перевести на прямую работу с регистрами. Остались только нативные драйвера SD, USB и Ethernet.
Без HAL я могу быстро реализовывать и легко отлаживать до десятка задач с жестким реальным временем. Исходники получаются прозрачными и чистыми. Нет никаких длиннющих макросов. Нет сбивающего с толку переименовывания обращений к регистрам. Взяв любое имя регистра в текстах с легкостью можно найти его в мануале, не гуляя по дебрям HAL в попытках понять что есть что.
Также без HAL легче централизовать всю информацию о периферии в одном файле и т.д. и т.п.

Так, стоп!
О чем мы дискутируем?

Я конечно смешиваю все в кучу, но:
Во первых: Почему же Вы оставили драйвера SD, USB и Ethernet? И зачем Вы используете MQX? Ведь сами же сказали, что Вы относитесь к «индивидуалам» которые делают все и прикладное ПО пишут, и драйвера по даташитам, и многое другое как я понял!
Во вторых: Я так понял Вы не читали статью, поскольку почему то все время критикуете STMicroelectronics, за навязывание своего HAL. А в статье как раз написано, как мы ушли от этого HAL-а. И сейчас на этой серии микроконтроллеров имеем независимый от оборудования интерфейс. То есть, программист может использовать обычные вызовы socket(), listen(), sendto() которые будут работать одинаково на всех платформах.

Получается, данную дискуссию Вы затеяли, чтобы доказать, что все платформы кроме Вашей (я не сомневаюсь, что она прекрасна), неправильны!

Давайте сойдемся на том, что я принял Ваше мнение, к сведению. И при случае посмотрю на микроконтроллеры LPX и прилагаемую к нему ОСРВ MQX!
Я открываю ваши тексты и вижу кругом функции и макросы от HAL предоставляемого ST.
И этого следует что вы делаете еще одну надстройку поверх HAL.

Функции socket(), listen(), sendto() это прикладной уровень. Если в вашем стеке TCP их раньше не было, то это проблема вашего стека.
А скажем в MQX, uCOS они всегда были.
К HAL т.е. к уровню аппаратной абстракции или платформо-независимости эти функции отношения не имеют. Это все равно что назвать платформо-независимой функцию printf

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

Просто я не согласен в одной мелкой детали во все этой истории, а именно с вашей презентацией полезности некоей кроссплатформенности построенной на концепции HAL от ST.
Это на мой взгляд пустая трата времени.
В вашей организации она нужна для реюзинга, а индивидуалам она вредна.

Мой подход, кстати, не уникален, я его подхватил у таких известных проектов как uCOS и Keil RTX. Минимализм и пропуск абстракции аппаратуры сильно экономит время.
В вашей организации она нужна для реюзинга, а индивидуалам она вредна.

В этом случае, я Вас попрошу не использовать наш проект. Конечно нужно использовать, только те средства которые полезны!
/* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
/* copy received frame to pbuf chain */
Лично для меня этих двух комментариев достаточно, что не смотреть дальше. Может, в Linux так принято, но в embedded так делать не то что нельзя, но крайне нежелательно.
Ну поскольку у нас используется не lwip, то скорее всего комментарии остались от какого-то примера из куба, сам код конечно адаптирован.
Но если честно не очень понимаю, что тут не нравится?
То есть, все равно должны выделить память под пакет, если Вы имеете в виду, что можно было бы использовать ту память где уже лежит принятый пакет, то это сильно ограничит функциональность, то есть необходимо как можно быстрее освободить место куда указывает дескриптор, ведь обработка пакета занимает приличное время, а нужно иметь возможность принимать следующие пакеты. Или я не прав?
Да, я именно это имел в виду, в хорошо организованном стеке данные идут по нему, физически не перемещаясь, что избавляет от дикого оверхеда, особенно в случае маленьких пакетов. А принимать очередные пакеты можно в свободные слоты, и для встроенных систем важно уметь определить необходимое количество слотов для работы без потерь и зарезервировать их заранее. Единственное место, откуда информацию действительно необходимо как можно скорее вытащить — это буферная память периферийного узла, но и то только в том случае, если у Вас нет развитой DMA для работы с этим узлом.

А skb_malloc в lwip не использует какой-нибудь предаллоцированный slab? Хотя здесь ещё всякие memcpy лишние при нормальном zero-copy.

Да, у нас в данном случае используются уже предаллоцированные буфера, то есть выделение можно считать константой по времени
Да, мы об этом думали, но вообще без копирования получается очень негибко.
То есть, в данном случае необходимо будет сохранить последовательность захвата и освобождения пакетов, это в принципе можно сделать, но тогда точно уйдет вытесняющая многозадачность и некоторые другие плюшки. Выигрыш же в одном копировании (иногда в двух, нужно пользователю в буфер скопировать), по нашим замерам не дал заметной разницы. Таким образом, мы сделали выбор в пользу удобства интерфейса, но все еще думаем над реализацией какой нибудь узкоспециализированной версии для предложенной Вами ситуации.
Ну истина всегда конкретна. Когда я делал один девайс, сначала использовал именно 1wip, потом был вынужден с него уйти (в силу принципиальной длины окна в один пакет) и нашел эту реализацию с продвижением данных по стеку, получилось почти на 20% быстрее, может быть, потому, что делал на Luminary, а у них memcpy была не DMA (у него DMA вообще не было), может, у Вас прирост и будет не столь заметен.
Тут сложно не согласиться, при таком ограничении в один пакет, копирование будет лишним.
По поводу производительности, мы делали замеры и у нас получалось на 10% хуже линуксового стека, на той же железке. Хотя нужно отметить, что это был довольно большой ARM, конкретная железка и, конечно, полный стек.

Я рад, что понял, а то первый Ваш комментарий меня немного напугал:)
НЛО прилетело и опубликовало эту надпись здесь
Пока нет.
TMS570 менее популярный чем STM32, но если есть сильный интерес, то можем посмотреть:)
Подскажите, чем отличается EmBox от той же FreeRTOS, кроме архитектуры?
Вы же пилите своё не ради пиления, а с какой то конкретной целью?

Ещё вопрос, чем именно драйвер Cortex-M3 отличается от Cortex-M4, например, USART?

Может совсем наглость с моей стороны, а можно какие нибудь примеры для ДискоФ4?
Подскажите, чем отличается EmBox от той же FreeRTOS, кроме архитектуры?

В двух словах трудно ответить, но например, что мы позволяем представить окружение на STM32 как будто это маленький линукс, то есть там можно запускать утилиты из линукс (конечно если собрать их в Embox), похожая командная строка, POSIX интерфейс, при этом сохраняя легковесность как в FreeRTOS. Пример, VoIP телефон на базеSTM32 и библиотеки pjsip. Это можно наверное сделать и на FreeRTOS, но потребует существенно больших усилий.

Ещё вопрос, чем именно драйвер Cortex-M3 отличается от Cortex-M4, например, USART?
В нашем случае ничем, нужно в конфигурации задать какая плата.

Может совсем наглость с моей стороны, а можно какие нибудь примеры для ДискоФ4?

Более точно можно плату? В принципе у нас есть базовый пример для stm32f4-discovery. А наши конфиги очень просто переделываются под другие платы. Если возникнут трудности, будем рады помочь.
то есть там можно запускать утилиты из линукс (конечно если собрать их в Embox)

Где они храниться будут? Можно чуть больше примеров?
У стм есть CircleOs, приложения можно переключать, а у вас как?
В принципе у нас есть базовый пример для stm32f4-discovery.

Это она и есть, т.е. для нее нужны примеры.
Где они храниться будут?

Не очень понял вопроса, но предположим в образе который получиться. Вы собираете Embox в требуемой конфигурации. Для Вас наверное подойдет arm/stm32f4cube (то есть для конфигурации наберите make confload-arm/stm32f4cube). В конфигурационном файле ./conf/mods.config можно задавать список и параметры всех модулей, в том числе список утилит. Например, include embox.cmd.fs.ls добавит утилиту ls (почти стандартную) в полученный в результате образ. Утилиты пишутся стандартным способом, то есть присуствует main() и можно использовать стандартную библиотеку, в том числе pthread, если нужна конечно.
В этом же конфиге можно настроить и работу планировщика и других частей. Например, в приведенном конфиге есть строчка
include embox.kernel.thread.core(thread_stack_size=5120,thread_pool_size=4)

Она задает количество потоков со стеком (вытесняющая многозадачность) и размер стека для каждого потока

Можно чуть больше примеров?

В конфигурации описанной чуть выше есть httpd, пример как мы его использовали вот

У стм есть CircleOs, приложения можно переключать, а у вас как?

Если я правильно понял, что это такое, то у нас гораздо серьезнее. В принципе можно сделать похожим образом, правильно настроив конфигурацию, но по большому счету у нас есть полноценное управление процессами и потоками. То есть приложение разработанное для Линукса, может работать у нас, без изменений, естественно с огладкой на ограничения аппаратуры.
НЛО прилетело и опубликовало эту надпись здесь
кроме поддержки отечественного железа?

Такого отличия не припомню:)
Нет, у нас есть поддержка некоторых специализированных отечественных комплексов и устройств, но насколько я знаю, ее нет в открытом доступе.
Мы любим играться с отечественными процессорами и микроконтроллерами, но это тоже не может служить нашей отличительной чертой.

Но вопрос хороший, постараюсь чуть позже более развернуто ответить. А кратко если сравнивать с приведенными Вами, RTOS, то у нас окружение почти линуксовое, то есть приложения пишутся как будто это обычное приложение, вызываются также, используется стандартная библиотека. Похожие вещи есть у eCos, но в более простом варианте.
НЛО прилетело и опубликовало эту надпись здесь
Это сложный вопрос.
Экзоядро подразумевает, что само ядро контроллирует только обращение к ресурсам, то есть при загрузке какого то ресурса куда то, идет проверка, после этого процесс который запросил ресурс использует его как хочет. Конечно это требует существенно меньше времени чем микроядро, в котором нужно постоянно переключаться.
На, «нулевом» этапе Embox предназначался для отладки оборудования и был наверное очень близок к экзоядру. Но с развитием проекта, он стал скорее конфигурируемым. То есть, все еще можно создать конфигурацию, при которой он будет экзоядром, мы пользуемся этим на ранних этапах портирования и в некоторых особенно маленьких платформах. Но Embox может быть сконфигурирован и как микроядро, и как монолитное и еще много различные гибридных вариантов, заточенных под задачу!
Немного подробнее о целях Embox.

Изначально это был маленький загрузчик для отладки аппаратуры. Помогали разрабочикам ПЛИС. В проекте учавствовали несколько студентов, и чтобы им было нескучно, решили расширить функциональность и разработать ОС. Довольно быстро поняли, что писать вытесняющие планировщики распределители памяти и тд не очень эффективно, нужно реальное применение этих частей. Первым стали роботы лего ну и вообще всякие любительские и не очень роботы.
Дальше пришло осознание, что без сетевого стека и полезных библиотек ОС никому не нужна, в том числе нам самим. Стали наращивать функциональность.
Потом поняли, что не успеваем все поддерживать и придумали как внедрять Линукс приложения, прямо целиком проекты с исходниками. То же самое с драйверами это как раз и описано в данной статье.

Подводя итог:
На сегодняшний день Embox имеет существенно более простые средства разработки и отладки систем по сравнению с приведенными Вами ОСРВ. Поскольку можно использовать мощный потенциал Линукса и не нужно лазить в регистры (вообще забота об аппаратуре сильно упрощается). Перед большими системами (Линукс и ко) у Embox есть другие приимущества.
Проблема перехода на новый чип отвалится сама собой при чётком разделении железного уровня и программного.
В ситуации с HAL — буквально каждый второй пишет программный код в тесной интеграции с железным уровнем.
Вместо стандартного стандартного обращения через инлайн функцию — включает полный код в тело программного уровня. Где этот кусок теряется под множеством строк проекта, без контекстных ссылок и описания в шапке.

Ок, начинаем новый проект под новый чип. Применить уже готовый работающий код из старого проекта — не получится. Потому как он завязан на железо по самые гланды. Это кстати проблема почти всех любительских графических интерфейсов. Народ пришёл из мира пиков и атмела, и меняться не желает.

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

Проблема перехода на новый чип отвалится сама собой при чётком разделении железного уровня и программного.
В ситуации с HAL — буквально каждый второй пишет программный код в тесной интеграции с железным уровнем.
Вместо стандартного стандартного обращения через инлайн функцию — включает полный код в тело программного уровня. Где этот кусок теряется под множеством строк проекта, без контекстных ссылок и описания в шапке.
Так проблема исчезает или все таки каждый второй пишет программный код в тесной интеграции с железным уровнем?
На самом деле, статья о нашем подходе к пути решения проблемы написания самописного кода. То есть, у нас используется код от производителя, который поддерживается и там будут фикситься баги, Мы же будем брать новые версии, что существенно проще.

Ок, начинаем новый проект под новый чип. Применить уже готовый работающий код из старого проекта — не получится. Потому как он завязан на железо по самые гланды. Это кстати проблема почти всех любительских графических интерфейсов. Народ пришёл из мира пиков и атмела, и меняться не желает.
Вот с последним однозначно согласен, это как раз проблема которую нам и хочется решить, с любительскими самописными самокатами мы пытаемся дело не иметь.

Насчёт универсальных конфигов — это пройденный этап, и он тупиковый. Подходит для быстрого старта — не более.
Во первых — написать новый конфиг дело десяти минут.
Во вторых — свой конфиг может быть каким угодно: хоть с отладкой в памяти, хоть с размещением части кода на внешней флешке, а конкретно для М7 — несколько вариантов использования TCM памяти.
Можете предложить лучший вариант?
На самом деле мы себе льстим, что частично решили проблему и наш конфиг позволяет сделать не только быстрый старт, но и довольно хорошее развитие.
По поводу M7 можете поподробнее на счет настройки. Интерес меркантильный, она у нас работает, но есть вопросы как раз с памятью:)

Для отладки в памяти необходим особо урезанный код на ассемблере. Для того чтобы сделать его универсальным — нужно загружать _estack не из кода флеша, а по ссылке на первый адрес рам памяти. Естественно для флеша стоит указать минимальный размер рама, а потом в принудительном порядке переписать. Работает на всех чипах st, от M0, L0, до M7.

_estack
Reset_Handler
Читать содержимое первой ячейки рам памяти, писать в Vector table offset register.
Переход на рам память (нулевой адрес +4).

Для самой ID все настройки линкера и оболочки забиваются на рам память, примеры есть даже у самой st. Разве что имеет смысл удалить двойное копирование, и инициализацию от самого GCC.

Для использования TCM в М7 есть два варианта, нативное и противное.
Примеры от st запутаны и непонятны даже для меня. Суть в том что ITCM (от 0x0) память программ может быть самостоятельной областью с нулевым доступом, и областью с автоматическим перекрытием флеша (аналог раздутого L1 кеша).
В случае самостоятельной области памяти — возникают определённые трудности с размещением в ней таблицы векторов, но зато есть возможность разместить куски собственного критичного ко времени выполнения кода.
Трудность заключается в написании бута предварительной загрузки, для него и основной программы придётся писать разные конфиги линкера.

Второй вариант — не слишком красив, но зато работает с пол пинка. Смысл в том что ITCM область предварительно заполняется копией флеша (адреса не важны, главное объём) — а после запускается репликация. При этом в ITCM область будет автоматически копироваться наиболее используемые куски кода, причём не только из собственного флеша, но из внешнего то-же. Управлять процессом не получится, и от этого становится грустно. Разница в скорости выполнения кода будет зависить от фазы луны и магнитных бурь на Марсе.

И наверное самое главное, внешняя sdram и spi флеш память. Тут можно составить куклу для самостоятельной настройки, потому как универсальных вариантов просто не существует. Пользователь может возжелать использовать раздельную компиляцию самостоятельных программ, с размещением их на sd или spi флешке. Это естественный шаг, когда всё остальные варианты уже не умещаются в самом чипе. Чаще всего это готовые модули из мира больших машин. Переписывать их с нуля — нет смысла, а вот пользоваться — одно удовольствие.
Почти всегда это либо игрушка на Си, либо программа управления чем-то большим и сложным.
В любом случае предлагать собственное решение для подобных случаев — не слишком хорошая идея. Пользователь вместо поиска оптимального решения, начнёт менять условия задачи.

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

Спасибо.
Постараюсь разобраться!

Может у меня мало опыта, но не видел ничего хуже HAL от ST. Дичайший оверхед при урезании функционала периферии.
Скомпилировал Hello World на STM32F0 с двумя USART'ами, каждый дескриптор USART_HandleTypeDef занимает по 122 байта драгоценнейшей оперативки. Зачем делать весь этот оверхед, когда ту же информацию можно прочесть из конфигурационных регистров периферии?

Вы совершенно правы!
Это наверное самая фиговая библиотека для BSP которую я видел, там действительно гиганский оверхед и куча маскросов в которых вообще нереально разобраться!
Но, важно, что он поддерживается производителем и вряд-ли умрет, а самому выгребать баги во всех драйверах, убиться можно. Я верю, что обеспечить поддержку реально для UARTа и еще нескольких устройств, но для более сложных, сильно сомневаюсь.
В общем мы пришли к такому подходу, только из-за того, что поддерживать все драйвера которые есть у нас, мы просто не в состоянии.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий