This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

stcSelfCheck() goes to undefined instruction exception

Other Parts Discussed in Thread: RM42L432, HALCOGEN

Hello,

I have the same problem, like in this thread.
I try to setup the CPU Self-Test in Hercules RM42L432.
For debugging I use Keil and I use HALCoGen for creating the API.
Everytime I issue the WFI instruction in function stcSelfCheck() (without debugging mode) the processor goes to undefined instruction exception.
What am I doing wrong?

Best regards

Falk

  • Can you pls try to find the exact location which resulted in the undefined exception ? you can use the link register which will give the exact address. pls let us know.

  • Hi,

    here is the disassembly.

    I commented the call to WFI out (because I think, the cpu doesn't stop at WFI) and this is the point where the function stcSelfCheck() returns to.
    If the DCI Instruction gets called, the cpu jumps to _undef.

    Thanks and best regards!

  • Hi,

    The return address is certainly not correct(that's not a valid opcode instead a constant).

  • Can you also pls check the stack settings once ?

  • Hi Falk,

      Are you using the HalCoGen to generate the sys_startup.c file which has the call to stcSelfCheck()? The stcSelfCheck() is supposed to execute WFI instruction. If WFI instruction is executed, it sends a signal (STANDBYWFI) to the STC controller to start the self check. After the self check, a CPU reset will be asserted. This will force the CPU to start from the reset vector at 0x0 again. In the _c_int00() it will check to see if CPU reset event has happened. If yes, it will eventually jump to the afterSTC() function which will then enter main(). The reason you are seeing undefined is because the WFI is never executed. The stcSelfCheck() is the last function call in _c_int00(). The return address after the stcSelfCheck() has just the literal pool data which are underfined instructions to the CPU.

      Now we need to find out why the CPU does not enter standby mode when WFI is executed. Can you please check if you have any pending interrupts to the CPU? I have also seen before that if you happen to have an asynchronous abort but the CPU has masked the asynchronous abort with the A-bit in the CPSR then the CPU will not enter standby even after executing WFI. So please check to see if you have any pending interrupts. It may be hard to know if you have any imprecise abort as by default the A-bit is set. You can try to clear the A-bit in the beginning of your program and see if WFI is taken or not.

  • Hi Charles,

    _clearCPSR_A_Bit_
    
    	mrs		r0, cpsr
    	and		r0, #0xFFFFFEFF
    	msr		CPSR_cxsf, r0
    	bx		lr

    I used the code above to clear the A-Bit.
    The Code for go into Idle mode I modified as follows:

    _gotoCPUIdle_
    
            WFI
            nop
            nop
            nop
    endless1
    		b	endless1
            nop
            bx    lr

    Next I loaded the code into flash and powered the board.
    With Keil I started the debugger (without reseting) and it shows up as follows:

    To answer your question:
    Yes I am using HALCoGen 4.10.00 for generating the code.
    The only Self Test enabled is the CPU Self Test.

    Which Interrupt Flag Registers I have to clear, so that all IRQs are disabled?

    Thanks and best regards

    Falk

  • Hi Falk,

      The VIM module has the interrupt enable registers that can be used to disable the interrupts. By default after reset, all channels are disabled except channels channel 0 and channel 1. Channel 0 is reserved for ESM. Channel 1 is not used. So check the VIM interrupt status registers INTREQx to see if you have any channels pending.

      In your screen shot the program counter is looping at itself when you connect to the target. Where is this branch to itself instruction? Is this in the main()? If it is already somewhere at the main() then the stcSelfCheck() should have finished. As I explained earlier, if StcSelfCheck() is called, the STC controller will assert a reset to the CPU. The code in the _cint00() will determine if the reset is due to STC self check by reading some registers in the STC and call cpuSelfTest()  for a real CPU BIST test. Eventually after the CPU self test is complete it will call afterSTC() from which the main() is finally called.  This flow is based on the HalcoGen generated sys_startup.c file.

  • Hi Charles,

    I will check for the IRQs asap.

    The Loop is placed in the _dabort routine, not in the main.
    I think I understood the desired behavior of the startup-code and the stcSelfCheck() function.
    But as I mentioned, I think the CPU reset does not occur because the CPU wakes immediately after WFI.

    Thanks!

    Falk

  • Hi Falk,

      I think the abort interrupts the CPU from going into standby mode after the WFI. So please find out what causes the abort and fix the abort problem first. You can check the CPU data fault status register and data fault address register to find out the address that causes the abort and the abort type.

  • Hi Charles,

    I read out the DFSR and DFAR into r0 and r1 respectively.
    After Power-On the debugger shows this:

    Directly after flashing this:

    After Power-On I think it is an Asynchronous External Abort and after flashing it is an Alignment Abort at Address 0xEA994416 which looks strange.

    Best regards

    Falk

  • Falk,

    I did a blinky test using Halcogen 04.01.00 and Keil Debugger.

    Here is the full project including Halcogen config files.

    2437.Blinky_test.zip

    This code will run the STC during the startup phase.

    Can you check in your project which Scatter/linker command file you are using.

    See the following screen shoot.

    It is necessary to use the one generated by Halcogen,

    Please let me know if this is helpful.

  • Hi Jean-Marc,

    Thank you for the project.
    I only have the part RM42L432 here.
    Can I adapt the project for this part?
    Or is it possible for you to send me a project with the right part?

    Best regards

    Falk

    EDIT:

    I took your project and adapted mine.
    Additionally I deleted all function calls which I put into the _c_int00().
    Now it works perfect I think.

    I noticed, that a function call with to many args results in faults like _dabort or _undef.
    Are there any registers (r0-r14) which I should leave unchanged before the __main is called?

    Best regards

  • Falk,

    The _c_int00() is generated by Halcogen.

    If your code is c code, the compiler will take care of saving/restoring all registers used in a given function.

    At the very beginning of  _c_int00, there is a function call to _coreInitRegisters_()
    This call is mandatory and has to be done just after reset.
    On Cortex core, all register (except PC and SPSR) are not initialized after reset/power-on reset.
    Because of the lockstep implementation (2 core running in parallel) it is important to be sure that both core are in the same state. That the purpose of this routine. It will initialize all cores register with the same default value.

    Concerning the number of arguments in a function call, as far as I know there is no limitation.
    The first few arguments are passed via register. (3 if I'm correct) If more arguments are present, than they will be passed via the stack. This could be the cause of your abort.
    If you have many cascaded function calls this could overflow your stack. This is just an assumption. Detail analysis of the code will tell you exactly what is going on.

    NOTE. In order to make a function call using the stack for passing argument, it is mandatory to have the stack correctly initialized. This initialization is done by calling _coreInitStackPointer_();
    This is the second call in _c_int00()
    Trying to use the stack before this call will result in unexpected results.

    The call to __main does not expect any register with a specific value.

    Let me know if I've clarified your question.

  • Hi Jean-Marc,

    thanks for the detailed answer!

    My function is called after _coreInitRegisters_() and _coreInitStackPointer_().
    I tried out when the error occurs. It happens if I use more than 4 args.
    The stack I think is big enough and the function I call doesn't call another.

    Best regards

  • Falk,

    Will it be possible to share your project. There is nothing I can do to debug your problem without code.

    if there is confidentiality problem please let me know.

  • Hi Jean-Marc,

    could you please just try to call a function with 5 arguments directly after _coreEnableFlashEcc_()?
    If I do this I get a _dabort.

    Best regards!

  • Falk,

    The problem you are facing is very certainly a stack issue.
    As I said in a previous post, on power on reset, the SP (R13) is not initialized.

    Have a look to the following code:

    void _c_int00(void)
    {
        
    /* USER CODE BEGIN (5) */
        int a=0;
        int b=1;
        int c=2;
        int d=3;
        int e=4;
    /* USER CODE END */

        /* Initialize Core Registers to avoid CCM Error */
        _coreInitRegisters_();

    /* USER CODE BEGIN (6) */
    /* USER CODE END */

        /* Initialize Stack Pointers */
        _coreInitStackPointer_();

    /* USER CODE BEGIN (7) */

    //    test(0,1,2,3,4);
        test(a,b,c,d,e);
    /* USER CODE END */


    This code will very certainly creates a DATA ABORT.
    The definition of a,b,c,d,e are local to this function so they will be stored in the stack.
    At that point the stack pointer is not yet initialized.
    In opposition, check this code:

    void _c_int00(void)
    {
        
    /* USER CODE BEGIN (5) */
    /* USER CODE END */

        /* Initialize Core Registers to avoid CCM Error */
        _coreInitRegisters_();

    /* USER CODE BEGIN (6) */
    /* USER CODE END */

        /* Initialize Stack Pointers */
        _coreInitStackPointer_();

    /* USER CODE BEGIN (7) */

        int a=0;
        int b=1;
        int c=2;
        int d=3;
        int e=4;

        test(a,b,c,d,e);
    /* USER CODE END */

    Please have a try and let me know.

  • Hi Jean-Marc,

    Thank you for the examples!

    As I said in my last post the function call is after _coreEnableFlashEcc_() and thus after _coreInitStackPointer_().
    I do not declare any variables before _coreInitStackPointer_().
    I did find out, that if I want to use the Stack in _c_int00(), I have to disable RAM and Flash checks (_coreDisableEventBusExport_() and _coreDisableFlashEcc_()).

    After that all works perfectly.
    Is there an explanation for this behavior?

    Best regards!

  • Falk,

    At that point, having your code is the only solution.
    Apparently your problem is in the _c_int00() but if I understand you have done some modification to it.
    On my side, I can only debug the file generated by Halcogen.

    I can send you a friend request so we can keep this out of view if there is confidentiality problem.

    Please let me know.