Pull to refresh

Comments 35

UFO just landed and posted this here
Ну, за отказ от макросов поклевать немного и можно :) В Contiki OS, не к ночи будь помянута, многозадачность построена на «протопотоках» (protothreads), очень забавной конструкции на чистых макросах, подобный же механизм используется в «со-процедурах» (coroutines) FreeRTOS. Сомневаюсь, что это можно обернуть в C++.
UFO just landed and posted this here
Ага, только на первый взгляд встроенные в язык coroutines мало чем отличаются от реализации их на макросах. Ну и если честно — как-то боязно использовать новые фичи C++ с компиляторами типа того же IAR.

Реализация на макросах не огромный ли switch внутрях использует? Если так, то у встроенных в язык сопрограмм есть два преимущества: в них можно использовать switch и в них нет логики по декодированию адреса инструкции из номера состояния.

По поводу Clion, да собирал тулчейн, + OpenOCD/GDB, плагином не пользовался. У меня STLink китайский через openOCD не прошивается, ресет не выведен на микронтроллер, приходилось при прошивке кнопку ресет рукой нажимать, поэтому плагин не подошёл, я подключился к STLink-Utility, и она после сборки и конвертации в двоичный файл прошивает, а потом уже запускается OpenOCD, чисто на отладку.
я для этого openocd запускал с дополнительным флагом -c “reset_config none separate”, чтобы работать без выведенного ресета. тогда идет сброс через swd
Еще раз спасибо, добавил перед reset этот ключ все заработало. Перед отладкой правда все равно приходится ресет рукой нажимать. Но все лучше, чем до.
Без простыни дефайнов ну никак жить нельзя


Есть задачи, которые не решаются без макросов(некоторые пока что)
Пара примеров:
* Q_OBJECT
* SCOPED_EXIT
* библиотека nan — там можно без макросов, но какой смысл
* включение различных участков кода
* поключение различных заголовочных файлов
UFO just landed and posted this here

У вас в исходниках thread.hpp опечаточка закралась: GetTaskHanlde

Спасибо, удалить надо этот метод вообще, не нужен он.
UFO just landed and posted this here
От операционной системы ожидаешь хоть какой-то изоляции от аппаратуры. А тут сразу «EXTI->PR = EXTI_PR_PR12;»… Наверное, стоило бы написать, что freertos занимается исключительно многозадачностью (треды, шедулинг, семафоры и т.д.), далеко не всем тем, чем обычные операционные системы занимаются.
Конкретно с FreeRTOS вечная путаница из-за того, что это не операционная система, а только ядро операционной системы, о чём чёрным по белому прямо в заголовке её сайта и сказано. Всё прочее там — обвес на усмотрение пользователя.

А ядро — это действительно треды, шедулер и IPC. Остальное не его забота.
Перефразируя агента Смита: «Мистер Андерсен, зачем Вам IPC, если у Вас нет процессов?».
Да это ядро, которое занимается многозадачностью, но как бы это и подразумевает под собой определение ОСРВ, по поводу прерываний и флагов, да в жизни так не используется. Есть промежуточный класс InterruptController, который все эти флаги скидывает, а потом вызывает обработчик конкртеного объекта, можно его сделать на основе механизма подписки, в итоге обработчик прерывания скажем кнопки из этого примера выглядел бы просто как:
void Button::HandleInterrupt() {       
         myTask.Signal();   
}

Но обвязку сделать уже не дело ОСРВ, так как этот механизм можно сделать по разному, можно сделать быстрым но жрущим много памяти, можно чтобы быстро, мало памяти, но много ручной работы,… т.е. не дело обертке решать за пользователя, как это реализовывать, так как зависит от конкретного проекта и контретных требований. Например, реализую я этот механизм с помощью шаблона подписчик, так чтобы любой мог подписаться на прерывание, но сколько этих подписчитков может быть? 10-100, динамически выделять память я же запретил себе :) Придется память выделить, а может у вас уже памяти нет. Поэтому пусть пользователь сам решает, как ему прерывание обрабатывать.
Для Cortex M4 «все» операционки используют 3 прерывания, прерывания System tick timer, System Service call via SWI instruction, Pendable request for system service, которые собственно в основном для ОСРВ и были придуманы


Есть нюанс. Tickless-системы — а это направление модное и правильное, вон Mbed сделали tickless с полгода назад — SysTick не используют, т.к. им by design не нужен регулярно тикающий таймер. За счёт этого у них ниже энергопотребление.

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

SysTick может не работать в режимах типа deep sleep; если же он все же работает — то относительно часто (при тактовой частоте всего 16 МГц — раз в секунду) генерирует прерывание и будит ядро.

Большой труд проделан. Подобная обёртка уже есть в CMSIS: CMSIS-RTOS
Насчет отказа от динамического выделения памяти — не согласен. У меня есть пару проектов, где контроллер работает в разных режимах, с разными наборами запущенных тасков, и без динамического выделения памяти — никак.

Спасибо, по поводу CMSIS-RTOS, я почитаю, чего-то CMSIS в виду спицифики работы, а именно опять же надежных применений нам запрещено использовать, я не использовал никогда, только заголовочник для упрощения доступа к регистрам модулей. А против динамического выделения памяти, вприципе я ничего против не имеею, иногда это упрощает жизнь, но опять же потому как SIL3 не рекомендует использовать динамическое выделение памяти приходится следовать эти рекомендациям.
Занятно, что список требований к ОС («никаких макросов», «никаких приведений типов») сильно совпадает с моими личными претензиями к FreeRTOS.
И все эти наслоения макросов из кишков фриртос никуда не деваются. И если использование операционки с этой прослойкой, действительно, должно упроститься, при отладке, если туда понадобится-таки лезть, мы опять упрёмся в void*, который надо привести к нужному типу, достать оттуда ещё один указатель, ещё раз привести…

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

Их обилие связано, в первую очередь, с тем, что фриртос запускается на очень большом зоопарке архитектур и на ооооочень большом зоопарке (музее?) компиляторов.
И там не пахнет не то чтоб плюсами, там банальных инлайн-функций вместо всех этих макросов нету…
Авторов FreeRTOS с таким подходом понять можно. Простить — сложнее :-)

В общем, моё мнение — эту обёртку можно использовать в каких-то особо странных случаях («мне нужно только freertos, потому что у неё сертификат, но самой freertos я видеть не хочу»). Иначе, если не хочется видеть фриртос — ей можно просто не пользоваться, благо альтернативы есть…
Все правильно, но автор ведь дал пояснения зачем он создал эту обёртку. В любом случае компилятор разберется с лишним кодом и оверхед не будет существенным. Когда приходится работать в команде и переносить куски кода на разные архитектуры, использование обёрток может сильно облегчить жизнь.
«Работать в команде» и «разные архитектуры» — это не про то. Командно переносить проект между архитектурами можно вместе с операционкой.
Тут про «переносить код на разные ос». И сейчас оно больше напоминает картинку «есть 14 конкурирующих стандартов»…
сначала мы использовали одну операционную систему, потом я для своих нужд начал использовать FreeRTOS, потом мы перешли на другую

А можно раскрыть тему: ЗАЧЕМ?!
Да, можно потому что вначале пользовали операционку, которая довольная старая, но очень популярная, после того, как мы наткнулись на 1001 баг в ней, мы решили от неё отказаться и перейти на более надежную с сертификатом надежности. FreeRtos я использую для обучения студентов. Сейчас договариваемся по использованию МАКС ОСРВ в университете.
Для Cortex M4 «все» операционки используют 3 прерывания, прерывания System tick timer, System Service call via SWI instruction, Pendable request for system service, которые собственно в основном для ОСРВ и были придуманы.

Для работы используются два — для переключения задач (обычно — PendSV_Handler) и для системного таймера (и тот только в обычном, не tickless, режиме).
SWI + SVC_Handler — это такой фриртосный костылик для запуска самой первой задачи.
Статья хорошая, но есть моменты которые врятли смогут претендовать на долгосрочную перспективу:
1. Зачем создавать враппер над «тредами», «семафорами», «мьютексами» и тп. если это уже было сделано в boost а также в стандартной библиотеке начиная с C++11.
(для использования достаточно создать POSIX совместимый враппер на С)
2. Любое упоминание об отказе от чего либо это всегда холивар. Вот выше у вас написано что вы не любите приведение типов и тут же приводите код который ими пестрит.
(С привидениями нет проблем если соблюдать правила описанные в соответсвующем стандарте)
3. Без динамической памяти жить в современном мире разработки очень и очень трудно. Например банальный паттерн PIMPL без ухищрений. Если необходимо уйти от фрагментации можно использовать memory pool, а также placement new.
Как жить без std::string и std::vector?
В любом случае идея написать враппер очень правильная и нужная. Сам писал в свое время(свой клас тред с шаблонным параметром размера стека, мьютексы и тп). Посмотрите в сторону использования библиотеки boost она не такая страшная как ее обычно рисуют в мире embedded.
1, Потому что IAR не совсем поддерживает thread (With C11 enabled, the IAR C/C++ Compiler for Arm can compile all C11 source code files, except for those that depend on thread-related system header files. The IAR C/C++ compiler does not support source code that depends on thread-related system headers.), и вообще микропроцессор не всегда имеет 512 кБайт ПЗУ и 64 кб ОЗУ, бывает и 32 кБ ПЗУ и 8 кБ ОЗУ — это именно для этих целей. Если вы выпускаете 100 000 датчиков в год, то 30 центов сэкономленных на процессоре, это 30 000 долларов, а если доллар уже 100 000. Представляете потери из-за того, что я решил выпендриться и использовать навороченную универсальную библиотеку или вектор?
2. Написано, что не отказ, а по возможности, это не моя прихоть, а требования стандартов надежности, да приведение типов есть, но они все из-за того, что по другому никак. Но избегать надо.
3. Вектор помогает, согласен, но жить без него можно :) также как и без стринга, когда у вас ограничения в ОЗУ. Boost хорошая библиоткеа, но половина из неё не будет работать с IAR, как не работает полностью atomic.
Мое мнение что мир emdedded разделен все таки на три части — 1 — это те кто делает, что-то на основе, чего-то типа Linux, вторые это те кто юзает большие микроконтроллеры с 1 МБ ПЗУ и 512 ОЗУ и третьи это те кто юзает небольшие до 256 кБайт ПЗУ и 32 кБ ОЗУ микро для датчиков — вот, я думаю, что как раз моя статься ориентирована на них, чтобы продвигать переход на С++. А так я полностью согласен с вами, чем больше уже готовых решений принимать, тем лучше, но все таки специфика есть везде…
Проблема даже не в том, что большой объем flash/ram в контроллер добавить дорого, а в том что эти универсальные библиотеки тредов/семафоров не дают реального времени на контроллерах. Оверхед слишком большой по времени, сложно потом все синхронизировать, особенно если нужно датчики тысячи раз в секунду опрашивать и еще что-то рассчитывать.
враппер над «тредами», «семафорами», «мьютексами» и тп. если это уже было сделано в boost а также в стандартной библиотеке начиная с C++11

Очевидно, треды и средства их синхронизации должны взаимодействовать с ядром ОС. Т.е. надо писать порт STL на конкретную операционку. Пока, к сожалению, таких супергероев не видно…

С привидениями нет проблем

Да нету никаких проблем с приведениями типов. Если никогда не ошибаться. А если в макрос, внутри которого cast на cast'е, передать что-то не то, компилятор это тихо сожрёт без каких-то варнингов.

Как жить без std::string и std::vector?

Продумать и описать протоколы, по которым идёт взаимодействие с внешним миром, статически выделить необходимые буферы (хоть сишные, хоть std::array), и жить…

Посмотрите в сторону использования библиотеки boost

В описываемом случае (контроллер относительно мелкий, malloc по каким-то соображениям не используется) лучше смотреть куда-то в район etlcpp.com. Бустом, правда, я никогда не пользовался — посмотрел, испугался, и закрыл.
Sign up to leave a comment.

Articles