Нюансы использования С++ с МК

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Нюансы использования С++ с МК

Сообщение isx »

День добрый!
Недавно начал использовать C++ для программирования STM32 и появились вопросы.
1) Почему все очень рекомендуют не использовать Exceptions?
Понятное дело, что это съедает некоторые ресурсы (при нужной конфигурации около 70кБ флеша как минимум), но если у меня жирный МК, то почему нет? Или есть другие подводные камни?
Просто как по мне - сделать стектрейс на эксепшнах это очень удобно. Вот пропустил ты в коде какой-то нюанс и поделилось что-то где-то на ноль. И всё - провалился в Hardfault, а откуда и почему - черт его знает. А с эксепшнами (если пробрасывать throw с описанием) мы можем найти как минимум метод.функцию, в которой произошла ошибка и отправить эту инфу в лог.
Но может я чего не знаю...
2) Почему используется связка FreeRTOS С++ вместо, казалось бы, очевидного std::task? Если язык уже предусматривает многозадачность и всё такое, то почему не использовать эти плюшки (тут я только рассуждаю, до практики не дошел)?

Всем спасибо за участие в дискуссии!
Аватара пользователя
HardWareMan
Мучитель микросхем
Сообщения: 429
Зарегистрирован: Ср сен 02, 2015 07:47:20

Re: Нюансы использования С++ с МК

Сообщение HardWareMan »

Команда SVC это тоже исключение. Которое специально разработано для использования пользователем для организации вызова функции ядра. Так и называется: SerVice_Call. Ну как INT # у х86. Так что лично моё мнение: если монолитный маленький код то лучше исключения не трогать (ну разве что правильно оформить HardFault, чтобы понимать кто вызвал). А если у вас любая ОС да ещё и загружаемые исполняемые модули то как раз надо использовать исключения по максимуму.
Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ
Актуальность репозитория: 22 апреля 2026 года
Если чего-то не хватает с сайта st.com - пишите, докачаю.
/!\ Обновлений для STM32PowerMon и STM32PowerMon-UCPD временно не будет.
tonyk
Это не хвост, это антенна
Сообщения: 1309
Зарегистрирован: Вт ноя 19, 2019 06:10:18

Re: Нюансы использования С++ с МК

Сообщение tonyk »

isx писал(а):1) Почему все очень рекомендуют не использовать Exceptions?
70к на исключения, 60к на stream. Тупо тратить время на заливку жалко.
Вот пропустил ты в коде какой-то нюанс..
...а твой МК управляет двигателем внутреннего сгорания. А ты там стэк раскручиваешь в поисках виновника, да?
поделилось что-то где-то на ноль
Для этого есть отдельные прерывания. Занимаюсь ПЛК, поэтому что там погромист понапишет в своей проге априори не известно, поэтому деление на ноль для меня нормальная ситуация, обработка которой занимает минимум тактов.
очевидного std::task
Так это всего лишь шаблон. Наполни его смыслом и используй. А я по-старинке:

Код: Выделить всё

////////////////////////////////////////////////////////////////////////////////

class Task : protected TaskBase 
{
    protected:

        Task
        (
            char const*             name, 
            unsigned portBASE_TYPE  priority    = ( tskIDLE_PRIORITY + 1 ), 
            unsigned portSHORT      stackDepth  = configMINIMAL_STACK_SIZE
        );

        virtual ~Task( void );

        virtual void run( void ) = 0;
......
Аватара пользователя
HardWareMan
Мучитель микросхем
Сообщения: 429
Зарегистрирован: Ср сен 02, 2015 07:47:20

Re: Нюансы использования С++ с МК

Сообщение HardWareMan »

[uquote="tonyk",url="/forum/viewtopic.php?p=4626175#p4626175"]твой МК управляет двигателем внутреннего сгорания. А ты там стэк раскручиваешь в поисках виновника, да?[/uquote]
И пусть весь мир подождёт! (с)
Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ
Актуальность репозитория: 22 апреля 2026 года
Если чего-то не хватает с сайта st.com - пишите, докачаю.
/!\ Обновлений для STM32PowerMon и STM32PowerMon-UCPD временно не будет.
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Re: Нюансы использования С++ с МК

Сообщение isx »

HardWareMan писал(а):А если у вас любая ОС да ещё и загружаемые исполняемые модули то как раз надо использовать исключения по максимуму
Лично я за время написания кода убедился, что код надо унифицировать максимально. Есть у тебя сегодня проект, в котором используетс какой-то парсер - делай так, как будто завтра тебе его использовать в новом проекте. Соответственно, если уж начал работать с эксепшнами, то и делай так же, чтоб в любом проекте в дальнейшем этот код переиспользовать можно было.
Само собой есть исключения - когда надо например засунуть что-то большое во что-то маленькое. Но и тут как бы стоит ли овчинка выделки... Цена на МК сейчас не космос, а время разработки ресурс ценный. Если только мы не о крупносерйном производстве, тогда можно и подумать.
Это мое мнение.
tonyk писал(а):60к на stream
Исключение и без стримов вроде работают.
tonyk писал(а):а твой МК управляет двигателем внутреннего сгорания
Тут тоже палка о двух концах. С одной стороны да, тратим ресурсы вычислительные, но с другой стороны - исключения штука исключительная и если мы попали в catch, то значит всё хреново. И в таком случае, в некоторых ситуациях, предпочтительнее будет узнать место возникновение ошибки.
Но опять таки, все индивидуально - если у нас счет на микросекунды, то там в прерываниях за каждый таки жопа горит)
Кстати, а что будет если мы словили исключение и в это время вызвался обработчик прерывания? У него приоритет будет выше или эксепшны работают на каком-то высшем приоритете?
tonyk писал(а):Так это всего лишь шаблон
Я просто вообще ни одного упоминания не видел в сети об использовании тасков. Везде FreeRTOS. Как будто эти таски в принципе не поддерживаются или требуют мегабайт памяти. Вот и стало интересно)
tonyk
Это не хвост, это антенна
Сообщения: 1309
Зарегистрирован: Вт ноя 19, 2019 06:10:18

Re: Нюансы использования С++ с МК

Сообщение tonyk »

isx писал(а):Исключение и без стримов вроде работают.
Мой сарказм оказался не понят: ты ещё ничего не написал, а 130К памяти уже занял.
Соответственно, если уж начал работать с эксепшнами...
...то это означает, что работа программы проверена не со всеми возможными значениями входных данных.
Аватара пользователя
azhel12
Встал на лапы
Сообщения: 145
Зарегистрирован: Пн апр 02, 2012 15:56:23

Re: Нюансы использования С++ с МК

Сообщение azhel12 »

Как любитель плюсов, не могу пройти мимо и не вставить 5 копеек:
1. В общем-то только лишнее потребление памяти + использование кучи для создания объектов исключений, что в серьезных проектах не допускается.
Даже в десктопах многие отказываются от исключений, тем более в c++23 появился std::expected
2. Тут всё просто, в тулчейне для МК просто нет реализации std::task (и многих других элементов стандартной библиотеки).
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Re: Нюансы использования С++ с МК

Сообщение isx »

azhel12 писал(а):лишнее потребление памяти + использование кучи для создания объектов исключений
Потребление памяти это да, но создание объектов в куче будет только в исключительных случаях - когда без эксепшна будет HardFault. Из обработчика HardFault, насколько мне известно, нельзя продолжить программу и он не дает информации о файле и методе, в котором было выброшено исключение.
azhel12 писал(а):Даже в десктопах многие отказываются от исключений
А как тогда делать нормальное логгирование? Ладно МК, но в десктопе кода в разы больше и без эксепшнов (особенно используя сторонние библиотеки) отладка вообще превращается в n-й круг ада)
azhel12 писал(а): std::expected
Не слышал о такой штуке, спасибо, изучу на досуге.
azhel12 писал(а):в тулчейне для МК просто нет реализации std::task
Даже если выбрать полношенный GNU17?
tonyk писал(а):...то это означает, что работа программы проверена не со всеми возможными значениями входных данных.
У меня как-то мама спрашивала: "А зачем программисты постоянно переписывают то, что уже написали, почему сразу не написать чтоб нормально работало?" :)
tonyk
Это не хвост, это антенна
Сообщения: 1309
Зарегистрирован: Вт ноя 19, 2019 06:10:18

Re: Нюансы использования С++ с МК

Сообщение tonyk »

isx писал(а):но создание объектов в куче будет только в исключительных случаях
Промышленные стандарты на функциональную безопасность ПО запрещают использовать динамическое распределение памяти. Некоторые стандарты допускают его использование до входа в главный цикл программы.
isx писал(а):У меня как-то мама спрашивала: "А зачем программисты постоянно переписывают то, что уже написали, почему сразу не написать чтоб нормально работало?" :)
Потому, что не все умеют писать сразу правильно. Вы часто едите в автосервис для очередного апгрейда ПО в ЭБУ двигателя вашего авто?
Базилюк
Нашел транзистор. Понюхал.
Сообщения: 159
Зарегистрирован: Чт сен 19, 2024 19:18:28

Re: Нюансы использования С++ с МК

Сообщение Базилюк »

Вообще, довольно интересная тема затронута. Я ранее тоже задавался таким вопросом. Ведь возникший аппаратный HardFault - это уже констатация факта, что "шеф, всё пропало". А вот программный "отловитель" ошибочных данных - штука весьма даже полезная.
Гипотетический пример - есть три датчика температуры воды в нагревателе. И вдруг с одного датчика приходят сильно отличающиеся от остальных датчиков показания. Нужно выполнить отбраковку этого датчика. И стандартный механизм проброски исключения, встроенный в язык С++, здесь как раз пригодится. То есть, будет какой-то общий вид, общий синтаксис для исключительных ситуаций работы кода.
С другой стороны, унифицированные решения, как правило, более тяжеловесные по сравнению со специализированным решением "по месту". Что и подтверждается увеличенным расходом памяти при использовании межанизма исключений языка С++.
Механизм исключений микроконтроллера - это уже аппаратная защита, а не программная, и вобщемто, кроме перезапуска МК ничего более сделать нельзя. То есть, когда неверные данные с заглючившего датчика вызовут HF, останется только перезапустить МК с потерей накопленной работы. А вот программное исключение позволит отбраковать датчик, дающий ложные показания и не учитывать его в работе.
Аппаратное исключение ядра SVC используется RTOS для переключения контекста, поэтому не подходит для пользовательских исключений.

По второй части вопроса: А вот потому, что ядро FreeRTOS написано на Си, а не на С++. И опять же, универсальное решение на базе языка С++ будет более тяжеловесным, чем написанное в FreeRTOS. В ней же не зря есть участки кода даже на ассемблере, потому что это именно специализированное решение для более быстрой работы.
Лично я за время написания кода убедился, что код надо унифицировать максимально.
В целом, нет, не согласен. Потому что, еще раз повторюсь, унифицированное решение - медленнее и тяжеловеснее специализированного. Если вы говорите, что типа да какая разница, памяти и частоты нынче в МК хватает, то посмотрите на смартфоны - размеры памяти в них выросли уже до 512 - 1024 ГБ, но и размеры приложений не отстают - каждое приложение по несколько сотен мегабайт, хотя оно работает практически так же, как и несколько лет назад, когда размер приложения измерялся в десятках мегабайт. И с аккумулятором та же ерунда - его ёмкость растет, уже 5,5 А-ч, а время автономности ровно то же самое, что и 10 лет назад с гораздо меньшим аккумулятором.
Человечество "вошло в петлю", когда гонка за скоростью выдачи обновлений ПО или новой модификации смартфона стала выдавать весьма низкокачественные продукты, практически не оттестированные. То есть, уже никого не интересует качество продукта, интересует только "а чо нового сделали". Рано или поздно такая концепция подойдет к "красной черте". Хотя, я прекрасно понимаю, что сейчас переубедить никого невозможно, все ослепли и оглохли в этой погоне, не замечая, что их творение уже через пару месяцев никому не нужно, потому как было выпущено "обновление с целью исправления багов". :)
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Re: Нюансы использования С++ с МК

Сообщение isx »

tonyk писал(а):Промышленные стандарты на функциональную безопасность ПО запрещают использовать динамическое распределение памяти
Интересно, не знал об этом.
tonyk писал(а):Потому, что не все умеют писать сразу правильно. Вы часто едите в автосервис для очередного апгрейда ПО в ЭБУ двигателя вашего авто?
Подискутировал бы, но не знаком глубоко с устройством ЭБУ. Может там отдельный МК для критических задач, которых в целом, не так и много, да и сложности я не вижу в них большой. А может и в чем другом дело...
Базилюк писал(а):Гипотетический пример - есть три датчика температуры воды в нагревателе
Вот это как раз случай, когда исключения лучше не использовать. Эта ошибка может быть обработана просто возвратом сообщения о невалидных данных.
Я имел в виду более сложные в обработке ситуации типа обращения к указателю с несуществующим блоком памяти, либо когда память была затерта и т.п.

Кстати, я тут поразмышлял и придумал интересную схему (а может и изобрел велосипед).
Как я говорил, мне исключения интересны больше тем, что позволяют размотать стек и посмотреть из каого класса и метода оно было выброшено.
Схема такая:
- создаем в каждом классе статическое константное поле с именем класса и в каждом методе такое же, но с именем метода
- делаем два глобальных статических указателя
- при каждом заходе в какую-либо функцию или метод назначаем этим указателям адреса наименований класса и фонкции\метода соответственно
- в обработчике HardFault берем значения из этих переменных, копируем в выделенную область энергонезависимой памяти, в которой также ставим флаг о наличии ошибки. Можно еще добавить инфу об инструкции из регистров.
- при перезапуске МК после инициализации добавляем проверку этого флага и если он выставлен, то что-то делаем (например передаем на сервер сохраненные строки с методом и классом), очищаем флаг и строки в энергонезависимой памяти.

Вместо наименования класса можно использовать namespace, имя файла или т.п. Пока не пришел к решению, что более эффективно.

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

В качестве расширения можно реализовать операции изменения статических переменных в виде define, что позволит иметь возможность изменять логику работы из одной точки кода + включать и отключать их когда нужно (например, отключить в продакшене, по каким-то причинам).
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

Re: Нюансы использования С++ с МК

Сообщение Martian »

[uquote="isx",url="/forum/viewtopic.php?p=4627306#p4627306"]Я имел в виду более сложные в обработке ситуации типа обращения к указателю с несуществующим блоком памяти, либо когда память была затерта и т.п.[/uquote]
Необходимо делать ещё исключение, которое отловит, что память затёрлась в вызове того исключения. И желательно ещё одно исключение, которое беду и с этим сторожевым исключением отловит.
В общем, вместо main сразу писать try
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Re: Нюансы использования С++ с МК

Сообщение isx »

Martian писал(а):вместо main сразу писать try
Зря смеетесь - на десктопе в c# я примерно так и делаю - в итоге код отсаживается в разы быстрее, так как ни одна проблема не может привести к крашу приложения (если catch правильно отработан), даже сторонние библиотеки, которые имеют свойство падать по неизвестным причинам, а абсолютно вся инфа о проблемах сохраняется в логи.
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

Re: Нюансы использования С++ с МК

Сообщение Martian »

Тоже работаю с C#. Но так не делаю. И как-то никто пока не жаловался.
Кроме того, программирование десктопных приложений и "железяк" несколько отличается.

А что такое "код отсаживается"?

Добавлено after 5 hours 44 seconds:
А вообще, это, наверное, всё субъективно плюс местячково (то есть, зависит от внешних условий, накладываемых компанией, командой, ТЗ и т.д.). В конечном итоге, важен лишь результат.
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Re: Нюансы использования С++ с МК

Сообщение isx »

Martian писал(а):Тоже работаю с C#. Но так не делаю. И как-то никто пока не жаловался.
Да я не к тому что жаловался, а к тому, что такой подход имеет место быть. Если будет проект с кучей кривых библиотек, то попробуйте, отладка в разы упростится)
Ну да, самом собой применимо к десктопу, на МК бы так не делал (пока не знаю всей нутряную блока try, поэтому непонятно как оно бьет по производительности. Надо будет затестить)
Martian писал(а):А что такое "код отсаживается"?
Отлаживается)

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

Но это оффтоп.
Кто еще даст замечания по архитектуре «заменителя эксешнов»?
Базилюк
Нашел транзистор. Понюхал.
Сообщения: 159
Зарегистрирован: Чт сен 19, 2024 19:18:28

Re: Нюансы использования С++ с МК

Сообщение Базилюк »

[uquote="isx",url="/forum/viewtopic.php?p=4627306#p4627306"][q обработке ситуации типа обращения к указателю с несуществующим блоком памяти, либо когда память была затерта и т.п..[/uquote]
Аппаратный HF прекрасно справляется с обращением к несуществующей памяти. Да, это ошибка программиста.
Поврежденные данные в ОЗУ, вернее, ошибочный доступ к ним, может отслеживать аппаратный механизм MPU, там, где он есть. Так же, API FreeRTOS имеет механизм отслеживания переполнения стека задачи. Иными способами определить, затерлись ли данные, не получится. Данные сами по себе никакого флага валидности не имеют и затертые данные ничем не отличаются от незатертых. Их повреждение можно определить только косвенно.

[uquote="isx",url="/forum/viewtopic.php?p=4627306#p4627306"]в обработчике HardFault берем з.....[/uquote]
Почитайте о том, что сохраняется при HF аппаратно и какая инфа там есть. А так же, какие события приводят к HF.
[uquote="isx",url="/forum/viewtopic.php?p=4627306#p4627306"]- создаем в каждом классе статическое константное поле с именем класса и в каждом методе такое же, но ...[/uquote]
но эта штука сильно утяжелит код и замедлит его. Если и добавлять такую инфу, то не в каждый метод и класс - это уж точно.
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Нюансы использования С++ с МК

Сообщение jcxz »

[uquote="isx",url="/forum/viewtopic.php?p=4627306#p4627306"]Схема такая:
- создаем в каждом классе статическое константное поле с именем класса и в каждом методе такое же, но с именем метода
- делаем два глобальных статических указателя
- при каждом заходе в какую-либо функцию или метод назначаем этим указателям адреса наименований класса и фонкции\метода соответственно
- в обработчике HardFault берем значения из этих переменных, копируем в выделенную область энергонезависимой памяти, в которой также ставим флаг о наличии ошибки. Можно еще добавить инфу об инструкции из регистров.[/uquote]Ну-ну... :))) Про многозадачные системы вы видимо никогда не слышали и всегда программируете только суперлуп да ещё и без прерываний.
В любой многозадачной среде такой подход бесперспективен. Так как первое же переключение контекста (задачи), поставит крест на вашей супер-системе.

[uquote="isx",url="/forum/viewtopic.php?p=4627306#p4627306"]В обработчиках прерываний только вот нужно будет 6, так как сначала текущие адреса нужно сохранить во временную переменную, изменить указатели на имя обработчика, а потом при выходе вернуть прежние значения.[/uquote]А во вложенных обработчиках прерываний? не подумали? 8)
А в ARM уровень вложенности ISR может быть весьма большим....

PS: Очередной лисапед с квадратными колёсами, который и по ровной дороге-то толкать надо. А на ухабах так и вся попа велосипедостроителя в занозах будет. :)))
Для отслеживания места сбоя сохраняют регистры, кадр стека и регистры HF. А не монстроидальные классы лепят.
А ещё лепше, когда микроконтроллер имеет ETB. Вот тут просто халва, а не отладка.
Ответить

Вернуться в «ARM»