Перейти к содержанию

    

Обработка Faults на Cortex-Mx

Интересует, как коллеги обрабатывают все Faults на микроконтроллерах Cortex-Mx.

Я про NMI, Hard, MemManage, Bus, Usage, SVCall, Debug Monitor, PendSV, Systick.

С SVCall, Debug Monitor, Systick все понятно, с PendSV в принципе тоже.

 

А что делаете с тяжелыми отказами, отказами шины и прочими? Сейчас я просто вывожу состояние нужных регистров и стек. Как правило, если где-то программа падает, я узнаю об этом на этапе отладки. Но ведь может быть такое, что устройство уже стоит у заказчика и частично подлежит отладке на объектах. И оно должно продолжить функционирование. Как обрабатывать тогда ошибки? Перезагрузка по WDT? Или все-таки грамотный обработчик исключения должен понять природу ошибки и попытаться исправить ее? Если да, то каким образом? Сейчас мне видится вариант с сохранением лога событий в памяти (допустим, SD карты) и перезагрузкой МК. Пока что больше хорошего развития событий не знаю. Отсюда и предположения для обсуждения:

1. Должны ли существовать обработчики исключения CPU, связанные с аварийным событием (промах по памяти, тяжелый отказ, например, и т.д.) только на момент разработки и отладки ПО и выявлять все проблемы именно на этапе разработки, а при этом в боевой работе устройство ни коим образом не должно ловить такие Fault-ы?

2. Пункт 1 влечет за собой следующий вопрос: если в боевом коде обработчики должны быть предусмотрены (я подразумеваю, что все-таки это именно так) - как правильно строить архитектуру обработки ошибок? Что должен делать код в обработчике, кроме как сообщать программисту (каким-то образом) о состоянии регистров?

3. Вопрос больше из разряда "как больше нравится" - код обработчика на ассемблере или на Си?

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

 

Я задаю себе вслух вопрос: "причину отказа я установлю, но что мне с этим делать дальше?".

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

Также был бы благодарен, если на эту тему существуют мануалы, но я об этом не знаю - будьте добры, поделитесь информацией :rolleyes:

Изменено пользователем Arlleex

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По-моему, так:

1. Должны быть и в релизе.

2. Регистры процессора, Fault Status'ы, содержимое стека сохранить в памяти, перезапустить процессор и

записать/отправить оповещение в штатном режиме.

3. Можно обойтись без ассемблера, это уже дело вкуса.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
А вот, скажем, выйти из той функции, которая сбойнула, и продолжить работу дальше. И зафиксировать сбой, по возможности, и передать.

1. Каким образом выйти?

2. А если дальше все пойдет еще хуже?

 

Безопаснее рестартовать, сохранив информацию о сбое.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
2. А если дальше все пойдет еще хуже?

Безопаснее рестартовать, сохранив информацию о сбое.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
А что делаете с тяжелыми отказами, отказами шины и прочими?

Определил для себя понятие "критическая ошибка". Это такая ошибка, возникновение которой не предусмотрено при создании программы, неизвестно "что делать?" при её возникновении и невозможно продолжать штатное функционирование устройства.

Такие ошибки у меня могут возбуждаться как аппаратными событиями (исключение от MPU при попытке недопустимого доступа к памяти, всяческие прочие HF (и Bus fault-ы и user fault-ы - для всех у меня делается эскалация до Hard Fault с общим обработчиком HF)); так могут вызываться и программно (набор функций trap(...)) если какая-то часть программы обнаружила недопустимое состояние (для каждого программного модуля/драйвера - свой класс возбуждаемых trap-ов). Обработчик trap() у меня висит на SVC.

При возникновении любого типа критической ошибки я делаю:

Защёлкиваю тип и ID критической ошибки состояние выполнения (регистры CPU, N слов от вершины стека), для программного trap() также защёлкиваю аргументы вызова. Для некоторых типов критических ошибок (например: неожиданное прерывание (которого не должно быть)) защёлкиваю состояние выполнения (регистры/стек) не текущего контекста, а прерванного. Далее - делаю базовый инит (выкл. всей периферии, останов DMA, инит базовой периферии - MPU и пр.) и дальше - в зависимости от состояния соответствующего ключа компиляции:

1) компиляция DEBUG: переход устройства в спец.режим "TRAP" - инит тактирования (PLL и пр.) для этого режима (минимальные частоты), инит отладочного UART, и циклический, раз в секунду, вывод "синего экрана смерти" - периодический дамп всех защёлкнутых данных в UART в текстовом виде; устройство находится в режиме TRAP до внешнего сброса/выкл. питания, обеспечивая фиксацию состояния ошибки.

2) компиляция RELEASE: аппаратный reset устройства.

И для того и для другого случая, копирую защёлкнутую инфу в спец. область памяти, которая не будет стёрта при reset-е, снабжаю её флагом и CRC. И, если устройство имеет non-volatile память, то после штатного рестарта, после начального инита периферии, эта инфа переписывается в журнал критических сбоев в этой non-volatile памяти.

 

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

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

 

Сейчас мне видится вариант с сохранением лога событий в памяти (допустим, SD карты) и перезагрузкой МК.

В момент ошибки у Вас устройство уже работает, куча разной периферии/DMA работают, и если при этом произошла ошибка, то в этом окружении уже опасно дальше что-то делать, иначе можно получить каскад таких сбоев. Лучше просто защёлкнуть как можно быстрее инфу об ошибке в ОЗУ и сделать начальный инит периферии к минимальному функциональному состоянию - минимуму работающей периферии необходимой для записи события ошибки в какую-то энергонезависимую память, и записать эту инфу. А уж после рестартовать опять систему к полной функциональности.

 

в боевой работе устройство ни коим образом не должно ловить такие Fault-ы?

Фиксация и отработка сбоев должна быть и в боевом режиме.

 

2. Пункт 1 влечет за собой следующий вопрос: если в боевом коде обработчики должны быть предусмотрены (я подразумеваю, что все-таки это именно так) - как правильно строить архитектуру обработки ошибок?

У меня у обработчик общий, но имеет два входа: для программного возбуждения сбоя (trap()) и для аппаратного возбуждения сбоя (все типы fault-ов).

 

3. Вопрос больше из разряда "как больше нравится" - код обработчика на ассемблере или на Си?

Защёлкивание всей инфы (регистры, стек, состояние CPU и пр.) у меня на асме, а "синий экран смерти" (режим работы TRAP) - на си.

 

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

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

Как-то так.

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Так же и сброс не всегда можно допустить, мало ли, какой процесс обслуживается.

Вы так и не рассказали, как собираетесь выбираться из fault'а.

"Мало ли какие процессы" должны контролироваться аппаратно и/или безболезненно переживать сброс.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Вы так и не рассказали, как собираетесь выбираться из fault'а.

Типа как известный персонаж:

post-38713-1530996957_thumb.jpg

:biggrin: :biggrin: :biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Типа как известный персонаж...

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

Поделиться сообщением


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

Ну так fault при доступе в несуществующую память, по которому соответствующий драйвер делает переназначение страниц памяти (или ещё каким образом делает подкачку из внешнего пула) - это штатная работа диспетчера виртуальной памяти, коли таковой есть. А ТС спрашивает о критических ошибках, т.е. - событиях не предусмотренных заранее при разработке ПО.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо участникам обсуждения!

Примерно так я себе это и представлял, на самом-то деле. Однако предполагал, что существует некий сводный "мануал-ритуал", в котором жесткими канонами высечены такие правила :rolleyes:

 

2) компиляция RELEASE: аппаратный reset устройства.

И для того и для другого случая, копирую защёлкнутую инфу в спец. область памяти, которая не будет стёрта при reset-е, снабжаю её флагом и CRC. И, если устройство имеет non-volatile память, то после штатного рестарта, после начального инита периферии, эта инфа переписывается в журнал критических сбоев в этой non-volatile памяти.

Ну то есть по сути в начале main()-а у Вас можно увидеть что-то наподобие:

int main(void)
{
    if(GetCriticalErrorStatus() == ERROR_OCCURRED)
        WriteInfoAboutError();

    ...
}

где GetCriticalErrorStatus() - функция, которая читает флаг в ОЗУ, установленный trap()-ом или обработчиком HF. Верно?

 

P.S. И еще один вопрос. Если необходимо логгирование на SD-карту памяти, например. Есть ли предпочтение наличию файловой системы или безразлично? Сейчас использую с файловой системой, однако приходится держать файл открытым и через некоторое время сохранять. Но питание могут выключить в произвольное время. Так может потеряться информация о файле, поэтому я делаю дублирование файлов, и это выглядит костылем. Какие изящные программные способы логгирования вы применяете?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
где GetCriticalErrorStatus() - функция, которая читает флаг в ОЗУ, установленный trap()-ом или обработчиком HF. Верно?

Да. Читает и очищает.

 

Какие изящные программные способы логгирования вы применяете?

Лучше логи писать в журналы (без ФС) - оно как бы органически под это дело и подходит. Я так и делаю. Журнал у меня - это некая FIFO-структура во FLASH/FRAM, с размером элементов обычно кратным целому числу блоков записи (хотя это не обязательно). Каждый такой элемент - одна запись журнала (на одно событие). При старте ПО выполняется монтирование каждого журнала: поиск "головы", определение числа записей, проверка их валидности и т.п.

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

 

Так может потеряться информация о файле, поэтому я делаю дублирование файлов, и это выглядит костылем.

Так даже с дублированием инфа может потеряться. Ведь обычно в файловой системе при обновлении файла происходит неатомарная модификация разных областей на носителе. Вследствие чего могут возникнуть ошибки в FAT или записи каталога, которые приведут не только к порче записываемого в данный момент файла, но и других файлов (всякие cross-links and etc.).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Лучше логи писать в журналы (без ФС) - оно как бы органически под это дело и подходит. Я так и делаю. Журнал у меня - это некая FIFO-структура во FLASH/FRAM, с размером элементов обычно кратным целому числу блоков записи (хотя это не обязательно). Каждый такой элемент - одна запись журнала (на одно событие). При старте ПО выполняется монтирование каждого журнала: поиск "головы", определение числа записей, проверка их валидности и т.п.

...

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

Поделиться сообщением


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

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

Поделиться сообщением


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

Вообще-то вероятность зависит от условий эксплуатации устройства автора. Вы откуда знаете какова у него вероятность?

А если у него при подаче питания на устройство, возможен дребезг контактов? При таком включении устройство может многократно включиться/выключиться.

Или например: пришла помеха - пачка импульсов (даже испытания на помехоустойчивость проводят пачкой импульсов) - тогда устройство многократно перезагрузится.

А теперь представьте, что у него в устройстве есть журнал включений/выключений, в который устройство должно писать инфу о включениях (сразу после вкл. питания). Какова будет вероятность попадания такого рестарта на момент записи? А если таких устройств у заказчика работает тысячи и работают они режиме 24/7? Как часто в такой системе будут происходить сбои ФС с потерями данных?

 

ФС нужна только если эту SD должны вынимать вставлять ещё куда-то (комп, etc.). Если нет и работа с SD производится только самим устройством, то ничто не мешает ему представить некий объект на SD (FIFO-журнал из секторов) как файл через свой внешний интерфейс. Даже хранить в таком журнале записи в бинарном виде (как удобнее для работы с ними), а выдавать пользователю через внешний интерфейс в текстовом виде (printf никто не отменял).

Я именно так и делал. Хранить удобнее бинарные записи (размер меньше, размер фиксированный), а при выдаче вовне переводить их в текст на лету.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация