Hi all!
I'm trying to write a bootloader application for SAM7X which receives a new (encrypted) firmware via the debug port, stores it in external flash, and after successfully downloading/storing it copies/decrypts the firmware to internal flash of the SAM7X. So far the bootloader and firmware(application) have been contained in a single µVision project and it seemed I can update the firmware. Bootloader and application have been put in two different ROM regions and when I wanted to download a new firmware I just skipped the bootloader part in the HEX file. But when I added the encryption stuff which also uses some library code I ran into troubles (code shared by bootloader and application) so I split the bootloader and application in two different projects. The project for the bootloader should be straight forward: include the ASM startup code, link code to ROM section 1, put all variables in RAM section 1. After running the bootloader call the firmware's 'main' function which is to be placed on a known address (beginning of the ROM section 2) via a function pointer.
What I'm not sure about is how to set-up the project for the application? I configured µVision to put code in ROM section 2, and variables in RAM section 2. But I did NOT add the ASM startup code since this was already included in the bootloader. When I compile the application I get a linker Warning: .\V4R0.sct: Warning: L6305W: Image does not have an entry point. (Not specified or not set due to multiple choices.) Not sure if this is a problem since the build process completes. However when I want to execute the firmware it seems that calling the application's 'main' (name is different since there can only be one main()), BUT then enters the ABORT mode at some point. I doubt it's got something to do with the application since this has been already running (without the bootloader).
Anybody got any idea? I'd really appreciate! regards, Chris
You still need a startup file.
1) The startup file contains an interrupt vector table.
2) The startup file (might) contains stub code and entry/exist code for interrupt handler(s).
3) The startup file makes sure that the library startup code gets executed.
4) The startup code gets linked to know where main() is.
So make a copy of the startup file, and remote any parts that are incompatible with the code already run by the boot loader startup file. Then build your application as a normal application, but with just a different memory region map.
Hi Per! Thanks for your response!
I'll give it a try, but I don't understand why I have to include the startup code twice. The startup code I'm using for the bootloader is the same as for the old application (which didn't have the bootloader). So the interrupt vector table etc. is already included in the bootloader section. After setting up the table, the handlers, and the stack pointer the startup code just calls __main which I thought I can do as well by calling to a function pointer which points to the beginning of the ROM section 2 (which contains the application). Is there some 'magic' code added by the compiler/linker between calling __main and my main() function?
best, Chris
edit: I just tried adding the startup code to the application, but the application still fails to run. When the bootloader exits it call to addr. 0x110000 which is the beginning of the ROM section 2 where the startup code is placed now:
Memory Map of the image
Image Entry point : 0x00110144
Load Region LR_IROM2 (Base: 0x00110000, Size: 0x00020f34, Max: 0x00030000, ABSOLUTE, COMPRESSED[0x00020dc4])
Execution Region ER_IROM2 (Base: 0x00110000, Size: 0x00020d4c, Max: 0x00030000, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x00110000 0x00000144 Code RO 3 RESET sam7.o 0x00110144 0x0000000c Code RO 249 * $$startup$$ entry.o(mc_t.l) 0x00110150 0x00000002 Code RO 266 .emb_text init.o(mc_t.l) 0x00110152 0x00000002 PAD 0x00110154 0x0000020c Code RO 9 .text adc.o
How do I run the application from the bootloader?
But you want your application to be modifiable without being dependant on the boot loader.
So you want your application to decide what interrupt vectors to catch.
And the C runtime library for your application needs to pick up the relevant information from your startup file to know what memory regions to clear (BSS variables) or to fill with decompressed, initialized data (DATA).
You do not want the boot loader to decide how large stack size your application has.
In the same way, you do not want the boot loader to care about the amount of data you reserve for a heap.
The boot loader should not need to know anything about your application, besides two things: 1) How to decide if the image is valid (i.e. a CRC32 check or similar of the relevant memory region) 2) How to activate the application - such as knowing the location of the interrupt vector table, and picking up the reset vector.
The startup code normally sets up the C library, stack, heap, external RAM and other settings that might not survive the jump to application or might be application specific. Your application must build and RUN (starting at address 0x0) successfully before any of what you are doing can work.
You're right Per, application and bootloader should be independent. Right now the app. doesn't use IRQs, and RAM is uninitialized, but it might require IRQs in the future, and having to update the bootloader because of the IRQs doesn't make sense (or isn't even possible). But I still don't know how to activate the application. I linked the startup code (region called RESET in the map file) to the beginning of the ROM region 2 (addr. 0x110000) and call it via a function pointer pointing to this address (like I did in some AVR bootloader project). Or do I have to branch to this address instead?
I just checked if the app. still works when I change the scatter file to put the app. at the beginning of the flash (where the bootloader would reside) and it does. So there must be something wrong with the way I call/activate the application from the bootloader. Maybe I have to dive into the assembly code to see what happens there...
One thing you need to consider is processor mode.
The startup file expects a newly reset processor.
But the startup file from your boot loader most probably sets the processor in user mode before you reach your code that jumps into the application startup file. That would result in the application startup code failing when trying to play with protected operations.
Did you remap the interrupt vectors? Did you switch to privileged mode before jumping to application (consider using a SWI) ?
I just added the following line (MSR...) to the beginning of the startup code putting the microcontroller in system mode
; Reset Handler EXPORT Reset_Handler Reset_Handler MSR CPSR_c, #Mode_SYS:OR:I_Bit:OR:F_Bit
but it still fails to execute the application.
I'm wondering if it's possible to read back the content of the internal flash and compare it against a binary/hex file using ULINK2? some background: when I download the application firstly I do a CRC check, write to external flash and compare (ie read back) the data, and finally do a MD5 over the whole (application) code. Only if this succeeds I update the internal flash with the new firmware. Before splitting bootloader and application in two projects updating the internal Flash was already working. But since I don't trust my own code anymore I'd like to verify the content of the Flash using ULINK2 (it's the only programmer I've got), but from µVision it's only possible to either 'Erase' or 'Program' the chip. It seems there's no executeable for the ULINK2 just DLLs?
Christoph, I'm new to the bootloader scene and I was wondering if you might be able to share parts of your bootloader project with me. At this point I'd be happy to just have the project basics: *.uvproj, *.uvmpw, <startup>.s, *.sct, and maybe some source code. I'm at: henleaze@cableone.net
Help! -chas-