Help with fault_isr

Status
Not open for further replies.

Tactif CIE

Well-known member
I'm trying to implement a fault handler in an app outside of Teensyduino or Platform.io, everything being compiled from Makefile.

I borrowed some code snippets and info but can't get a working solution

The relevant parts of my main.cpp file are :

Code:
#define SCB_SHCSR_USGFAULTENA (uint32_t)1 << 18
#define SCB_SHCSR_BUSFAULTENA (uint32_t)1 << 17
#define SCB_SHCSR_MEMFAULTENA (uint32_t)1 << 16

void __attribute__((naked)) fault_isr(void) {
    uint32_t *sp = 0;
    asm volatile("TST LR, #0x4\n\t"  // Test EXC_RETURN number in LR bit 2
                 "ITE EQ\n\t"        // if zero (equal) then
                 "MRSEQ %0, MSP\n\t" // Main Stack was used, put MSP in sp
                 "MRSNE %0, PSP\n\t" // else Process stack was used, put PSP in sp
                 : "=r"(sp)
                 :
                 : "cc");
    term.println("*** Crashed ***");
    term.print("PC=");
    term.print(sp[6], 16); // 6 * 4 = 24 -> PC
    term.print(" LR=");
    term.print(sp[5], 16); // 5 * 4 = 20 -> ??
    term.print(" make crash");
    term.println();
    term.flush();
    while (1) {
        // keep polling some communication while in fault
        // mode, so we don't completely die.
        if (SIM_SCGC4 & SIM_SCGC4_USBOTG)
            usb_isr();
        if (SIM_SCGC4 & SIM_SCGC4_UART0)
            uart0_status_isr();
        if (SIM_SCGC4 & SIM_SCGC4_UART1)
            uart1_status_isr();
        if (SIM_SCGC4 & SIM_SCGC4_UART2)
            uart2_status_isr();
    }
}

extern "C" int main(void) {
    SCB_SHCSR |= SCB_SHCSR_BUSFAULTENA | SCB_SHCSR_USGFAULTENA | SCB_SHCSR_MEMFAULTENA;
setup();
    while (1) {
        loop();
        yield();
    }
}

I've several problems :

1) in mk20dx128.c all the fault handlers are weak aliased to fault_isr() function - So my own fault_isr() should take precedence to the one provided by teensy core - This is not the case, I only get some handling when defining
Code:
void __attribute__((naked)) hard_fault_isr(void)
but never with
Code:
void __attribute__((naked)) fault_isr(void)
BTW, fault_isr is not defined as a weak symbol - Is it the reason my function not being called ?

2) Is the initialization of SCB_SHCSR correct ? Is SCB_SHCSR the right register ?
3) I don't really understand in which conditions (which faults) the handler would be called - Tried to understand from the Cortex M4 documentation but it's still very unclear to me

Side note : in the above code, the 'term' variable is only an instance of a custom class deriving from usb_serial_class
 
Not sure what is 'outside of TeensyDuino' when it seems PJRC code is in use?

If using PJRC code in TeensyDuino there are a couple of fault handlers that are weak and can be overridden easily - then when triggered the fault comes to your code.

In the noted file mk20dx128.c you'll find them like this:
Code:
void nmi_isr(void)		__attribute__ ((weak, alias("unused_isr")));
void hard_fault_isr(void)	__attribute__ ((weak, alias("fault_isr")));
void memmanage_fault_isr(void)	__attribute__ ((weak, alias("fault_isr")));
void bus_fault_isr(void)	__attribute__ ((weak, alias("fault_isr")));
void usage_fault_isr(void)	__attribute__ ((weak, alias("fault_isr")));
void svcall_isr(void)		__attribute__ ((weak, alias("unused_isr")));
void debugmonitor_isr(void)	__attribute__ ((weak, alias("unused_isr")));
void pendablesrvreq_isr(void)	__attribute__ ((weak, alias("unused_isr")));

This in local code gets called when the fault occurs:
Code:
// These take over the weak fault handlers that are NULL in base TeensyDuino code
void nmi_isr(void)
{
  debug_fault( 1 );
}
void hard_fault_isr(void)
{
  debug_fault( 2 );
}
void memmanage_fault_isr(void)
{
  debug_fault( 3 );
}
void bus_fault_isr(void)
{
  debug_fault( 4 );
}
void usage_fault_isr(void)
{
  debug_fault( 5 );
}
void svcall_isr(void)
{
  debug_fault( 6 );
}

Not sure what OS is in use - but there is a way to run Arduino build from cmdline {editor can execute} on Windows under tset on my github.
 
Last edited:
Not sure what is 'outside of TeensyDuino' when it seems PJRC code is in use?

My bad, of course all the code comes from TeensyDuino - What I meant is I've extracted the tools, core libraries and teensy libraries, added tycmd, organized the whole thing to suit my tastes and extended the Makefile from https://github.com/apmorton/teensy-template/blob/master/Makefile

Everything seems right, I can compile my app which uses several Teensy libraries (mostly from Paul, but 1 external) and upload the firmware to the Teensy with tycmd, all in a single make command from Visual Studio Code.
I like the idea to understand the build process, and to switch core source code from stable Teensyduino release to github master in a single change of my Makefile.

Not sure what OS is in use - but there is a way to run Arduino build from cmdline {editor can execute} on Windows under tset on my github.

Mac OS Sierra 10.12.6

Now about the code you posted

Code:
// These take over the weak fault handlers that are NULL in base TeensyDuino code
void nmi_isr(void)
{
  debug_fault( 1 );
}
void hard_fault_isr(void)
{
  debug_fault( 2 );
}
void memmanage_fault_isr(void)
{
  debug_fault( 3 );
}
void bus_fault_isr(void)
{
  debug_fault( 4 );
}
void usage_fault_isr(void)
{
  debug_fault( 5 );
}
void svcall_isr(void)
{
  debug_fault( 6 );
}

I presume that debug_fault() is your own fault_handler - But how can debug_fault() get access to the original PC address as there are two consecutive function calls...
Not sure to be clear, let me rephrase

1) void usage_fault_isr(void) is called - Here we can have access to the stack, so find PC address
2) you call debug_fault()
3) in debug_fault() isn't the stack "polluted" by the preceding call ? How in debug_fault() can we find the original PC address the same way I did in my void __attribute__((naked)) fault_isr(void) function ?
4) why all your handlers are not declared "naked" ? I though it was mandatory...
 
Just seeing I missed this reply … busy with the Teensy 4 beta.

I did find code that works for that - I'm not sure if it is a better guide. You can see the link I got it from and the code in place in the Teensy 4 Cores here

Seems it sounds more like you expected with naked entry and register copy. If you find it can be better adapted than what I suggested for use on T_3's it would be good to see your solution.
 
Status
Not open for further replies.
Back
Top