Диагностика Imprecise Bus Faults в микроконтроллерах Cortex-M3/M4/M4F

При разработке программ для систем на микроконтроллерах серий Cortex-M3/M4/M4F программисты, бывает, сталкиваются с исключениями ядра, когда программа останавливается в бесконечном цикле в обработчике FaultISR. Как правило, попадая в этот обработчик вы уже не можете определить что произошло, т.к. стек вызовов в отладчике уже не отображается. Еще хуже, если в регистре Fault Status появится ошибка Imprecise Bus Error. Вот про диагностику этой ошибки я и расскажу.

Разрабатывая проект на микроконтроллере TI Tiva под управлением FreeRTOS я столкнулся с подобной ситуацией, когда, в результате тестирования, программа стала попадать в исключение. Падение было плавающим, т.е. момент возникновения неисправности проявлялся через случайное время после старта программы.Imprecise Bus Fault

Фирма Texas Instruments выпустила документ Diagnosing Software Faults in Stellaris ® Microcontrollers в котором содержится мого интересной информации для диагностики программных проблем. Но про Imprecise Bus Error вообще мало информации. Написано лишь, что это асинхронная ошибка и в регистре адреса не содержится точного адреса инструкции вызвавшей ошибку. В моем случае все шаги по поиску неисправности описанные у TI для Imprecise Bus Fault привели лишь в функцию vPortStartFirstTask(), эта функция запускает задачи во FreeRTOS. Тупик? Не совсем.

Плотный поиск в интернете навел меня на форум Freescale и документ A Way to Detect Imprecise Hard Fault Source. Там я и нашел более полное описание ошибки Imprescise Bus Fault и интересный способ ее диагностики. Итак, по порядку. Микроконтроллеры Cortex имеют WriteBuffer для инструкций и выполнение следующей инструкции начинается до завершения предыдущей. Это увеличивает производительность, но усложняет отладку. В случае Imprescise Bus Fault ошибку вызвыает предыдущая инструкция, когда регистр PC уже указывает на следующую в очереди команду.

К счастью, разработчики ядра Cortex, предусмотрели возможность отключения этого буфера. У микроконтроллера Kinetix фирмы Freescale это производится в регистре Auxiliary Control путем установки бита DISDEFWBUF. В моем случае у микроконтроллера Tiva TM4C1294NCPDT фирмы Texas Instruments тоже есть регистр Auxiliary Control, только бит называется DISWBUF. Думаю, что и у микроконтроллеров других производителей есть что то подобное.

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

После запуска программы я опять получил ошибку, но на этот раз это была Precise Bus Fault, что мне и было нужно. На скриншоте видно что регистр NVIC_FAULT_STAT имеет значение 0x0008200 - это и есть Precise Bus Fault. При этом в регистре NVIC_FAULT_ADDR содержится адрес инструкции вызвавшей ошибку 0х00005369. Можно посмотреть дизассемблером по этому адресу.

Это была функция xQueueGenericSend(), которая отдавала Mutex прсле использования общего ресурса. В моем случае оказалось что портился объект Mutex, а проблема была в не проинициализированном локальном указателе.

Я надеюсь что эта техника перевода Imprecise Bus Fault в Precise Bus Fault поможет кому-нибудь еще.