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

Parents Reply Children
  • Yes I think you are correct. They are strings and the USB upload process does not update the addresses for the new string information. I have verified that with the debugger. What portion of the code do you need to see? All of it? This is for a company not a personal project. i'm a little hesitant to throw it all out there into cyberspace if I don't have too.

    If I load the same hex file through the ULINK2 it properly updates the entire memory.

  • The USB loader in the bootloader does not contain any information for preprocessing the HEX data and convert all references where the "main" program references into the "bootloader" part, and that errs when you try to mix one boot loader with another "main" application. To perform reference fixups, there must be relocation information in the file you program your device with. But HEX files do not contain any relocation information. And your boot loader wouldn't know what to do with them anyway - it's a dumb loader. Not a full linker.

    Never, ever, try to get the compiler to build boot loader and application together. Even when you do everything 100% correct, you can't control the small helper functions that the compiler will use. Things like performing long division or similar, that the processor may not have native instruction-set support for and that is too big to just inline everytime it is needed.

    It is possible to have the same source code for both boot loader and application. But it does require two separate compilations, and would then result in two separate hex files. It's possible to merge these two hex files manually (or automatically with suitable tools) if you need a single file for factory production.

    But your project setup must guarantee that any change in the boot loader (as long as the size still fits in reserved space) will not change any single byte in the application. And any change in the application must not result in any single byte changed in the boot loader. Everything else is a big, epic, failure. What seems to work will fail when you are in most need of it to work.

  • first, Per brings up more things against a "monoprogram" than I thought of. I am sure that there are more

    second,
    But your project setup must guarantee that any change in the boot loader (as long as the size still fits in reserved space) will not change any single byte in the application. And any change in the application must not result in any single byte changed in the boot loader.
    even that will not guarantee functionality

    Erik

  • You have all convinced me that I'm not going to get this to work reliably till I separate the bootloader from the app.

    Thanks for all your help! Wish me luck!

    Todd

  • "developing the bootloader and the main application as a single program"
    is a quite standard way here in my current company; and of course, it works well.

    "What seems to work will fail when you are in most need of it to work."
    It fails, mainly because a MCU design flaw, and/or a compiler design flaw.

    The bootloader I developed is a freak for my current company.

    My bootloader is able to dump the content of flash, so that I can compare the HEX file with the programmed flash to make sure the flash programming is successful. Of course this is a totally unnecessary functionality.

    --
    Hopeless Battle.

  • So if your company is making one compile/link pass that ends up generating both a boot loader and an application - how have you managed to get the compiler/linker to not call any helper function that gets stored in one memory area from the other memory area?

    Or is the boot loader written 100% in assembler?

    The nice thing with building both in the same step is that it looks like it works, until you make the wrong type of changes in the code. Suddenly a change in the boot loader generates changes in the application area. Or a change in the application generates changes in the boot loader area. And when that happens, you are in a deep pile of ***. The equipment already shipped can't be updated until the problem is solved. But if the shipped boot loader has a reference into the application area, you just have to figure out how to get the compiler to produce a new application that still has the exact same contents at that location.

    By the way - all boot loaders are expected to have code to verify that they correctly program the application area. But that is something completely different from having a boot loader that doesn't contain unexpected, "hidden" references into the application area, that makes the boot loader fail after an update of the application.

  • is a quite standard way here in my current company; and of course, it works well.

    The bootloader I am commonly using has a small dependency between it and the application in the form of a piece of RAM telling the bootloader whether it should perform IAP, in addition to some checksums of the data and the location of the data in RAM. No explicit dependencies exist beyond that - otherwise, the thing is becoming one program, really...

  • 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?