Всем здравствуйте! Хотел бы найти ответ на свой вопрос. Есть устройство, которое должно быть надежным даже в случае отказа, при возникновения каких либо неучтённых ошибках в программе (и как следствии зависание STM32). Мысль такая, если возникает ошибка, заходим в обработчик исключения, в нем отключаем мотор и все что нужно. На первое время, пока с моими знаниями, хотя бы так. Что дальше будет, для меня пока не важно - главное отключить мотор. Я не могу зайти в обработчики (ни в какие) исключений. Что я для этого сделал:
1) Включил глобальные прерывания:
__enable_irq();
2) Разрешил их как обычные прерывания:
NVIC_EnableIRQ(NonMaskableInt_IRQn);
NVIC_EnableIRQ(HardFault_IRQn);
NVIC_EnableIRQ(MemoryManagement_IRQn);
NVIC_EnableIRQ(BusFault_IRQn);
NVIC_EnableIRQ(UsageFault_IRQn);
NVIC_EnableIRQ(SVCall_IRQn);
NVIC_EnableIRQ(DebugMonitor_IRQn);
NVIC_EnableIRQ(PendSV_IRQn);
NVIC_EnableIRQ(SysTick_IRQn);
3) Переоределил сами обработчики:
extern "C" void HardFault_Handler(void) { GPIOB->BSRR |= GPIO_BSRR_BR_5; // выключаем мотор }
ну и так во всех, что есть:
NonMaskableInt_IRQn
HardFault_IRQn
MemoryManagement_IRQn
BusFault_IRQn
UsageFault_IRQn
SVCall_IRQn
DebugMonitor_IRQn
PendSV_IRQn
SysTick_IRQn
4) искусственно создаю ситуацию появления ошибки. Или обработчик, например Таймера, не переопределю, а он должен попасть туда, или такой командой:
__asm("svc 0");
5) уже под отладчиком я регистр NVIC_ISER0 устанавливаю в 0xFFFFFFFF, что все прерывания разрешить системные (хотя здесь я не уверен что я правильно настраиваю)
Но при созданной ситуации "STMка зависла", я не попадаю ни в один из определённых обработчиков исключений. А попадаю в цикл всем известный Loop
.section .text.Default_Handler,"ax",%progbits Default_Handler: Infinite_Loop: b Infinite_Loop .size Default_Handler, .-Default_Handler
Что я сделал неправильно или что недоделал или в чем не прав и ошибаюсь?
Мы разобрали этот вопрос. Дело оказалось прозаическим.
Если посмотреть файл startup_stm32xxxx.s, который лежит в "/Core/Startup/" мы увидим такие строки
Default_Handler: Infinite_Loop: b Infinite_Loop
Сюда мы попадаем, если прерывание у нас не объявлено, но разрешено.
Потому что в стартовом скрипте стоят заглушки.
.weak NMI_Handler .thumb_set NMI_Handler,Default_Handler .weak HardFault_Handler .thumb_set HardFault_Handler,Default_Handler .weak MemManage_Handler .thumb_set MemManage_Handler,Default_Handler .weak BusFault_Handler .thumb_set BusFault_Handler,Default_Handler .weak UsageFault_Handler .thumb_set UsageFault_Handler,Default_Handler
Это только часть, остальное можно посмотреть самим.
Вся ошибка возникла когда автор вместо
extern "C" void TIM1_BRK_TIM15_IRQHandler(void)
описал прерывание
extern "C" void TIM1_TIM15_IRQHandler(void)
соответственно у него вызывалось прерывание, которое нужно, но обработчика там не было. И согласно алгоритму всё сваливалось на метку Default_Handler и зацикливалось.
Правда автор не указал это в сообщении.
Но возникает ещё интересная тема. А когда вызываются прерывания, которые указал автор? В документации это как то скудно описано.
Получаем - невнимательность вызвала ошибку, не связанную с другими проблемами, которые могли бы вызвать описанные автором прерывания.
В то же время возникает вопрос: А как себя обезопасить от таких ошибок?
Добавлю от себя.
Скажу с радостью, что проблема решена. Спасибо людям!
Первое что. Есть некоторые ошибки в понимании происходящего в железе.
__enable_irq();
Обработчики исключений включены по умолчанию, специально я их не отключал. И поэтому здесь эта команда не имеет смысл.
Второе. Я действительно не понимал некоторых вещей. Действительно, если я разрешил прерывание, например Таймера, но не описал его обработчик или описал его с ошибкой (например, вместо TIM6_IRQHandler(void), написал TIM6IRQHandler(void)) просто упустил один символ, то STMка уходит на заглушку, откуда в тот самый Infinity Loop. И с этим ничего не поделаешь. Это уже как говорится моя проблема.
Третье, никакой ошибки здесь нет, поэтому я не входил ни в какие обработчики исключений, в которые хотел.
Ошибка действительно возникала, если я, например специально делил на ноль, что делать нельзя, соответственно я всё-таки входил в обработчик исключения:
extern "C" void HardFault_Handler(void)
Четвертое, если взглянуть на код функции
NVIC_EnableIRQ(HardFault_IRQn);
то там ничего не происходит, так как HardFault_IRQn имеет значение отрицательное, а в функции NVIC_EnableIRQ проверяется по условию на значение больше, чем ноль. И эти команды не имели смысл.
Пятое, читать и еще раз читать Programming manual.
Но остались вопросы:
Есть такой регистр - SHCSR (System handler control and state register). Он виден под отладчиком. Там есть биты:
USGFAULTENA BUSFAULTENA MEMFAULTENA
Если переведем документ Programming manual PM0214, то прочитаем следующее для этих трёх битов:
Установит в "1", чтобы разрешить
Под отладчиком, смотря на эти биты, я вижу, что они все сброшены в ноль...
Получается, 3 обработчика исключений:
MemManage_Handler BusFault_Handler UsageFault_Handler
запрещены???
Получается, 3 обработчика исключений:
MemManage_Handler BusFault_Handler UsageFault_Handlerзапрещены?
Хм, похоже на то, судя по битам.