4
votes

I've written a bootloader for my SAM4S that sits in sector 0 and loads an application in sector 1. The problem however is that when I attempt to jump to the new function it appears to generate an exception (debugger goes to Dummy_Handler()).

Bootloader contains the following entries in map:

.application    0x00410000        0x0
                0x00410000                . = ALIGN (0x4)
                0x00410000                _sappl = .
                0x00410004                _sjump = (. + 0x4)

The application image map file has:

.vectors       0x00410000       0xd0 src/ASF/sam/utils/cmsis/sam4s/source/templates/gcc/startup_sam4s.o
                0x00410000                exception_table
…
.text.Reset_Handler
                0x0041569c      0x100 src/ASF/sam/utils/cmsis/sam4s/source/templates/gcc/startup_sam4s.o
                0x0041569c                Reset_Handler

Exception table is defined as follows:

const DeviceVectors exception_table = {

        /* Configure Initial Stack Pointer, using linker-generated symbols */
        .pvStack = (void*) (&_estack),

        .pfnReset_Handler      = (void*) Reset_Handler,

The bootloader declares the application jump point as:

extern void (*_sjump) ();

and then makes the following call:

_sjump();

The memory contents at 0x00410004 are 0x0041569d, and I notice that this is not word aligned. Is this because we are using Thumb instructions? Either way why is it not 0x0041569c? Or more importantly why is this going to an exception?

Thanks,

Devan

Update: Found this but it does not appear to work for me:

void (*user_code_entry)(void);
unsigned *p; 
p = (uint32_t)&_sappl + 4;
user_code_entry = (void (*)(void))(*p - 1);

if(applGood && tempGood) {
    SCB->VTOR = &_sappl;

    PrintHex(p);
    PrintHex(*p);
    PrintHex(user_code_entry);

    user_code_entry();

}

The code prints: 00410004 0041569D 0041569C

Update Update: The code that attempted to jump with a C function pointer produced the following Disassembly:

--- D:\Zebra\PSPT_SAM4S\PSPT_SAM4S\SAM4S_PSPT\BOOTLOADER\Debug/.././BOOTLOADER.c 
user_code_entry(); 
004005BA ldr    r3, [r7, #4]     
004005BC blx    r3

I was able to get this working with the following assembly:

"mov   r1, r0        \n"
"ldr   r0, [r1, #4]  \n"
"ldr   sp, [r1]      \n"
"blx   r0"

Based on this I wonder if the stack reset is required and, if so, is it possible to accomplish such in C?

2
Could be the protection mode on the CPU. Might have to change it so you can access memory outside of the protected region.Magn3s1um
@Magn3s1um It does not look like the MPU has been configured by my bootloader.devanl
What is the address of your sjmp functions. I don't see any jmp, b instruction in your bootloader, are you sure those four lines is all? Post your C or assembler code of the bootloader (and maybe its disassembly).RedX
@Magn3s1um - I have verified that MPU is disableddevanl
@RedX I modified the code a little today ` void (user_code_entry)(void); unsigned *p; p = (uint32_t)&_sappl + 4; user_code_entry = (void ()(void))(*p - 1); if(applGood && tempGood) { SCB->VTOR = &_sappl; PrintHex(p); PrintHex(*p); PrintHex(user_code_entry); user_code_entry(); }` _sappl is a linker symbol which points to vector table. The idea is that p then points to the reset vector and user_code_entry is a function pointer that calls the reset vector function handler for the application.devanl

2 Answers

3
votes

I had the same problem with SAM4E. I cannot guess what your problem might be, but I can point out difficulties that I had and information I used.

My bootloader was not storing in the correct memory location a few parts of the firmware. This was leading to the dummy_handler exception. When I fixed the error in the address calculations the bootloader worked perfectly.

My suggestions:

  • Follow ATMEL's example: the Document and the Example Code should be enough. The main.c is enough to understand how the bootloader should work. It is not necessary to get into partitioning details at the beginning.
  • You may want to read how you can execute functions/ISRs from RAM
  • This webpage explains the Intel HEX format.
  • Finally, after the bootloader finishes with the upgrade, you can read the flash and send it back to the host computer. Then compare it with the original image (using a script). That is how I debugged my bootloader.

Other ideas that might help:

  • Do you erase each page before you write it?
  • Do you unlock each memory space before you erase/write it?
  • You could lock the Bootloader's Section to avoid overwriting it by mistake
  • You could lock the section(s) of the upgraded firmware.

The address you have to point to is 0x00410000 not 0x00410004. The Atmel's example code (see function binary_exec) in combination with the Intel Hex format (record type 05) should solve this question.

I hope this piece of information will be of some help!

2
votes

I had the same problem on the SAM4S which brought me to this question. So if someone arrives here again, here is what I found. As ChrisB mentions following the Atmel example code is a good start, however I found that the problem was the actual code requesting the jump which just didn’t work for the SAM4S. What was missing was rebasing the stack pointer before the vector table and then loading the reset handler address. Try something like this:

static void ExecuteApp(void)
{
    uint32_t i;

   // Pointer to the Application Section
   void (*application_code_entry)(void);

   // -- Disable interrupts and system timer

    __disable_irq();
    SysTick->CTRL = 0; // Disable System timer

    // disable and clear pending IRQs
    for (i = 0; i < 8; i++) 
    {
        NVIC->ICER[i] = 0xFFFFFFFF; // disable IRQ
        NVIC->ICPR[i] = 0xFFFFFFFF; // clear pending IRQ
    }


    // Barriers
    __DSB();    // data synchronization barrier
    __ISB();    // instruction synchronization barrier

    // Rebase the Stack Pointer
     __set_MSP(*(uint32_t *) APPCODE_START_ADDR);

     // Rebase the vector table base address
     SCB->VTOR = ((uint32_t) APPCODE_START_ADDR & SCB_VTOR_TBLOFF_Msk);

     // Load the Reset Handler address of the application
     application_code_entry = (void (*)(void))(unsigned *)(*(unsigned *)
                              (APP_START_RESET_VEC_ADDRESS));

    __DSB();
    __ISB();

    // -- Enable interrupts
    __enable_irq();

     // Jump to user Reset Handler in the application
     application_code_entry();

}