Reply by Mike Harrison May 8, 20092009-05-08
On Fri, 08 May 2009 11:34:03 -0000, you wrote:

>> The idea behind this module is to reprogram the ARM's firmware from a
>> USB drive, by our customers. If the module lives in RAM, when we ship
>> then the product, then module will be lost do to power toggles, which
>> is something we don't want. The module is a self-contained driver
>> that "talks" to a USB controller and reads the firmware binary from a
>> connected USB drive. The firmware is read into RAM and then loaded
>> into flash via IAP calls. Because of the reprogramming, this module
>> must execute from RAM, but to allow the customer to reprogram anytime
>> they want, the module must live in flash.

Where the storage/comms involves a lot of code (USB/TCP etc.) another option is to add an external
serial eeprom/flash chip.
The new firmware image can be copied into it by code residing within the main application, and only
when the new image is complete and verified, it can be IAP'd using a very simple loader.

This avoids the risks of a RAM-based complex loader leaving a system in limbo due to an incomplete
update. With the above approach, the 'vulnerable' window when copying the image is typically only a
second or two.

An Engineer's Guide to the LPC2100 Series

Reply by CokaCola May 8, 20092009-05-08
> The idea behind this module is to reprogram the ARM's firmware from a
> USB drive, by our customers. If the module lives in RAM, when we ship
> then the product, then module will be lost do to power toggles, which
> is something we don't want. The module is a self-contained driver
> that "talks" to a USB controller and reads the firmware binary from a
> connected USB drive. The firmware is read into RAM and then loaded
> into flash via IAP calls. Because of the reprogramming, this module
> must execute from RAM, but to allow the customer to reprogram anytime
> they want, the module must live in flash.
>

I had the same problem. In my application there is not enough RAM left to do a scatter loading of the module at startup.

I found a soloution to fix this problem (see source code attatched below). Within the module a scatter loading section named UPDATER is defined (there is no need to edit the scatter loading description file). The two linker variables UPDATER$$Base and UPDATER$$Limit represents the boundaries of this module. They are used to controll the copy process.

I'm using RealView MDK-ARM Version: 3.40.

/*
* ==> Compile this file position indipendend! <= *
* Open: Options for file 'Updater.c' -> C/C++
* Enter '--apcs=/ropi' into the field 'Misc controls'
*/
#include

#pragma push // store current pragmas
#pragma O0 // disable optimation
#pragma arm section code="UPDATER" // create new scatter section

typedef void func_type(void);

/*
* linker defined variables.
*/
extern unsigned long UPDATER$$Base; // first byte of section UPDATER
extern unsigned long UPDATER$$Limit; // first byte after section
// UPDATER

/*
* (dummy function)
* A simple function called by Update_FW.
*/
void Sub_function(void)
{
FIO0CLR |= 0x08000000; // clr pin
}
//////////////////////////////////////////////////////////////
/*
* (dummy function)
* In the real project, this function will update the flash
* with the new firmware.
*/
void Update_FW(void)
{
FIO0SET |= 0x08000000; // set pin
Sub_function();
}
//////////////////////////////////////////////////////////////
/*
* Copy the code of this module to the desired address.
* Return a function pointer to Update_FW now located in RAM.
*/
func_type* Copy(unsigned int addr)
{
unsigned int *src, *dest, *begin, *end, offset;

// boundaries of the section UPDATER
begin = (unsigned int*) &UPDATER$$Base;
end = (unsigned int*) &UPDATER$$Limit;

src = begin;
dest = (unsigned int*) addr;

// copy data from FLASH to RAM
while (src < end)
{
*dest++ = *src++;
}

// offset between the function Update_FW
// and the base address uf the section UPDATER
offset = ((unsigned int) &Update_FW) - ((unsigned int) begin);

// return pointer to the function Update_FW
// now located in RAM
return (func_type*)(addr + offset);
}
//////////////////////////////////////////////////////////////
#pragma pop // restor pragmas

Reply by rtstofer May 14, 20072007-05-14
--- In l..., "kohansey" wrote:
>
> Thank you, Richard for you detailed reply. I was wondering if any
> knows how to do exactly what Richard just described but using the
> RealView compiler?
>

Seems to me that Darcy Williams has already pointed you to the answer:
http://tech.groups.yahoo.com/group/lpc2000/message/24836

Doesn't the factory (Keil) approach work?

Richard
Reply by kohansey May 14, 20072007-05-14
Thank you, Richard for you detailed reply. I was wondering if any
knows how to do exactly what Richard just described but using the
RealView compiler?
Reply by kohansey May 14, 20072007-05-14
Thank you, Richard for you reply. Do anyone know how to do what
Richard just described but using the RealView compiler?
Reply by rtstofer May 11, 20072007-05-11
--- In l..., "kohansey" wrote:
>
> The idea behind this module is to reprogram the ARM's firmware from a
> USB drive, by our customers. If the module lives in RAM, when we ship
> then the product, then module will be lost do to power toggles, which
> is something we don't want. The module is a self-contained driver
> that "talks" to a USB controller and reads the firmware binary from a
> connected USB drive. The firmware is read into RAM and then loaded
> into flash via IAP calls. Because of the reprogramming, this module
> must execute from RAM, but to allow the customer to reprogram anytime
> they want, the module must live in flash.
>

This type of thing is trivial with GNU gcc and ld. It's almost fully
documented in the 'ld' manual (page 44 of 'Using ld' Version 2.14). I
tried it yesterday and it appeared to work just fine.

However... (Don't you just hate however's?) You have to declare a
pointer to the function and call via the pointer. Otherwise you will
have a problem with addressing.

Here's the function prototype:

int Setup1(void) __attribute__ ((naked)) __attribute__ ((section
(".xram")));

Here's the function:

int Setup1(void)
{
return 4;
}

Here's the pointer declaration:

static int (*pramfunc)(void) = Setup1;

Here's the invocation:

void Setup(void)
{
(*pramfunc)();
...
}

Finally, here's what I did to the 'ld' script. It needs further
refinement:

SECTIONS
{
.text :
{ {
*(.startup)
*(.text)
*(.rodata)
*(.rodata*)
*(.glue_7)
*(.glue_7t)
_etext = .;
} >flash

.other :
{
_other = .;
*(.xram);
_eother = .;
} >ram AT >flash

.data :
{
_data = .;
*(.data)
_edata = .;
} >ram AT >flash

.bss :
{
_bss_start = .;
*(.bss)
} >ram

. = ALIGN(4);
_bss_end = . ;
_end = .;

.dma :
{
_dma_start = .;
*(.dma)
_dma_end = . ;
} >ram_usb_dma
}

By defining the symbols '_other' and '_eother', I can copy the flash
between these locations to the beginning of RAM. In fact, the .map
file will show space for the code in RAM before the linker allocates
.data. By definition, this is the beginning of RAM.

Now, if the function had position independent code, it would be even
more fun to copy it to the stack and run from there. This would
eliminate the static allocation of RAM for a function that runs every
couple of years. I have no idea if this will work.

Or, use the overlay feature of 'ld' and see if you can put the code
into .bss or even .data on top of other data. After all, the system
will require a reboot after updating so trashing these areas is
unimportant.

In any event, there is no point in copying the code to RAM until it is
time to run. Copying certainly doesn't need to be in the startup code
where RAM is initialized.

Kind of a slow day yesterday...

Richard
Reply by kohansey May 11, 20072007-05-11
The idea behind this module is to reprogram the ARM's firmware from a
USB drive, by our customers. If the module lives in RAM, when we ship
then the product, then module will be lost do to power toggles, which
is something we don't want. The module is a self-contained driver
that "talks" to a USB controller and reads the firmware binary from a
connected USB drive. The firmware is read into RAM and then loaded
into flash via IAP calls. Because of the reprogramming, this module
must execute from RAM, but to allow the customer to reprogram anytime
they want, the module must live in flash.
Reply by Brendan Murphy May 11, 20072007-05-11
--- In l..., "kohansey" wrote:
>
> I know that the Keil CARM compiler has the __ram keyword that does
> something similar, however, I am using the RealView compiler (even
> though it is Keil IDE). The keyword __ram doesn't work with the
> RealView compiler. One of the previous postees gave a link to scatter
> loading, this seems to be the way to go, however, the app-note doesn't
> give an example or go into detail about what I am attempted to do, and
> it doesn't tell me how to define a section in my C code that is used
> with the scatter file. So I am still left in the dark. If anyone has
> experience with scatter loading and having a different load and
> execution areas, please post an example.
>

Just as a matter of interest, why do you need to run from RAM in the
first place?
Reply by kohansey May 11, 20072007-05-11
I know that the Keil CARM compiler has the __ram keyword that does
something similar, however, I am using the RealView compiler (even
though it is Keil IDE). The keyword __ram doesn't work with the
RealView compiler. One of the previous postees gave a link to scatter
loading, this seems to be the way to go, however, the app-note doesn't
give an example or go into detail about what I am attempted to do, and
it doesn't tell me how to define a section in my C code that is used
with the scatter file. So I am still left in the dark. If anyone has
experience with scatter loading and having a different load and
execution areas, please post an example.
Reply by Mike Nelson May 11, 20072007-05-11
IAR has an extension in their C/C++ compiler called
"__ramfunc". You put it in your function declaration
and it is stored in flash with the rest of your code.
The function with the "__ramfunc" declaration is copied
to RAM during initialization before the "main" function
is executed. It is linked to run in RAM only, it will
not run properly in its flash storage location.

Does Keil have something similar?

--- In l..., "kohansey" wrote:
>
> Those are all good answers to get the module to compile into RAM, and
> I have already try these things. What you might not understand is
> then you tell Keil to put a file into RAM, it does exactly that, but
> as soon as you power down the device, you just lost your RAM program
> and there is nothing in flash to restore it. So good attempts, but I
> have already tried that.
>
> I need to be able to compile the module with the rest of my project
> into flash, so that the module will also be available to the device
> when needed. That part is easy, just compile normally. But now I
> want to take the module that resides in flash, copy it to RAM and
> execute it. That is my question, sorry if I had confused anyone.
>