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

What is the extra information in my .HEX file?

Background:
I'm a noob. I'm attempting to add the ability to update the application on a NXP LPC2468 by using the USB and adding a bootloader. It sort of works. The unit has an LCD and a keypad. A very minor change to the main application will work without any problem. But for instance, if I add a character to a menu, it will cause a problem: The text for the rest of the application will be shifted or entirely wrong.

The bootloader and the USB driver is located in sectors 0-8 in the Flash. The main application is located in Sectors 9-20. When a USB drive with a correctly named .HEX file is connected, the bootloader will erase sectors 9-20, then load the new main application .HEX from the USB.

When comparing Hex files I can see the problem, but I don't know what it is. If I change an existing character lets say a "1" to a "2", I can see the corresponding value in the .HEX change from "0x31" to "0x32" just as it should. If i then remove that character things in the bootloader section will change. I think this is because the "lookup table" for the text is located here? also the area containing the text seems to be randomly pieced together like the compiler optimizes the locations to save memory. When removing a character this area gets changed quite alot.

Also I can see the now incorrect text in the on chip RAM. The IAP commands if i understand them correctly are only for the flash. How do I update the RAM after a USB upload?

Also the part of the .HEX that changes is not part of my code, at least it is not represented in the MAP file. I don't know what it is.

I'm sure I have alot of ignorance about the inner functions of the processor and the compiler. If fact I don't know even what to search for!

Please help!

Thanks,

Todd

  • A shared memory region for parameter passing isn't a problem as long as that memory region is protected from having the linker place any other variables there.

    The problem is when both linker and application uses shared code, and the access to that shared code isn't implemented in a "BIOS-style" way with a predefined entry point and pre-defined parameter-passing method.

    The "traditional" way many people implement a single-build boot loader + application is that they first builds one binary and program their device with. Then they change the version string of the application and have the boot loader update the device with the new application. Then they verify that their device now reports the newer application version.

    It may seem like a working test, to verify that the boot loader works. But just changing a n-character version string to another n-character version string will not trig all the failure situations where the boot loader and application has cross-linked code and data references. So more than one company have managed to ship broken boot loaders and not noticed until they need to create a bug fix or add more functionality to the application. Then they have to fix their boot loader and have the customers send in the equipment just because the remote update can't be used. And management looks at each other and can't understand why, since they just knew that the remote download functionality was tested before shipping started...

  • And management looks at each other and can't understand why, since they just knew that the remote download functionality was tested before shipping started...

    Now working on the first product that will update itself and associated bluetooth devices via the Internet. I am making sure this kind of failure does not bite me...

  • What is the proper way to "link" the application to the bootloader. In other words how should the bootloader call the application without needing a common included file?

    Previously I had a "start vector" memory location setup in the scatter file and a simple fuction that resided there that called the main() function in my application. The applications main() function was renamed to main_startup so as not to be confused with the bootloaders main() function. Now with both programs is separate projects I'm having difficulty getting this to work because I can't reference a function that doesn't exist.

    Thanks,

    Todd

  • There is nothing forbidden about having a common include file. It's probably quite common to allocate a couple of bytes of RAM for a info structure where boot loader and application can share information.

    Maybe the application wants to force a change of program so it sets a magic value in this structure before forcing a watchdog reset.

    Maybe the boot loader wants to report some version or statistics to the application - or potentially information that "application region 'A' contains a broken binary".

    The problem isn't on the source-code level, but a problem with the linker linking both application and boot loader at the same time. With both linked at the same time, the linker will give them shared helper variables (lots of them from the CRTL) and helper functions.

    But the "normal" way to start the main application is to know that the start of the application area stores the applications vector table, which means the boot loader always knows a fixed location relative of the start of the memory region allocated for the application code, where it can pick up a suitable start address.

    It's common that the boot loader contains one vector table. Then, before it starts the application, it turns off all interrupts, and then makes use of the reset vector in the applications vector table to activate the application.

    So no need for any entry function name or location to be known - the position of the reset vector has a hard-coded offset in the interrupt vector table.

  • What is the proper way to "link" the application to the bootloader.

    By not actually linking at all. If you need to do more than just merge the HEX file of the boot loader with that of the application (or load both files for a debugging session), your bootloader is quite likely not going to work.

    The bootloader sets a small number of fixed addresses which are then used in the application. One of those is either the entry point of the application image, or the location of a pointer to that entry point. The easiest way is for the application to have its interrupt entry / interrupt vector table in the normal memory layout, but a different location. The boot loader then starts the application the same way the CPU itself starts up after a reset --- but with a different base address of the vector table. You even can express code like that in C, if you feel sufficiently lucky:

    typedef void (*T_EntryPoint)(void); // function pointer type
    /*...*/
    ((T_EntryPoint)0x10000)();  call function at location 0x10000
    (*((T_EntryPoint *)0x10000))(); call function whose address is stored at 0x10000
    

  • I found this in one of the nxp app notes for a bootloader (AN10835):

    
    #define AP_ADDR 0x10000// where the user app located
    typedef void (*FP)(void);
    
    /** run the user application from pre-specified address*/
    void Run_Application(void)
    { FP fp;
     fp = (FP)AP_ADDR;
      (*fp)();
    

    When debugging the bootloader, it did set the PC to 0x10000, so i think that means its working.

    I'm trying to get the main application to work right now. As soon as I change IROM1 from a start value of 0x00000000 to a start value of 0x00010000 the program will no longer operate properly. It keeps getting stuck in an endless loop in a section called "decompress2". What am I missing...?

  • It keeps getting stuck in an endless loop in a section called "decompress2". What am I missing...?

    You're probably missing some modifications to the application's copy of the startup code. The routine you're stuck in is the code that sets up initial values for the application's initialized variables from the master image. It's quite possible that this code needs to be informed separately about where you moved the entry point.

  • Is this likely to be in the target options setup or in the code itself?

  • I'm trying to get the application code to run by itself without the bootloader, to verify it works when loaded at 0x10000. So far it will only work if I load it at 0x0. I have tried changing the settings for the ulink2, the scatter file & the target options. So far I'm striking out. Same problem as above with the endless loop. I don't know where or what to search for.

    Someone please tell me I'm an idiot and the easy fix is X....

    Here is my scatter file:

    
    ; *************************************************************
    ; *** Scatter-Loading Description File generated by uVision ***
    ; *************************************************************
    
    LR_IROM1 0x00010000 0x00070000  {    ; load region size_region
      ER_IROM1 0x00010000 0x00070000  {  ; load address = execution address
       *.o (RESET, +First)
       *(InRoot$$Sections)
        RTX_Conf_LPC23xx.o (+RO)
        LPC2300.o (+RO)
            SSP_Display.o (+RO)
        SSP_Keyboard_Task.o (+RO)
    ;    ghwbuf.o (+RO)
        ghwinit.o (+RO)
        ghwioini.o (+RO)
        SSP_Menu_Task.o (+RO)
        SSP_Util.o (+RO)
        SSP_SPI.o (+RO)
        Retarget.o (+RO)
        SSP_IO.o (+RO)
        SSP_CRC16.o (+RO)
        SSP_ISR.o (+RO)
        SSP_Graph.o (+RO)
        SSP_Logfile.o (+RO)
        SSP_MaintPort_Task.o (+RO)
        SSP_Aux485Port_Task.o (+RO)
        SSP_Param.o (+RO)
        RTC.o (+RO)
        SSP_Relay.o (+RO)
        SSP_ProbeComm_Task.o (+RO)
       *LCDDRV.lib (+RO)
       .ANY (+RO)
      }
      RW_IRAM1 0x40002000 0x00010000  {  ; RW data
        RTX_Conf_LPC23xx.o (+ZI +RW)
        LPC2300.o (+ZI +RW)
       .ANY (+RW +ZI)
      }
    

  • Hi Todd,

    Maybe see this:
    http://www.keil.com/forum/13707/

    Search for "Predrag Despotovic" and "13-Dec-2008 12:07 GMT"
    Follow the instructions and configure your startup code properly.

    RAM_INTVEC and REMAP

    ; * RAM_INTVEC: when set the startup code copies exception vectors
    ; * from on-chip Flash to on-chip RAM.
    ; *
    ; * REMAP: when set the startup code initializes the register MEMMAP
    ; * which overwrites the settings of the CPU configuration pins. The
    ; * startup and interrupt vectors are remapped from:
    ; * 0x00000000 default setting (not remapped)
    ; * 0x40000000 when RAM_MODE is used
    ; * 0x80000000 when EXTMEM_MODE is used
    

  • I've been using the LPC2300.s but after reading the above thread I discovered it does not contain the code for RAM_INTVEC. So I changed over to the LPC2400.s and got it to compile and load to my target. It also will run properly on the target.

    I then changed the IROM1 from this:

    LR_IROM1 0x00000000 0x00080000  {    ; load region size_region
      ER_IROM1 0x00000000 0x00080000  {  ; load address = execution address
    

    to this:

    LR_IROM1 0x00010000 0x00070000  {    ; load region size_region
      ER_IROM1 0x00010000 0x00070000  {  ; load address = execution address
    

    added RAM_INTVEC to Options/target/asm/define
    complied and loaded the ulink 2 debugger. It is NOT setup to run to the main (). the debugger starts at 0x00000000 and when it gets to 0x000000010, the PC jumps to 0xFFFFFFF3 and crashes.

    If I debug using the Simulator, and an ini file to allow execution in 0x40000000, it will actually start at address 0x00000000 which is an ANDEQ instruction (that area all the way to 0x0000ffff is all zeros) and then it gets lost in the os_sys_init function, never returns.

    What am I doing wrong?

    0x00000000  E59F4018  LDR       R4,[PC,#0x0018]
    0x00000004  E59F5010  LDR       R5,[PC,#0x0010]
    0x00000008  E5946000  LDR       R6,[R4]
    0x0000000C  E0056006  AND       R6,R5,R6
    0x00000010  E5846000  STR       R6,[R4]
    0x00000014  E51FF004  LDR       PC,[PC,#-0x0004]
    0x00000018  7FFFE040  SWIVC     0x00FFE040
    0x0000001C  FFFFBFFF  (???)
    0x00000020  3FFF8000  SWICC     0x00FF8000
    0x00000024  00000000  ANDEQ     R0,R0,R0
    0x00000028  00000000  ANDEQ     R0,R0,R0
    0x0000002C  00000000  ANDEQ     R0,R0,R0
    0x00000030  00000000  ANDEQ     R0,R0,R0
    0x00000034  00000000  ANDEQ     R0,R0,R0
    0x00000038  00000000  ANDEQ     R0,R0,R0
    0x0000003C  00000000  ANDEQ     R0,R0,R0
    0x00000040  FFFFFFFF  (???)
    0x00000044  FFFFFFFF  (???)
    0x00000048  FFFFFFFF  (???)
    0x0000004C  FFFFFFFF  (???)
    
    0xFFFFFFF1  FFFF      (???)
    0xFFFFFFF3  FFFF      (???)
    0xFFFFFFF5  FFFF      (???)
    0xFFFFFFF7  FFFF      (???)
    0xFFFFFFF9  FFFF      (???)
    0xFFFFFFFB  FFFF      (???)
    0xFFFFFFFD  FFFF      (???)
    

  • Your processor always starts at address 0. Which is why you need a boot loader (or help from JTAG interface to play with the program counter) to get it to enter your application.

    Since you already know about the boot loader issue, I'm a bit confused about what you mean with "start at address 0" - your simulator ini file (or your boot loader) would make sure the execution starts where it should in the application area which means it's this area you should dump if you don't agree about the contents.

    Another thing - the processor core do only support the interrupt vector table to start at address 0. So the remapping of the vector table does not move it. It just makes a very specific part of the RAM area to overlay the original ROM contents at address 0. So an application starting at 0x1000 have the interrupt vector copied into RAM and that RAM region mapped to show up at address 0.

    After this has been correctly done, memory reads at address 0 and forward should show same contents as address 0x1000 and forward and same contents as that RAM region.

    Note that newer ARM cores can remap where the interrupt vector table is stored - but older ARM cores relies on the external memory controllers to remap the address lines to make other memory show up at address 0.

  • I get what you are saying about starting at address 0x0. I was more concerned about the difference between the two debuggers and what that meant as far as what my error might be. I was hoping it would offer a clue since i'm lost.

    ; *  The LPC2400.S code is executed after CPU Reset. This file may be
    ; *  translated with the following SET symbols. In uVision these SET
    ; *  symbols are entered under Options - ASM - Define.
    ; *
    ; *  NO_CLOCK_SETUP: when set the startup code will not initialize Clock
    ; *  (used mostly when clock is already initialized from script .ini
    ; *  file).
    ; *
    ; *  SETUP_EMC: when set the startup code initializes External Bus
    ; *  Controller.
    ; *
    ; *  RAM_INTVEC: when set the startup code copies exception vectors
    ; *  from on-chip Flash to on-chip RAM.
    ; *
    ; *  REMAP: when set the startup code initializes the register MEMMAP
    ; *  which overwrites the settings of the CPU configuration pins. The
    ; *  startup and interrupt vectors are remapped from:
    ; *     0x00000000  default setting (not remapped)
    ; *     0x40000000  when RAM_MODE is used
    ; *     0x80000000  when EXTMEM_MODE is used
    ; *
    ; *  EXTMEM_MODE: when set the device is configured for code execution
    ; *  from external memory starting at address 0x80000000.
    ; *
    ; *  RAM_MODE: when set the device is configured for code execution
    ; *  from on-chip RAM starting at address 0x40000000.
    

    So RAM_INTVEC causes the exception vectors to be copied from flash to RAM. Are the exception vectors the same as the interrupt vectors?

    One of the help files states that RAM_INTVEC also causes a REMAP, so that would mean that the exception vectors get copied to ram at 0x40000000. correct? How much room do they need?

    REMAP: performs memory remap on some devices.
    EXTMEM_MODE: configures for code execution from off-chip Flash ROM.
    RAM_MODE: configures for code execution from RAM.
    RAM_INTVEC: performs REMAP and copies the interrupt vectors.
    

    If i'm reading all this correctly I won't need the REMAP, because RAM_INTVEC does both a REMAP and the vector copy.

    Do I need my code to execute from 0x40000000? is that required when using a REMAP?

    The reason for all these questions is that my bootloader requires about 0x2200 bytes of IRAM1 already and my application uses 0x97f8 bytes. That leaves about 0x4076 bytes avaliable. Is that enough for the interrupt vector table. Doesn't this also mean that i'm already executing in RAM?

  • Address 0x40000000 is in RAM.

    So your code can be anywhere in flash (except the first 64 bytes or something like this).

    The interrupt vector table is first within the application binary you build. The startup code copies this interupt vector table into the start of RAM. Then performs a remap so the first bytes of RAM is visible on top of the first bytes of the flash.

    So it doesn't matter where your application is - the remapping is always 0x40000000 -> 0x00000000. The processor core finds the copied application vectors at the start of the flash without knowing that it's remapped RAM there. It's just happy to find vectors. And the vectors points to the correct positions in your application, since the linker linked your application for the specific position you configured to use for your application area.

    But it is important that your boot loader makes sure all interrupts are disabled before you jump to the application, or hw interrupts may accidentally return back into the boot loader while the application is preparing the remapping.

  • Hi Todd,

    It is strange to me, that you use LPC2300.s for a LPC2468.
    And the mentioned "os_sys_init function" shows that you also use the RTX.
    Quite complex for me.

    I would suggest you to start with a correct working example, test it and trace it, then you know how these stuff work. This way would be simpler. After you understand these stuff, you can then tailor it for your need.

    Go to the below web page:
    ", then you will find several zip files to download. they are application notes with software.