Современные микроконтроллеры имеют достаточно большую производительность и это дает многим программистом возможность думать в примерно следующем ключе: — «Ничего страшного, если 1-5% производительности уйдут на обслуживание операционной системы. Зато мой код будет легко отлаживаемый и явный!». Эти мысли подкрепляются большим количеством энергонезависимой (flash) памяти для хранения кода операционной системы и оперативной (RAM/SRAM) памяти для выделения под каждую задачу своего стека. Однако в большинстве случаев эта мысль ошибочна. И в данной статье я расскажу, почему.

О проектах, с которыми я работаю


В своей практике мне часто приходится работать с «конструктором». Я подробно описывал такой подход в своей предыдущей статье, посвящённой использованию C++ в микроконтроллерах. Тогда я не рассказал самое главное. Большинство «блоков» данного «конструктора» так или иначе завязаны на операционной системе реального времени. Большинство «блоков» имеют по собственному потоку (task, в терминах используемой операционной системы реального времени FreeRTOS). И того, в среднем, на проект приходится порядка 10-15 задач. Иногда это значение доходит до 35-40.

Куда столько?


Вот краткий перечень задач, которые встречаются в каждом проекте:
  • обслуживание АЦП (каждый модуль обслуживается своим потоком);
  • обслуживание wdt (если ОС упала, то задача его не сбросит и устройство перезагрузится);
  • работа со страницами настроек (отдельный поток контролирует работу с flash памятью);
  • обслуживание протокола взаимодействия с внешним миром (по потоку на интерфейс. Например, uart);

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

Кажущаяся простота


Несмотря на то, что в проекте много задач, каждая из них «спрятана» внутри объекта соответствующего класса (помним, что конструктор на C++, однако это можно сымитировать и на C, используя «программирование на C в объектно ориентированном стиле». Но лучше не надо). Так как объекты этого «конструктора» глобальны и в проектах используется FreeRTOS 9, поддерживающий создание собственных сущностей в буферы, выделенные пользователем, то использование памяти можно проконтролировать еще на этапе компоновки. Так что с точки зрения контроля утечек памяти — все более или менее нормально. Но есть следующие нюансы:
  • требуется четко осознавать, сколько потребуется стека для каждого потока. При этом:
    • нужно учитывать критичные случаи (например, вложенность при определенном поведении);
    • если используются функции из стандартных библиотек, тогда еще и знать как они устроены, или хотя бы иметь представление о том, сколько они будут потреблять стека;

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

Злоупотребление функционалом операционной системы


Основные же проблемы начинаются в тот момент, когда вы начинаете забывать, что пишете именно под микроконтроллер. ОС накладывает свои расходы на работу с собственными сущностями (такими как семафоры, мутексы, очереди). Вот пример UART класса для реализации функции терминала. В прерывании идет прием байта, после чего, в случае, если он проходит диапазон на допустимые входные символы, он добавляется в очередь с соответствующими заменами (например '\n' меняется на последовательность "\n\r"). Так было сделано для того, чтобы обезопасить порт на отправку (поскольку порт может работать не только как терминал. Через него могут отправляться еще и log-данные). С одной стороны это дает гарантию того, что ответ будет отправлен при первой же возможности и не будет мешать отправке более приоритетных данных (к тому же пока отправляются более приоритетные данные — идет накопление в буфер, что позволяет потом задействовать DMA для отправки ответа). Однако уже начиная с этого момента вы встаете на скользкую дорожку. Вместо того, чтобы писать связку через очередь, можно было бы просто верно настроить прерывание по непустому буферу, не работающему в данный момент UART-у и окончании работы DMA. Такой подход требует чёткого понимания того, как работает периферия. Однако снижает издержки до абсолютного минимума, делая надобность в подобном решении нулевой.

Игнорирование аппаратного функционала микроконтроллера


В своей практике я встречал проект с 18-ю программными таймерами операционной системы, настроенными на одну и ту же частоту. При этом в микроконтроллере было порядка 10 таймеров, из которых использовался только systic. Для тактирования планировщика операционной системы. Такое решение объяснялось отсутствием желания «возиться с аппаратной частью» микроконтроллера. При этом под стек для функции, вызываемой программным таймером отводилось порядка 10 кб. На деле же использовалось порядка 1 кб (не доходя). Это объяснялось «неясностью происходящего внутри вызываемых библиотек».
В данном случае можно было смело выделить TIM6 (в случае использования stm32f4), который бы генерировал прерывание с заданной частотой и внутри просто вызывались бы требуемые функции.

Использование бесконечного цикла вместо конечного автомата


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

Игнорирование «аппаратного планировщика»


Во многих тридцати двух битных микроконтроллерах есть продуманный контроллер прерываний с настраиваемой системой приоритетов. В случае stm32f4 он имеет название NVIC, и имеет возможность настраивать приоритеты прерываний с 16 уровнями (не рассматривая еще и подуровни).
Большинство приложений под FreeRTOS, с которыми мне пришлось столкнуться могли бы быть написаны как конечные автоматы, вызываемые в прерываниях с верно настроенными приоритетами. А в случае возвращения процессора к «нормальному выполнению» — отправляться «спать». При этом отпала бы необходимость в блокировании доступа к большинству ресурсов (переменным и прочему). Приложения лишились бы лишнего уровня абстракции. Причем в данном случае — далеко не бесплатного. Однако такой подход требует вдумчивого планирования архитектуры для каждого проекта. В проектах «конструкторах» — все прерывания имеют один приоритет и, по сути, нужны для того, чтобы «отфильтровать» данные. После чего положить остатки в очередь, откуда их заберет поток объекта соответствующего класса.

Итоги


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

Комментарии (58)


  1. newpavlov
    25.07.2019 15:36

    Несколько оффтопик, но хотелось бы узнать мнение автора: смотрели ли вы в сторону Rust и его подхода (см. ещё rtfm) к программированию микроконтроллеров? Чего по вашему мнению не хватает на данный момент языку в данной области (ну кроме официальной поддержки производителями железа)?


    1. Vadimatorikda Автор
      25.07.2019 15:42

      К сожалению о Rust знаю лишь по наслышке. По-этому не могу ничего сказать на этот счет. Думаю есть на хабре люди, которые смогу высказать свое мнение по этому вопросу.
      Опять же ИМХО, но для себя выбрал путь «Си для драйверов + Lua для логики». Поскольку в моей практике редко встречаются устройства с «золотой серединой». Это либо совсем уж «преобразователи протоколов» (там нет никакой Lua. Драйвера и пара функций). Либо уж совсем монстры (GUI, логика переходов сравнимая с игровыми ботами...). Но к Rust присматриваюсь чисто в академических целях. Может в будущем займусь всерьез.


  1. emmibox
    25.07.2019 15:50

    Современные разработчики просто не имеют бэкграунда в виде создания кода без РТОС, поэтому для них состояние «отсутствия РТОС» не является альтернативным подходом, и у них нет выбора между этими подходами с оценкой преимуществ и недостатков каждого.


    1. Vadimatorikda Автор
      25.07.2019 16:08

      Сомневаюсь, что дело в этом. ОСРВ в МК не дает особых преимуществ над железом (если речь о FreeRTOS). Поскольку она дает лишь базовые вещи. Потоки и их средства синхронизации. Другое дело «ОС со встроенным аппаратным уровнем», каких сейчас тоже не мало. Там да. Есть и uart.tx() встроенные и прочие.


      1. emmibox
        25.07.2019 16:53

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


        1. Vadimatorikda Автор
          25.07.2019 17:27

          Ну если в этом смысле, то возможно. Хотя и не факт. Например бытует мнение о том, что в прерываниях нужно делать «минимум работы». А остатки уже в основной программе. Это не совсем справедливо для «больших» микроконтроллеров. Из-за наличия NVIC (о чем было в статье).


    1. NordicEnergy
      25.07.2019 21:09
      +1

      Кто эти разработчики? Вот я вообще не использую rtos, как и любой другой разработчик, пишущий код для устройств критичных к времени реакции, читай real-time. RTOS — это безусловно удобно, но во многих задачах их не применить по объективным причинам.


      1. emmibox
        25.07.2019 22:56
        -1

        Наверно вы не современный разработчик… Хотя бы потому, что RTOS как раз и создана для того чтоб писать код устройств критичных по времени реакции — и c ее помощью может быть решен весь класс таких задач. Вопрос лишь в цене такого решения, и моменте, когда эта цена становиться оправданной.


        1. lingvo
          26.07.2019 13:11

          Как только вы начинаете решать с помощью RTOS задачи, для которых не нужно реальное время, что-то начинает идти не так...


          1. emmibox
            27.07.2019 11:49

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


            1. Vadimatorikda Автор
              27.07.2019 11:50

              Вот только нужны ли в микроконтроллере «под сотню» задач — вопрос отдельный.


      1. Gorthauer87
        26.07.2019 10:02

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


    1. KonstantinSpb
      25.07.2019 23:21
      +2

      А еще некоторые разработчики думают, что ОСРВ это такие же ОС, как и общего назначения, только упрощенные. Да, и многие реализации так называемых РТОС в качестве планировщика имеют RR, когда в реальности должен быть либо Rate-Monotonic, либо EDF. Не многие знают, что надо производить Wcet анализ и прочие анализы, что система справится в пиковых нагрузках и не будет встреча с deadline-ом. и.т.п.

      А еще, чтобы облегчить себе жизнь, есть инструменты вроде
      www.state-machine.com/qm
      www.uppaal.org
      и.т.п.


  1. Ksiw
    25.07.2019 19:12

    Vadimatorikda, что же насчёт мьютексов? Тут очень важный аспект.


    1. Vadimatorikda Автор
      26.07.2019 03:06

      Нет потоков и ОС — нет mutex-ов.
      А если серьезно, то правильно настроив NVIC — можно получить такой код, когда такой проблемы не возникает.
      Насколько я знаю, еще есть средства самого языка для атомарного доступа. Но ими я не пользовался, увы. Не было необходимости. Так что буду знать, если знатоки напомнят. std::...;
      Иногда приходилось применять «костыль» с блокировкой всех прерываний и последующим возобновлением. Так как это дело пары команд ассемблера, то ничего ИМХО, страшного.


    1. juramehanik
      26.07.2019 09:49

      нет мютексов, не беда, в кортексе есть LDREX и STREX
      we.easyelectronics.ru/STM32/atomarnye-operacii-v-cortex-m3.html
      Но опять же это к вопросу умения работы с периферией.


      1. Vadimatorikda Автор
        26.07.2019 10:14

        Спасибо. Давно не использовал.


      1. LennyB
        26.07.2019 16:10

        В M0 нет, увы.


  1. avf1906
    25.07.2019 21:06

    неубедительно :)
    — умение работать с периферией ортогонально использованию ОС.
    — что за жуткие таймеры занимающие 1кб? для того что бы использовать один аппаратный таймер для отметки 10 интервалов достаточно 10 32-битных переменных или task_sleep. Неумение использовать таймеры никоим образом не относится к недостаткам ОС. А для аппаратных таймеров найдутся другие важные задачи. У меня в одном из проектов аппаратными задачами были заняты 11 таймеров из 13, и как быть по вашему, если нужно 5 интервалов?
    — какая религия запрещает использовать конечные автоматы совместно с ОС?
    Я не фанат ОС, использую приблизительно в 1 из 3 проектов, и не всегда FreeRtos, где полегче TNKernel и ее форк TNeo использую, но Ваши аргументы абсолютно неубедительны и сводятся к тому, что инструмент в кривых руках работает криво. Так это вроде очевидно и не только к ОС и МК относится.


    1. Orange11Sky
      25.07.2019 22:22
      +1

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


  1. Amomum
    25.07.2019 21:23

    На мой взгляд основной минус использования ОС — это трудноуловимые баги. Два дня сидишь, взявшись за голову, потому что вообще непонятно, что происходит. Просто HardFault в случайный момент времени, в стеке вызовов мусор.


    А потом оказывается, что...

    При использовании FreeRTOS на stm32 прерывания, которые используют системные вызовы, обязательно должны иметь приоритет ниже, чем прерывание, которое вызывает диспетчер. Источник. Конечно, это должен проверять ассерт, жаль, что он по-умолчанию выключен!


    1. Nick_Shl
      26.07.2019 02:23

      По первому — RTFM.
      По второму тоже самое, но дам подсказку: www.freertos.org/Stacks-and-stack-overflow-checking.html
      Учитесь сначала читать документацию, а потом использовать все доступные средства. А если все делать методом "тыка", то да, баги становятся трудноуловимыми…


      1. Amomum
        26.07.2019 12:47

        Спасибо, я уже в курсе.


        По первому — да, конечно, кто ж спорит. Только вот ссылку на это я сейчас полчаса искал — и это я знал, что искать! Документация на FreeRTOS оставляет желать лучшего, прямо скажем.


        По второму — как вы, наверное, тоже в курсе, эта защита от переполнения не является идеальной (по вашей ссылке так и написано); полностью спастись можно только с MPU, которое есть далеко не всегда.


        1. Vadimatorikda Автор
          26.07.2019 13:27

          Ну и настройка MPU — это далеко не тривиальная задача. Чего стоит только выравнивание.


        1. Nick_Shl
          27.07.2019 05:09

          Ну да, если она переполнит стек положив туда точно такие же значения, какие использует RTOS для проверки — тогда да, не сработает.


          1. Amomum
            27.07.2019 13:15

            Или, например, если переполнение вызвано прерыванием и приведет к hard fault'у до проверки. Вариантов достаточно много.
            Разумеется, проверки — вещь не бесполезная, просто нужно осознавать, что это не панацея.


            1. Vadimatorikda Автор
              27.07.2019 13:20

              Ну а так же, что «не бесплатная». Именно поэтому нужно понимать, когда стоит их включать, а когда нет. В конечном продукте (в идеале) они бесполезны и их можно отключать. Само собой, если просчитаны всевозможные случаи и гарантируется, что стек не будет переполнен ни при каких обстоятельствах.


    1. Ryppka
      26.07.2019 08:17

      Вроде во FreeRTOS прерывания на другом стеке работают, даже регистры разные?


      1. Amomum
        26.07.2019 12:50

        Может быть, вы имеете в виду, что регистр SP другой (не MSP, а PSP)?


        1. Ryppka
          26.07.2019 13:34

          Именно. А что, там одно и то же значение оказывается. А то я не вникал в тему, если честно.


          1. Amomum
            26.07.2019 13:52

            Вроде по-умолчанию нигде дополнительный стек не выделяется. И на практике стек прерывания будет просто стеком прерываемой задачи.


        1. AVI-crak
          26.07.2019 14:09

          habr.com/ru/users/Amomum
          Всё так, только полностью наоборот. MSP который использовался в системе без ос — теперь обслуживает прерывания. PSP предназначен для задач, и его можно переключать из прерывания.


  1. ittakir
    25.07.2019 21:31
    +2

    Я в не очень крупных проектах использую кооперативную многозадачность.
    Каждый объект имеет функцию processEvents() в которой он проверяет, нужно ли ему что-то сделать, выполняет это, или сразу делает возврат из функции.
    В main() у меня бесконечный цикл, в котором для каждого объекта вызывается processEvents():

    for(;;) {
        uart.processEvents();
        spi.processEvents();
        webServer.processEvents();
        ...
        sleep();
    }

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

    Преимущества такого подхода:
    1. Все предельно просто. Не нужно никаких RTOS, есть только одна функция, которая периодически вызывается.
    2. Не нужны мьютексы для синхронизации между задачами. Однако, не забываем про прерывания!
    3. Не нужно выделять память на каждую задачу отдельно. Достаточно такого количества памяти, что потребляет самая ресурсоемкая задача.

    Недостатки:
    1. Не так круто, когда у тебя под капотом банальный бесконечный цикл, а не RTOS.
    2. Время исполнения задачи не должно быть слишком большим. Это не значит что нельзя делать какой-то очень длительный расчет, просто придется его бить на части и запоминать промежуточные результаты.
    3. Возможно, не так энергоэффективно, как RTOS. Хотя если работы у задач нету, они все быстро исполнятся и CPU уйдет в сон.

    С RTOS мне лично не понравился именно момент с назначением количества памяти каждой задаче. Мало дашь — получишь очень трудноуловимый баг с порчей соседних задач. Много дашь — памяти не хватит, задач то много.


    1. Nick_Shl
      26.07.2019 02:25

      Как и участнику выше, дам ссылку: www.freertos.org/Stacks-and-stack-overflow-checking.html, что бы баги стали менее "трудноуловимыми".


      1. Vadimatorikda Автор
        26.07.2019 03:14

        По моему опыту — не всегда помогает. Увы. Например работал с одной GUI библиотекой, которая позиционировала себя «как для МК», а на деле там был ад. Так вот. Она отжирала порядка 40 кб для 128 на 64 пикселя монохромного экрана (как потом выяснилось). При этом еще и умудрилась успеть залезть на кусок переменных планировщика и структур описания потоков и других внутренних штук. Это было очень сложно отлавливать, потому что в hard я падал именно при попытке сменить задачу)


        1. Nick_Shl
          26.07.2019 04:10

          Для такого экрана можно и самому писать библиотеку. Ничего сложного там нет. Я делал для экрана на чипе ST7920 кажется. И надо там всего 1 Кб под буфер экрана.
          Но куда проще взять чужой непроверенный код, а потом жаловаться, что "RTOS — это плохо". Если там ошибка, которая заставляет её срать в память, что точно так же она может убить что-нибудь и без RTOS. Причем если это не выяснится при написании(и вы будете думать, что все хорошо), то выяснится уже в продакшене, что гораздо хуже.


          1. Vadimatorikda Автор
            26.07.2019 04:33

            Ну так я и не говорю, что ОС в этом виновата. Я лишь отметил, что при таком стечении обстоятельств разобраться без ОС было бы проще. Поскольку в pc-регистре было бы чуть более адекватное значение, чем функция переключения контекста. А про библиотеку — требование заказчика. У них эта библиотека использовалась для цветного экрана прошлым программистом. И в ТЗ она была обязательной. А т.к. с закрытым кодом, то пришлось еще и писать авторам и выяснять, что да почему (они лишь давали .a + .h под разные архитектуры).


            1. Nick_Shl
              27.07.2019 05:12

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


  1. MacIn
    25.07.2019 22:16
    +2

    Однако в большинстве случаев эта мысль ошибочна. И в данной статье я расскажу, почему.

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


    1. Vadimatorikda Автор
      26.07.2019 03:17

      Да, про фатальность получилось не сильно ярко. Я привел пример с UART-ом. Это можно сказать «из реального прадакшена». Просто чуть упрощенный, чтобы ко мне не было вопросов. Там видно, что код становится неявным. Поток данных почему-то засовывается в очередь. Из этой очереди потом идет отправка обратно. Какое-то накопление байт зачем-то в буфере…


      1. MacIn
        26.07.2019 17:14

        Да, но в этом примере как раз просто показано, что есть два подхода: один, который вам люб по тем или иным причинам, и другой, который нет.
        Чем плоха стыковка через очередь — из этого описания непонятно. Т.е. если это съедает слишком много ресурсов, что становится критичным — тогда вопросов нет. Но иначе-то — в чем проблема использования такой абстракции?


        1. Vadimatorikda Автор
          26.07.2019 20:30

          Согласен. Данный пример только дает возможность выбрать между методами. Но к сожалению, кода аналогичного тому, с которым сталкиваюсь в прадакшене под рукой не нашлось. Но если вкратце, то сталкивался со следующим:
          Принимаемые данные с последовательного порта клались в очередь, а затем раз в 20 мс выдавались пачкой по другому интерфейсу. Проблема в том, что это нагружало процессор очень значительно. Поскольку прием велся по DMA на частоте примерно 1 мегабит, вызывались прерывания, там вызывалось добавление в очередь ресурсом до 50к элементов, а затем другой поток раз в 20 мс извлекал в массив данные и по DMA отправлял в другой порт. А ведь можно было убрать этот уровень абстракции с очередью и просто использовать кольцевые буферы. Поскольку никакой проверки на корректность не производится (по ТЗ).


          1. Nick_Shl
            27.07.2019 05:18

            Так а в чем проблема?
            Задача приема реализует кольцевой буфер. Вызывается шедулером каждую мс, проверяет совпадает ли NTDR с сохраненным значением, если нет — выгребает все что принято. В таком случае прерывания от UART пообще не нужны.
            Задача передачи вызывает функцию у задачи приема "дай мне порцию данных". В этой функции задача приема использует мютекс, который захватывается так же при добавлении данных в кольцевой буфер — и никакие очереди не нужны.
            Понятно, что можно наворотить все что угодно, насоздавать кучу задач, а потом ругать RTOS.


            1. Vadimatorikda Автор
              27.07.2019 05:21

              Про запутанность отписал ниже. Это пример с недооцененным загрузом процессора.
              Ну а вообще да. Не вина ОС, что ее используют через одно место. Сам использую ОС периодически. Проблема в том, как ее МОЖНО при КРИВЫХ РУКАХ использовать. Что и происходит периодически.


              1. Nick_Shl
                27.07.2019 06:29

                При КРИВЫХ РУКАХ что угодно МОЖНО использовать криво — что с RTOS, что без. Так что получается статья ни о чем.


                1. Vadimatorikda Автор
                  27.07.2019 06:32

                  Не совсем. Статья о том, что не надо пихать ОС везде, куда лезет. Просто пример подобрал не самый удачный.


                  1. MacIn
                    27.07.2019 16:58

                    Какой тогда удачный? Статья вырождается в «делайте так, а не так» — почему, собственно?


        1. Vadimatorikda Автор
          26.07.2019 20:34

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


  1. Pafnutyi
    26.07.2019 13:02

    Возьмем типичный МК проект. Считать датчики(АЦП, i2C и тп), считать регистры с какой нибудь модбас(и тп) фигни, зажечь пару лампочек (нарисовать картинку) включить реле, пошимить пару транзисторов. 99% процентов проектов прекрасно обойдется библиотекой уровня АбДурины ))

    Речь о чём, сам вопрос надо ставить подругому: не злоупотребление, а почему пользователь выбирает вариант с РТОС. Чем-то же ртос завлекает, быстрым получением работающей поделки, ненужностью разбираться в периферии и тд, а вовсе не необходимостью «паралелить» процессы. Когда есть хороший набор типовых библиотек позволяющий не напрягаться на работе — мало кто спрыгнет на ртос ;P С другой стороны сейчас не 2000год, есть куча РТОС для МК которые позволяют вообще не вспоминать о регистрах периферии, потому и злоупотребляют


    1. lingvo
      26.07.2019 13:15

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


    1. AVI-crak
      26.07.2019 13:58

      Отсутствие желания и времени разбираться в периферии — это для пользователей публичных библиотек. ОС тут не имеет значения.
      Человек просто берёт готовый пример, адаптирует под свои условия, и наслаждается готовым результатом. Ничего плохого в этом нет.
      Трудно быть первопроходцем: когда примеров нет, публичных библиотек нет, и вокруг одни юзвери — умеющие только скачивать готовое.


  1. AVI-crak
    26.07.2019 13:49

    Куда столько?
    обслуживание wdt (если ОС упала, то задача его не сбросит и устройство перезагрузится);

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


    1. Vadimatorikda Автор
      26.07.2019 15:03

      Мы выделяем 1 задачу как раз. С самым низким приоритетом (выше idle). Если ее вытеснили на сильно долгое время, то что-то выжирает сильно много ресурса. Обычно МК берется с сильно большим запасом (потому что дешевые). Перезагрузка гарантирует, что МК будет инициализирован заново как положено и продолжит свою работу и вертолет не упадет от того, что сервопривод перегрелся и отвалился кварц, например. Будет сделана попытка запуститься без него и жить дальше.
      Событие собаки никто не обрабатывает. Собака все убивает, если ее не сбросить.
      Надо отметить, что в устройствах с которыми я работаю — нет надобности в «закрытии сессии» (за исключением пары случаев, но они блокируются при нормальной работе).


      1. AVI-crak
        26.07.2019 16:02

        А, ну так это разные классы задач: выжить любой ценой, и выжить с минимальными потерями.
        Под первый вариант попадают все вторичные системы, временный глюк которых не приводит к необратимой катастрофе.
        Второй вариант…
        — Шеф, у нас тут верхний ключ на 600А пробило, и линия зависла на отметке 1200В. Давай ещё раз стартанём, вдруг её отпустит…
        В этом случае нужно не только корректно завершить работу, но и запретить дальнейшую эксплуатацию до завершения ремонта.


        1. Vadimatorikda Автор
          26.07.2019 16:11

          Аааааа… Ну тут конечно же от задачи. Просто у нас так проектируют схемы, что в случае если МК умрет, то все линии по умолчанию не должны ничего натворить (если только внутри МК не произойдет замыкание на питание). Иногда даже закладываем на такие штуки декодеры на логике. Если нужный код — можно реле открыть… Любое иное — закрыть.


      1. Nick_Shl
        27.07.2019 05:21

        Мне вот интересно, как вы определите "отвалившийся кварц" на запуске?


        1. ittakir
          27.07.2019 06:42

          STM32 умеет такое делать, в случае отвала внешнего кварца переходит на внутренний RC генератор.


          1. Vadimatorikda Автор
            27.07.2019 06:47

            Ну и из-за того, что у нас «отвалился кварц» надо произвести инициализацию по другому алгоритму. Например, без этого кварца уже нельзя использовать ETH, но можно технологический UART и т.д.