Open forGGe opened 7 years ago
Right now, theCore handles all faults in common way - it hangs:
To be able to handle it externally, two steps must be taken:
remove corresponding line from default handlers listing. Say, you want to implement UsageFault handler, you need to remove def_irq_handler UsageFault_Handler line
implement C function with following signature:
extern "C" void UsageFault_Handler(void)
{
/* Print registers, and other useful stuff */
}
Note that the ecl::bypass_puts()
function must be used to print data, instead of printf()
. Bypass console is specifically crafted for such purpose and can be invoked from fault/IRQ handlers.
Some additional guides:
Trying to implement the UsageFault_Handler
on external interrupt example.
I've modified the _startup_armcm.S file removing def_irq_handler UsageFault_Handler
and its definition in vectors:
I've also modified the main.cpp file of the mentioned example adding the exception's handler as follows:
extern "C" void UsageFault_Handler(void) { ecl::bypass_puts("This is an Usange Fault"); }
and added a division by 0 to force the fault:
`int a;
int b=2;
int c=b;
int main() {
ecl::cout « "Hello, Embedded World!" « ecl::endl;
//Forced Fault
a=b/(c-b);`
but the program works fine. Any idea? Maybe theCore has defined this exception with a priority so low that it's never active?
Hi @M3one !
Thanks for your feedback.
Either it is optimized out by the compiler, or handler is not called indeed.
Could you please modify it a bit:
int main()
{
ecl::cout << "Hello, Embedded World!" << ecl::endl;
//Forced Fault
a=b/(c-b);`
ecl::cout << "After Fault! << ecl::endl;
}
Meantime, I will check on my side. Stay tuned.
Indeed, by default trap is not enabled on division by zero. Try to add there:
*((volatile int*)0) = 42;
You should get the MemManage fault (I hope, currently I have only M0 on my table, that results in HardFault when trying to write into 0x0 address).
Let me know if that helps.
main.cpp file:
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "target.hpp"
#include <ecl/iostream.hpp>
#include <ecl/thread/utils.hpp>
#include <ecl/thread/semaphore.hpp>
#include <platform/exti_manager.hpp>
using ecl::exti_manager;
using ecl::cout;
using ecl::endl;
using ecl::semaphore;
using ecl::usr_btn; // Defined in stm32discovery.json
extern "C"
void board_init()
{
gpio_init_generated();
}
extern "C" void UsageFault_Handler(void)
{
ecl::bypass_puts("This is an Usange Fault");
}
void user_button_handler(void *ctx)
{
semaphore *s = reinterpret_cast<semaphore*>(ctx);
s->signal();
}
int main()
{
ecl::cout << "Hello, Embedded World!" << ecl::endl;
//Forced Fault
*((volatile int*)0) = 42;
ecl::bypass_puts("Working?"); //to be sure I'm not messing with files
semaphore s;
exti_manager::handler h;
h.set_ctx(&s);
h.set_cb(user_button_handler);
exti_manager::subscribe<usr_btn>(h, exti_manager::trigger::rising);
while (1) {
s.wait();
ecl::cout << "Button pressed!" << ecl::endl;
exti_manager::unmask(h);
}
}
Output:
Welcome to theCore the_core v0.3.0.300 047b0a5-dirty Hello, Embedded World! Working?
Not working :(
F4 discovery board MCU has Usage Faults no active (or masked, not sure) by default. That's why it didn't work. If a hard fault is provoke, then it does call the HardFault_Handler()
:
extern "C" void HardFault_Handler()
{
ecl::bypass_puts("This is an Hard Fault");
for(;;);
}
void user_button_handler(void *ctx)
{
semaphore *s = reinterpret_cast<semaphore*>(ctx);
s->signal();
}
int main()
{
ecl::cout << "Hello, Embedded World!" << ecl::endl;
//Forced Fault
typedef void (*fptr)(void);
((fptr)0xdeadbeaf)();
semaphore s;
exti_manager::handler h;
To enable hardware reporting of div0 errors we need to configure the CCR. The CCR is part of the Cortex-M’s System Control Block (SCB) and controls entry trapping of divide by zero and unaligned accesses among other things.
Source Here
F4 discovery board MCU has Usage Faults no active (or masked, not sure) by default. That's why it didn't work. If a hard fault is provoke, then it does call the HardFault_Handler():
To enable hardware reporting of div0 errors we need to configure the CCR. The CCR is part of the Cortex-M’s System Control Block (SCB) and controls entry trapping of divide by zero and unaligned accesses among other things. Source Here
That's answer to many things. Thanks!
Could you please enable all possible faults by adding more code in platform.cpp
file?
In such way, we can be sure that no bugs (like division by 0, which is shame to ignore!) slips trough our fingers.
Done. It should be working. Now both divide-by-cero and unaligned memory access fault exceptions are enable. Don't know why but these faults are scaled to hard fault.
I've also added more code to the main.cpp
of the external interrupt example to handle all exceptions. Not yet finished but you can check the faults if you want.
Per discussion is Telegram chat:
The fault handling will be moved in arch.cpp
for the CM* architecture module.
No MSP or stack unwinding will be made in first iteration of this task.
Thanks!
Bunch of ARM exceptions are exist that not handled within theCore:
NMI A Non Maskable Interrupt (NMI) can be signalled by a peripheral or triggered by software. This is the highest priority exception other than reset. It is permanently enabled and has a fixed priority of -2. NMIs cannot be:
HardFault A HardFault is an exception that occurs because of an error during exception processing, or because an exception cannot be managed by any other exception mechanism. HardFaults have a fixed priority of -1, meaning they have higher priority than any exception with configurable priority.
MemManage A MemManage fault is an exception that occurs because of a memory protection related fault. The the fixed memory protection constraints determines this fault, for both instruction and data memory transactions. This fault is always used to abort instruction accesses to Execute Never (XN) memory regions.
BusFault A BusFault is an exception that occurs because of a memory related fault for an instruction or data memory transaction. This might be from an error detected on a bus in the memory system.
UsageFault A UsageFault is an exception that occurs because of a fault related to instruction execution. This includes:
The following can cause a UsageFault when the core is configured to report them:
SVCall A supervisor call (SVC) is an exception that is triggered by the SVC instruction. In an OS environment, applications can use SVC instructions to access OS kernel functions and device drivers.
PendSV PendSV is an interrupt-driven request for system-level service. In an OS environment, use PendSV for context switching when no other exception is active.
Those exceptions if triggered and not handled by user, should produce stack trace, registry info and some status info, if possible.
Default handler verbosity must be configurable and dependable on build mode, i.e. in debug build it should print more info. Handlers override must be possible in compile time.