How to create/link a program that runs ONLY in flash memory

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to create/link a program that runs ONLY in flash memory

9,667 Views
AndersJ
Contributor IV
I would like to upload one or more applications to flash memory,
and then on reset/boot have a small handler runing in block 0
jump to one of the applications.
 
The application can then upload an upgrade of itself and put it
in a free block of flash memory, generate a reset, and have the
block 0 handler jumpstart to the new application.
 
This is basically a live firmware upload with only a second of downtime
for restart of the new uploaded version. I believe this is a safe "bootload"
approach since the uploaded program can be checksummed before
it starts. Also the upload is allowed to crash without bringing the
application down for good, as might happen in a conventional RAM-based
bootloader.
 
Now to my question:
Is it possible to locate a program entirely in flash memory,
so it will not need anything stored in for instance 0xC000
or any other area under 0xFFFF?
 
I realize the vector table is an issue here, but I think I can
handle that via a secondary vector table to jmp into the
correct table, hopefully also stored in flash.
 
Thanks for any pointers in the right direction,
Anders J
 
Labels (1)
0 Kudos
11 Replies

1,646 Views
imajeff
Contributor III
Hi Anders,

I get the thing you are trying to do, and I think I have the best solution (at least generally).

The problem is actually that embedded differs from a typical RAM-based PC in that it has no dynamic linker on-system. What you wanted is to dynamic-link your application as it loads into Flash, so that every time you upgrade firmware, it loads into a new location, then executes from there. Problem is that PCs are designed to do that (the large RAM helps with vectors and such), but the ROM-based firmware is not designed to do that.

Before the solution, I need to clarify one thing in your question. When you refer to "0xC000 or any other area under 0xFFFF", you should know that those are Flash. The Flash is all the parts in the MCU that are rewritable ROM. The memory banks you are thinking of separately are just another way to address the Flash so there can be more of it, but writing to 0xfffe is actually writing to the expanded address 0xffffe, or 3F:BFFE.

The solution I think is simple... a double-write of Flash. While you are loading the upgrade to the MCU Flash, you are assuming there is always enough Flash for at least two complete instances of the application. That is great because you only need two to make a safe upgrade. The backup version is still in place to execute on the next boot, and the bootloader section can be busy writing the upgrade to a temporary Flash block where it can verify integrity and everything. After it is satisfied that the upgrade was written successfully to temporary Flash location, the bootloader can safely erase the excecutable location in Flash and start copying from temporary Flash to the location where the application is always linked.
0 Kudos

1,646 Views
imajeff
Contributor III
Looking at my proposed solution and your trouble of how to control CW for more controlled link destinations, I see that you will need to be a master of your linker. I suggest that CW is not good for that, but I wouldn't really know. I just feel much more control using GCC.

Either way, I see that the linking is already solved if you follow my previous post. The next challenge might be how to keep track of re-link information in order to copy from temp to executable location. For example the upgrade wants to load vectors to 3F:BF80 which you cannot because the current app has vectors loaded there. So you could store that in 30:BF80 and keep track that this is the vector table to move later to 3F:BF80.
0 Kudos

1,646 Views
AndersJ
Contributor IV

Hi again, and thanks for your lengthy response.

You are describing exactly what I want to do. I will not be using a "simple bootloader" to upload the upgrade, because it is a fairly complex procedure using a CAN based protocol over a large geographical area, and the upload sw is located inside the application, since the appliciation is needed to do the communication.´

Since the application/loader puts constants at 0xCnnn it is reasonable to believe that the uploaded upgrade will have similar constants in the same area in block 0, The running program would therefore have its constants overwritten during the upload.

I believe I cannot just move everything the S19 file wants to put in block 0, to another block. I want to link/locate it to block 0, so that the program can still find it. I cannot however figure out how to do this, and that is my major problem right now.

If I could resolve the linker issue I would not need a temporary flash location, which is good because, if something goes wrong during the erase/copy procedure the old and working program may have been erased, and not yet been replaced by the new one. If on the other hand I could have the ENTIRE application in block 1 and than swap to another vector table, the risky time window is almost zero.

Anders

 

0 Kudos

1,645 Views
imajeff
Contributor III
Well the way I've suggested doesn't involve the dynamic linking you are having trouble with, which is why I suggested it. I admit my method adds a little more risk by still needing to overwrite the same addr space, but I've seen that the greater risk is in the transmission between systems, not within the MCU that is upgrading.

I just don't think you will ever eliminate all of the fixed-ppage dependency caused by normal use of C and CodeWarrior. It would seem easier though, if it were GCC. The linker script seems simpler in telling in which memory regions to place anything. It even lets me put everything in PPAGE banks so that there is no way possible for the application to boot :smileyhappy:
0 Kudos

1,646 Views
mjbcswitzerland
Specialist V

Hi Anders

The internal FLASH of the HC12 is designed for boot loaders (as is FLASH in most other uPs too). I would take a quick look at the serial monitor usind for example in the M9C12NE64. It occupies 2k (I think) and coordinates downloads.

When it starts it it checks to see whether there is a valid application loaded. It can delete an application and accept a download of new code.

It handles all interrupts but allows the user to load a new jump set - also what you are thinking about.

It uses the top 2k in FLASH (protected sectors) and probably this is the best way to go because the code and vectors are together (which seems logical).

Look for the application note AN2548 (code is available to the app. note) and also at AN1280A (the more powerful d-Bug12) which shows how user definable vectors ad calls are implemented.

Good luck.

Mark Butcher
www.mjbc.ch

0 Kudos

1,646 Views
AndersJ
Contributor IV

Mark,

Thanks for your comments.

I have read these AN's, and they are helpful in general terms. It seems however that CW always puts some data in non banked memory as illustrated by the cut-out below from the map file.

I would like to load my application in block 1, above 0xFFFF and NEVER touch non banked memory.

Or, put another way: I want a basic very simple kernel running in non banked memory, that calls the main application in block 1, or on command calls a newly upgraded application in block 2 instead. In this case the question would be how to extract the code that is located in banked memory, and upload only that. Perhaps extract and upload only those S19 records?

It seems my big problem is that CodeWarrior ALWAYS needs some non banked memory.

How to get around that?

My big concern it to minimize the risk of getting a dead device if there is a problem during bootload. A conventional ram based bootload has a rather large time window during which nothing may go wrong. My approach, would shorten this time window to a short one byte Page swap in a EEPROM byte, and a COP reset. Virtually no time window at all, and plenty of time during upload to validate the received new program. The backside to my approach seems to be that I can't make it work :smileysad:

All comments appreciated, thanks,

Anders J

================= CUT ===============

.init                             32     R     0xC000     0xC01F   ROM_C000
.startData                        30     R     0xC020     0xC03D   ROM_C000
.rodata                          468     R     0xC03E     0xC211   ROM_C000
.rodata1                        2642     R     0xC212     0xCC63   ROM_C000
NON_BANKED                      2058     R     0xCC64     0xD46D   ROM_C000
.copy                            255     R     0xD46E     0xD56C   ROM_C000

0 Kudos

1,646 Views
Sten
Contributor IV
I actually do not quite understand what you want to do, but if you put a small bootloader (like the one in AN2153) in the protected top of block 0, you can then load your application to where ever CW want to put it (block 0 or block 1, banked or unbanked). The only thing to do in the application is to exclude the bootloader area from the PRM-file and to move the interrupt vectors to a place where the bootloader can find them.
0 Kudos

1,646 Views
AndersJ
Contributor IV

Sten,

I have tried to exclude everything from block 0, but the constants are a problem. If I force them to block 1, by removing the NON BANKED memory areas from the PRM-file, I get various linker errors, seen below. It seems CW needs these constants under 0xFFFF.

Anders

=====================================

L1128: Cutting value pZeroOut startup data member from 0x3D8057 to 0x8057
L1128: Cutting value toCopyDownBeg startup data member from 0x3CBE11 to

 

0 Kudos

1,645 Views
Sten
Contributor IV
If you want to put your whole application in block 1, you will have to modify the start12.h and start12.c to use far pointers when initialising static variables or to use the 'minimal startup code' option when making the project.
0 Kudos

1,302 Views
Vaibhav15
Contributor II

Hi Sten,

Can you please explain changes required for placing the application and running application code form the other blocks in more details. I have one use case mentioned below

So I am using MC9S12XEP100CVL controller and I am using Block 0[256KB] for bootloader application which uses around 12 sectors[code and verification data]  and user application is around 680KB so we are not able to use remaining sectors of block 0 due to XEp100 limitation mentioned below.

Limitation: XEP100 does not allow to perform any operation like erase and write on the unused flash addresses of particular Block where the code is running.

So there are two options I can think of 

1. Using other blocks for running the user application code.

   - Can you please share any example code or what all things we need to take care for running user     application from different blocks?

  - Do we need to update parameter file[prm] ? 

2. finding a to way to use the remaining block of the block 0.

   - Is there any way we can write to unused sectors of block 0 where my bootloader application is running?

I added this question in detail on community. Please find attached link for same 

Link : https://community.nxp.com/t5/S12-MagniV-Microcontrollers/FW-update-using-bootloader-in-XEP100-HSC12X...

Any kind of help will be appreciated. 

Thanks in advance.

 

0 Kudos

1,646 Views
CompilerGuru
NXP Employee
NXP Employee
For which derivative is this anyway?
Also, what's the size of the complete application to be downloaded?
If it is smaller than one page, 16k, it should not be much of a problem.
Just set PPAGE initially and never ever modify it, and that's it :smileyhappy:.

If it is larger than 16, then there are completely different things to consider.
For example, the CALL instruction does encode the page to be called, so the applications can only be loaded in their link time page. Just spliting up all pages in two areas is not enough, you would also need to build/download the application which was actually linked into the currently unused pages.
Is initiailization of globals needed, if so, enable the paged support. If not, switch off the startup code.
The hardest part, I think, is actually the handling of the runtime support. CodeWarrior is using the runtime support with JSR, so it has to be always reachable.

If the app is just a bit larger than 16k, maybe it can be split up into multiple 16k sub applications? Then you would need some RAM based way to call from one app to the other (to avoid to use CALL extended, which hardcodes the page), but if the interface between the 16k apps is small, this should be doable.

Daniel
0 Kudos