В этом тексте я бы хотел перечислить способы повышения надежности для встраиваемого ПО. Как обычно начтем с определений.
Надёжность (reliability)— свойство объекта сохранять во времени в установленных пределах значения всех параметров, характеризующих способность выполнять требуемые функции в заданных условиях применения. Интуитивно надёжность техники связывают с недопустимостью отказов в работе. Это есть понимание надёжности в «узком» смысле — свойство объекта сохранять работоспособное состояние в течение некоторого времени или некоторой наработки.
Ошибка (Error)- отклонение измеренного значения величины от её истинного значения. Ошибки всегда можно исправить.
Сбой (fault) — ненормальный режим, который может вызвать снижение или потерю способности функционального блока выполнять требуемую функцию. Сбой представляет собой состояние, характеризуемое неспособностью выполнить необходимую функцию.
Отказ (failure)— нарушение работоспособности объекта, при котором система или элемент перестает выполнять целиком или частично свои функции, иначе произойдёт сбой в работе устройства, системы, органа.
Авария (crash)— разрушение сооружений и (или) технических устройств непредвиденный выход из строя оборудования или механизмов, разрушение зданий или инфраструктуры, в результате которых становится невозможным дальнейшее функционирование объекта. Неконтролируемый взрыв и (или) выброс опасных веществ. В авариях происходит существенный материальный ущерб. Поломка агрегатов. Выход из строя оборудования. В авариях не должно быть человеческих жертв.
Катастрофа (catastrophe) - крупное бедствие, событие с трагическими последствиями, с человеческими жертвами.
Что можно предпринять чтобы увеличить надежность прошивки?
1. Сторожевой таймер (WatchDog)
" Cемь бед - один reset "
Должен быть запущен сторожевой таймер (WDT). Прошивка может зависнуть при некорректных входных данных или в результате стресс тестирования. Сторожевой таймер позволяет автоматически перезагрузиться и устройство не останется тыквой.
"Я видел промышленно производимое оборудование, в котором периодически срабатывал watchdog, и весь MK уходил в reset. (35 раз в сутки) И ладно, дальше работаем. Почему он упал, зачем он упал, что сделать, чтобы он не падал — эти вопросы никому не интересны."
2. Оконный сторожевой таймер Window watchdog (WWDG)
Оконный сторожевой таймер следит за тем, чтобы его сбрасывали не чаще и одновременно ни реже определенного временного интервала. Это позволяет выдерживать заданный период. Если опрос выходит за рамки, то это интерпретируется как отказ и происходит перезагрузка процессора.
3. Bit Stuffing (Положительное выравнивание)
Покажу на примере CAN. Когда узел передал пять последовательных битов одного уровня, то трансивер добавит шестой бит противоположного уровня к исходящему потоку битов. Приемники удалят этот дополнительный бит. Это делается для того, чтобы избежать избыточных компонентов постоянного тока на шине, но также дает приемникам дополнительную возможность обнаруживать ошибки: если на шине встречается более пяти последовательных битов одного уровня, подается сигнал об ошибке заполнения. Например CAN-трансивер вставляет в поток инвертированный бит, если в сдвиговом регистре приема оказалось 5 одинаковых бит. Это работает bit stuffing. Bit stuffing также присутствует в USB. Таким образом можно отлавливать ошибки потери отдельных бит при рассинхронизации тактовой частоты между передатчиком и приемником на уровне передачи отдельных бит данных.
4. MPU для контроля переполнения стековой памяти
MPU - это аппаратная часть процессора, которая предоставляет защиту памяти. Это упрощенная версия MMU, которая делает только защиту памяти. MPU не поддерживает виртуальную память. MPU вызывает исключение при нарушении доступа к памяти.
В ARM Cortex-M, когда происходят срабатывание по MPU, то выстреливает прерывание MemManage_Handler. Регистр CFSR содержит внутри себя регистр MMFSR. Вот MMFSR битом MMARVALID как раз и укажет, что обнаружен валидный адрес в регистре MMFAR. Если в MMFAR 1, то надо читать MMFAR. Там будет лежать физический адрес по которому произошло нарушение MPU доступа. В регистре MMFSR отдельно можно только выявить факт исполнения кода из региона (бит IACCVIOL). А на запись и чтение ARMы выделили только один бит - DACCVIOL.
Если определить запретный регион между кучей и стеком, то на основе MPU можно сделать предупреждение на переполнение стековой памяти.

Аналогично можно следить и за Heap памятью.

Можно даже сделать две группы регионов MPU. Регион на предупреждение (желтый) и регион на саму ошибку (красный). Вот и получается, что MPU стоит на страже stack и heap памяти.
5. Мажорирование
Это принятие решения по результату голосования. Например в UART семплы захватываются несколько раз за бит. Нечетное количество семплов. Значение бита выбирается в результате электрического голосования семплов. Если больше нулей, то ноль, если преобладают 1 - 1. Это позволяет противостоять ошибкам передачи данных.
Если у вас в прошивке есть NVRAM, то вы можете сделать три экземпляра NVRAM и записывать туда одинаковые данные в трех копиях. А когда надо будет считывать, то вычитывать три файла и выдавать на выход тот, который совпал по крайней мере в двух случаях из трех.
6. Покраска Cтека (Stack Painting)
Можно делать в коде периодическую проверку степени заполнения стековой памяти. В ARM Cortex-M реализовать автоматическую проверку процентного соотношения заполнения стековой RAM памяти. Это даёт ценнейшую метрику при разработке программного обеспечения. Достаточно теперь прогнать модульные тесты, посмотреть на заполнения стека и выделить большее количество в новом релизе прошивки по мере надобности.

7. Проверка адекватности показаний датчиков
Любой датчик может выйти из строя. После измерения физической величины надо сразу проверить показания на предмет промахов и абсурдных значений.
8. Проверка конфига перед применением
Каждая программа перед стартом так или иначе принимает конфигурацию работы перед запуском. Например настройки битовой скорости трансиверов. Стандарт разработки ПО ISO-26262 требует перед применением конфига проверять его на валидность в run-time. Это позволит отреагировать на неверно сконфигурированную программу.

9. Работа процессора в режиме Lockstep
Системы Lockstep — это отказоустойчивые компьютерные системы, которые выполняют один и тот же набор операций одновременно и параллельно. Происходит избыточность. Избыточность (дублирование) позволяет обнаруживать и исправлять ошибки: выходные данные операций Lockstep можно сравнить, чтобы определить, произошла ли ошибка.

Затем происходит контроль и оценка путем сравнения результатов отдельных ядер ЦП выполняются отдельными, ограниченными по времени и непрерываемыми этапами. Т.е. процессорные ядра одновременно или с небольшим смещением по времени выполняют одинаковые инструкции. В архитектуре CPU lockstep, выходы обоих CPU сравниваются инструкция в инструкцию. Если результат не совпал - прерывание или сброс CPU.
Цель Lockstep: как можно раньше обнаружить сбои в работе процессора путем пошагового сравнения внутренних или внешних результатов, полученных двумя процессорами, работающими синхронно.
Достигаемая таким образом избыточность позволяет обнаруживать и реагировать на аппаратные сбои в одном из ядер процессора, как в случае двухъядерного процессора в режиме Lockstep.
Другими словами, либо все это происходит, либо ничего из этого не происходит, но не что-то среднее. Иногда между системами устанавливается временной сдвиг (задержка), что увеличивает вероятность обнаружения ошибок, вызванных внешними воздействиями (например, скачками напряжения или ионизирующим излучением от изотопов).
10. Критические секции
Перед прыжком в приложение загрузчик должен отключить все прерывания. Иначе программа приложения зависнет, если в ней сработает прерывание для которого в приложении нет функции обработчика. Еще критическую секцию надо активировать при операциях с FIFO. Иначе данные могут исказиться.
11. HeartBeat LED
В сборке присутствует HeartBeat LED. Чтобы просто глядя на устройство убеждаться, что прошивка не зависла. Раз мигает LED значит не зависло. Значит вертится суперцикл в main-е.
12. Обратная связь
В системах управления есть такое понятие как обратная связь. Это когда сигнал с выхода поступает на вход. Например плечи H-моста заведены на ADC, чтобы MCU мог понять, что напряжение в самом деле включилось и в нагрузке есть ток.
13. Error Correcting Code ECC
Error Correcting Code (ECC) — это метод кодирования данных, который позволяет не только обнаруживать, но и автоматически исправлять ошибки, возникшие при хранении или передаче информации. В отличие от простых методов контроля четности, которые могут лишь сигнализировать о проблеме, ECC активно восстанавливает исходные данные.
14. CRC
При приеме пакета надо проверить его CRC. Это даст гарантию, что данные не повреждены. Второй пример. Загрузчик перед записью должен проверять контрольную сумму приложения. Если CRC32 не cовпадает, то такую прошивку лучше не запускать. Правильная CRC это всего лишь гарантия, что прошивка как файл передалась корректно. Это не защита от чужеродного firmware. CRC это не только про протокольные пакеты. Также при помощи CRC следует защищать данные в NVRAM инверсной копией.
15. Бит четности
Бит четности это по сути однобитная CRC. Применяется в UART.
16. Модульные тесты
Тесты позволяют делать безопасное перестроение упрощение кода, локализовать причины сбоев. Тесты выступают как документация к коду. Код тестов должен быть встроен прямо внутрь кода прошивки. По крайней мере для Debug сборок. Тесты можно запускать как при старте питания так и по команде из CLI.
17. Health Monitor (медбрат)
Это отдельная задача, поток или периодическая функция, которая периодически проверяет все компоненты, счетчики ошибок, регистры статусов и в случае, если возникли какие-то сбои, HM как-то сообщает об этом пользователю. HM должен работать непрерывно. Например при ошибке посылает красный текст в UART-CLI а при предупреждении-желтый текст.
Health монитор повысит надежность изделия в целом и позволит найти ошибки, которые пропустили модульные тесты.
Вот вам яркий пример. Health монитор может выявить факт того, что соскочили настройки прерываний. Бывает такие неприятные моменты, что в многоядерных системах перезагрузка одного ядра сбрасывает прерывания другого ядра. Ибо внешние прерывания (UART, SPI и пр.) общие на все ядра. В этом случае Health Monitor может взять и починить эту ситуацию заново включив прерывание по конкретному номеру. Вот так...
18. Порядковый номер пакетов
При отправке нумеровать пакеты. Это позволит на стороне приемника определить потерю непрерывности потока (срыв потока). Порядковый номер пакета это также требование стандарта ISO-26262
19. Matrix Access Monitor
В некоторых микроконтроллерах есть блок, который называется Matrix Access Monitor (MAM). Модуль MAM предоставляет интегрированную архитектуру для управления доступом, защиты памяти и изоляции периферийных устройств. Он позволяет программному обеспечению настраивать устройство (включая ядра, DMA , Ethernet) для управления правами доступа к каждому блоку ведомого устройства (памяти или периферийных устройств), а именно, доступом на чтение, запись, выполнение и супервизор.
MAM позволяет защитить память от чтения со стороны DMA, в то время, как MPU защищает память только от действий CPU. MAM позволяет не просто наложить ограничение на память, как это происходит в MPU, а наложить ограничение на память для конкретного блока: DMA0, DMA1, ETH или CPU2.
20. Коды Рида-Соломона
Коды Рида-Соломона циклические коды, позволяющие исправлять ошибки в блоках данных. Если говорить образно, то если вы запишите CD диск с кодами Рида-Соломона, а затем просверлите отверстие 10мм в случайном месте диска, до все данные можно будет восстановить. Есть математические методы вокруг этого. Это используется в интерфейсе UWB для борьбы с потерянными радио пакетами.
21 Слежение за стеком аппаратным таймором.
Когда срабатывает прерывание то его переменные оказываеются на стеке того ядра в котором прерывание возникло. В связи с этим можно периодически делать выборку значения указателя стека внутри прерывания таймера, срабатывающего с достаточно высокой частотой. Частота прерываний таймера должна быть максимально возможной, пока она не начинает влиять на производительность реального времени приложения. Типичные частоты могут быть в диапазоне 10..250 кГц. Достоинство этого метода - не нужно вручную искать функцию с самым глубоким использованием стека.
void sampling_timer_interrupt_handler(void) { char* currentStack; int a; currentStack = (char *)&a; if (currentStack < lowStack) lowStack = currentStack; }
22 Программный watchdog
Программный watchdog на аппаратном таймере. Из-за того, что аппаратный watchdog основывается на RC-генераторе, его точность часто оставляет желать лучшего. В этом случае можно дополнить его программный watchdog-ом на аппаратном таймере с большей точностью, на кварцевом генераторе, и функцией Window watchdog , если она не доступно аппаратно, или тоже имеет проблемы с точностью.
23 Защита данных в RAM памяти CRC
Локализация данных блоков данных частей программы и контроль неизменности их содержимого вне интервала доступа в этим данных. Если есть некий объект в RAM, данные которого могут и именоваться периодически, на интервале времени, составляющем, малую часть всего цикла работы программы, то после изменения этих данных можно защитить этот блок памяти, пересчитав его контрольный код - например CRC или контрольную сумму, а перед использования этих данных - проверить его. Этим может быть достигнуто уменьшение времени возникновения сбоя, который может остаться незамеченным.
Итог
Как видите, существует много приёмов, которые помогают повысить надежность встраиваемого ПО. Если Вас есть, возможность написать про ещё какой-нибудь метод повышения надежности прошивок, то можно обсудить это в комментариях.
Ссылки
Название | URL |
Покраска Cтека (Stack Painting) | |
FC7300F8MDT: Lockstep (или как МК выявляет сбои) | |
ARM Cortex-M: пуск Memory Рrotection Unit (MPU) | |
Модульное Тестирование в Embedded | |
Aтрибуты Хорошей Прошивки (Firmware) | |
Атрибуты Хорошего Загрузчика | |
Ортодоксально Каноническая Прошивка (ОКФП) | |
https://microsin.net/programming/arm/mastering-stack-and-heap-for-system-reliability.html | |
NVRAM для микроконтроллеров |
Вопросы:
--Какие существую еще способы увеличения надежности при проектировании встраиваемого ПО?