This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Bootloader for LPC1766 - starting the program

I'm working on a bootloader that uses a hex file and I would like to know, how to start loaded program.

In Keil v. 4.24 startup.s file contained this:


Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                LDR     R0, =__main
                BX      R0
                ENDP

And __main function was an entry point for any program. Keil generated hex-file and __main-function address was here as "Linear start address". All was well.

But Keil's 4.5 (or higher) startup.s containes this:


Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  SystemInit
                IMPORT  __main
                LDR     R0, =SystemInit
                BLX     R0
                LDR     R0, =__main
                BX      R0
                ENDP

So what is an entry point now? And where does "linear start address" point to?
Is there some reliable way to start loaded program based on information in the hex file?

Moving SystemInit call from reset handler to the actual main is obvious, but a little bit inconvinient.

Parents
  • A hex file contains a record “Start Linear Address Record”. The meaning of this record is well defined for an Intel processor but open to interpretation for a Cortex-M3

    IMHO, the entry point is really “Reset_Handler” which branches to “__main” in your v4.24 example.

    However, a quick experiment seems to suggest that the “Start Linear Address Record” in the Keil generated HEX file will point to “__main” by default. (You may want to check in the Keil documentation in relation to what to expect here; I didn’t).

    This is of no consequence for the first start-up file you show as “Reset_Handler” branches immediately to main.

    However, if you were to use this value for the second example you would bypass the CMSIS initialisation function SystemInit. (BTW: SystemInit needs to be called before anything else to initialise the system so it should not be called from main).

    You might want to add this line

    --entry= Reset_Handler

    in your linker control string to get what I consider the correct entry point. It will control what is in the “Start Linear Address Record” of the hex file.

    It seems to default to the following in the absence of it being specified.
    --entry=__main

    However, this is a Cortex-M3 device so the exception vector table contains the true entry point.

    You will need to mimic the Cortex-M3 start-up by loading by the initial program counter AND the stack pointer.

    The exception vector table should be located at address 0x0 (by default) in the hex file.

    From your point of view, load the MSP with the value at offset 0x0 in the hex file, and vector to the entry point which is located at offset 0x4.

    In code…

            MOVS.N          R3      ,#0x0
            LDR.W           R13     ,[R3]
            LDR.W   PC      , [R3,#0x4]
    

Reply
  • A hex file contains a record “Start Linear Address Record”. The meaning of this record is well defined for an Intel processor but open to interpretation for a Cortex-M3

    IMHO, the entry point is really “Reset_Handler” which branches to “__main” in your v4.24 example.

    However, a quick experiment seems to suggest that the “Start Linear Address Record” in the Keil generated HEX file will point to “__main” by default. (You may want to check in the Keil documentation in relation to what to expect here; I didn’t).

    This is of no consequence for the first start-up file you show as “Reset_Handler” branches immediately to main.

    However, if you were to use this value for the second example you would bypass the CMSIS initialisation function SystemInit. (BTW: SystemInit needs to be called before anything else to initialise the system so it should not be called from main).

    You might want to add this line

    --entry= Reset_Handler

    in your linker control string to get what I consider the correct entry point. It will control what is in the “Start Linear Address Record” of the hex file.

    It seems to default to the following in the absence of it being specified.
    --entry=__main

    However, this is a Cortex-M3 device so the exception vector table contains the true entry point.

    You will need to mimic the Cortex-M3 start-up by loading by the initial program counter AND the stack pointer.

    The exception vector table should be located at address 0x0 (by default) in the hex file.

    From your point of view, load the MSP with the value at offset 0x0 in the hex file, and vector to the entry point which is located at offset 0x4.

    In code…

            MOVS.N          R3      ,#0x0
            LDR.W           R13     ,[R3]
            LDR.W   PC      , [R3,#0x4]
    

Children
  • Thanks for your reply!

    BTW: SystemInit needs to be called before anything else to initialise the system so it should not be called from main

    Strictly speaking, SystemInit from LPC peripheral library contains:
    1) Clocking initialization
    2) Peripheral clocking and power
    3) Flash-memory fetching step setup

    While __main initialize stack, heap and all global objects (i'm not entirely sure about this, so feel free to correct). And this things can be done in any order, so calling SystemInit from main is no big deal.

    There is also the funny part, that in SystemInit there ise this code:

    //  Set Vector table offset value
    #if (__RAM_MODE__==1)
      SCB->VTOR  = 0x10000000 & 0x3FFFFF80;
    #else
      SCB->VTOR  = 0x00000000 & 0x3FFFFF80;
    #endif
    


    Note that there is no evidence at all of this kind of setup in wizard-like thingy for this file. And this kinda makes bootloading code in some other memory area (apart from 0x000...) impossible!
    There is no other way round but to remove this manually before compiling program that will be loaded (because, obviously, bootloader should move VTOR with respect to memory offset for loaded program).

    Anyway, back to the point.
    >However, this is a Cortex-M3 device so the exception vector table contains the true entry point.

    You will need to mimic the Cortex-M3 start-up by loading by the initial program counter AND the stack pointer.

    The exception vector table should be located at address 0x0 (by default) in the hex file.

    I do not really understand what else could start on reset other than reset_handler. I remember something about booting into the ISP mode first and memory remapping - but I don't need this to happen after secondary bootloading. Or do I?

    So i do not understand your suggestion about witchcraft with program counter and stack pointer. Where can i read about this? What difference would it make if I will just go straight to reset_handler?

  • The cortex chip have magic to set up the stack in hardware before starting the program tat the reset handler.

    That is a magic special to allow the reset handler to be written in C, i.e. to allow every single line of code to be in C. Of course with the special that the initial C function called will have uninitialized RAM, CRTL etc so it will not see the environment the C language standard requires before normal hand-over to the user application.

    If your boot loader and your loaded application will use the same stack memory region then you could ignore the stack information the compiler puts into the binary for your application. But that would then mean that you are locked into a separation of how much stack and how much global variables by a design decision made already when you wrote the boot loader.

    If your boot loader instead looks for the stack information in the vector table just as the real processor would do, then you can decide when you build a new version of the application if you need to grow or shrink the stack compared to previous versions of the application.

  • >The cortex chip have magic to set up the stack in hardware before starting the program tat the reset handler.
    Riiiiight, so maybe there is something for me to read about this? Or maybe you can tell me what exactly I should do to start loaded application properly?

    (I thought that calling __main will be sufficient to properly initialize stack and so on :C )