3

I have an mplabx project with a custom bootloader and application for the PIC32MX795F512L. All throughout its development, I have been jumping from the bootloader to the application with no problem using the line:

((void (*)(void))(APPLICATION_RESET_ADDRESS))();

where APPLICATION_RESET_ADDRESS is a macro with the address of the reset handler for my application. After some recent modifications to the bootloader, I suddenly started getting into the general exception handler sometime after executing that line and before getting into the main function of the application. the odd thing is, if I set a breakpoint on that line and then continue after breaking it works fine. further more, if I change the way I jump to the application to:

asm volatile
(
    "JALR %0"
    :
    :"r"(APPLICATION_RESET_ADDRESS)
    :
);

it jumps to the application with no problem which is really confusing because the assembly generated by: ((void (*)(void))(APPLICATION_RESET_ADDRESS))(); is

LUI v0,-25341
ADDIU V0, V0, -28672
JALR V0
NOP

and the assembly generated by:

asm volatile
(
    "JALR %0"
    :
    :"r"(APPLICATION_RESET_ADDRESS)
    :
);

is

LUI V0, -25342
ORI V0, V0, -28672
JALR V0
NOP

so both methods use the same number of instructions, and both jump using JALR the only difference between the 2 is how they load the pointer into the register. does anyone have any ideas?

  • What is the value for your `APPLICATION_RESET_ADDRESS`? – embedded_guy Jul 28 '14 at 21:43
  • @embedded_guy 0x9D029000 –  Jul 29 '14 at 11:11
  • Perhaps it was something else that you changed in the boot code? I see no reason why you are not able to jump to the application based on what you have above. Do you have any interrupts running in the boot? – embedded_guy Jul 29 '14 at 15:47
  • @embedded_guy i do have several interrupts running in the bootloader including 2 timers and an ethernet interrupt. Should that affect anything though? i thought the interrupts would restore any clobbered registers upon returning. –  Jul 29 '14 at 17:28
  • If you are not already doing it, I would try disabling all interrupts prior to jumping to the application. – embedded_guy Jul 29 '14 at 18:42

2 Answers2

1

I know this isn't an answer to why but, I used the same method as the AN1388 from microchip to jump to my bootloader:

void jump_to_app(void)
{
    void (*fptr)(void);
    fptr = (void (*)(void))USER_APP_RESET_ADDRESS;
    fptr();
}

It works and we have a pretty complicated bootloader/application combination in our product.

blsmit5728
  • 434
  • 3
  • 11
  • `((void (*)(void))(APPLICATION_RESET_ADDRESS))();` should be doing the same thing as this function. the thing is though, even my inline assembly works, but if i dont know why one method works and the other doesnt i don't know when/if it will happen again in the future –  Jul 28 '14 at 19:54
  • 1
    Oh I agree with you, Did you happen to investigate the exception code to see what the issue was? Look into overriding the weak handler and break in there to check the error code. – blsmit5728 Jul 29 '14 at 00:13
1

I don't know if you have already covered this case. But, one possible issue that you may be experiencing is the fact that you could be running interrupts while jumping to your application. While Microchip does not expressly cover this situation in their Application Note on the PIC 32 Bootloader - AN1388, there is a possibility that you could vector to an incorrect address if an interrupt occurs and you are in the middle of setting up your startup code in the application - a lot of this would depend on how your startup code is setup.

It is always a good idea to disable interrupts prior to jumping to your application.

If you look at the AN1388 Source Code for microchip, you can see that they disable interrupts prior to jumping to the application. Below is their code with my own comments:

//Enter firmware upgrade mode if there is a trigger or if the
//application is not valid.
if(CheckTrigger() || !ValidAppPresent())
{
    TRANS_LAYER_Init(pbClk);  //  Init the transport layer...
                              //Interrupts are enabled during
                              //this function.
    while(!FRAMEWORK_ExitFirmwareUpgradeMode())
    {
        /* Keep receiving commands from the PC */
        ...
    }

    TRANS_LAYER_Close();  //   This is just a wrapper that
                          //makes a call to a function which
                          //disables all interrupts.
}

JumpToApp();  //Similar to your function.

Hopefully, this will give you someplace to look. I do not see any issues with how you are calling the jump.

embedded_guy
  • 1,939
  • 3
  • 24
  • 39
  • 1
    it appears to be working now, so im hoping interrupts were the culprit. I also turned off DMA to make sure that wasn't part of the problem. Only time will tell for sure though. –  Jul 30 '14 at 11:00
  • I am glad that worked out for you. Disabling DMA was a good idea as well. – embedded_guy Jul 30 '14 at 15:36