Where to put a variable in flash

I am currently writing a program that will need to be able to hold the user-assigned address perpetually. I am using a Philips LPC2148 and I have found the section in the manual that shows you how to write RAM to flash via the IAP interface.

How do I know where to put this variable in flash, though? Is there a way to declare a variable in my C program (I’m using WinARM to compile) that will specifically go into the flash? This would keep the program from potentially overwriting it with code. Even better, is it possible to make the compiler write to the flash location without having to go through the IAP (say like var = 5)? Any help would be awesome.

Hi Brennan.

What you intend to do is, at run-time, put an item of data (user-assigned address) into onchip flash.

Philips onchip flash is just like most other flash memory you may encounter. You have to erase it first and then program the new information into it using the IAP routines.

Fortunately, Philips LPC2000 flash is broken up into 8K blocks and these individual blocks may be erased by IAP commands. Obviously, you would have to sacrifice an entire 8-k block to hold a single 4-byte address or go to the trouble of copying the entire flash block to RAM, changing the 4-byte data item, and then reprogramming the entire 8K block again.

It’s a difficult trade-off. RAM is a more precious resource in these highly-integrated microcontrollers. I suspect that sacrificing one of the 8k flash blocks is a better solution for non-volatile storage.

As far as I know, there is no way to avoid using the IAP routines to alter flash memory at run-time. Philips has an application note describing this here: http://www.semiconductors.philips.com/a … 0256_1.pdf

Cheers,

Jim Lynch

Thanks for the reply, Jim. Do you think it would be wise for me to rename the section of flash that I use to put my variable in in the linker script? I noticed in your notes that if you gave a section of memory a name, that the linker wouldn’t try to put code and other stuff there.

Hi Brennen.

GNU C does allow you to put variables in a “user defined” section. These variables have to be global (defined above the function definition).

For example, here’s three variables defined as global and placed into the section USER1 by use of the “attribute” specification.

/************************************************************

Variables assigned to a user section

************************************************************/

unsigned int encoder_count attribute ((section(“USER1”))) = {0};

unsigned char marker_pulse attribute ((section(“USER1”))) = {0};

unsigned char direction attribute ((section(“USER1”))) = {0};

/**********************************************************

MAIN

**********************************************************/

int main (void) {

int j;

int a,b,c;

Now, in the linker command script, I will first identify where in flash I want to place the USER1 section. Note that I placed it in the last 8k block of flash memory.

/* specify the LPC2106 memory areas */

MEMORY

{

flash : ORIGIN = 0, LENGTH = 248K

user_flash : ORIGIN = 0x3E000, LENGTH = 8K

ram : ORIGIN = 0x00200000, LENGTH = 64K

}

Now, we have to create a linker output section and direct it’s placement into the “user_flash” memory area.

/* now define the output sections */

SECTIONS

{

. = 0;

.text : {

*(.text) *(.rodata) (.rodata) *(.glue_7) *(.glue_7t) _etext = .;

} >flash

.data : {

_data = .; *(.data)

_edata = .;

} >ram AT >flash

.bss :

{

_bss_start = .;

*(.bss) } >ram

.user :

{

_user_start = .;

*(USER1)

} >user_flash

. = ALIGN(4);

_bss_end = . ; }

_end = .;

Now if you compile and link this, these three variables appear in the last 8k block of flash. You would have to use the IAP routines at run time to update them, obviously.

.user 0x0003e000 0x8

0x0003e000 _user_start = .

*(USER1)

USER1 0x0003e000 0x8 main.o

0x0003e000 encoder_count

0x0003e005 direction

0x0003e004 marker_pulse

0x0003e008 . = ALIGN (0x4)

0x0003e008 _bss_end = .

0x0003e008 _end = .

Sorry that this is such a long description. You can see the advantage of the professional compilers; they usually have shortcuts available to do this more conveniently.

Cheers,

Jim Lynch

Thanks so much, Jim. You are the guru of all things ARM. 8)

Hi Brennen.

In my haste to edit the linker script for inclusion into this forum, I dropped a carriage return in the .bss section. Properly edited it should look like this:

.bss :

{

_bss_start = .;

*(.bss)

} >ram

This should be a bit clearer now.

Jim Lynch

If the LPC is like most Flash (and EPROM) devices there is no need to erase before writing for a single time.

Just make sure the location is programmed to all ones initially.

You can then take any bits to zero when you write your value.

You can actually write a number of times but you cannot get any bits that were previously zeros back to ones without an eraze.

I have not tried the LPC Chips to see if they behave this way or if the Philips routines support doing this.

I hope this helps.

The LPCs have the additional limitation that you can’t program a block of 16 bytes again, because of a ECC mechanism. Flashing could program additional bits from one to zero, but the ECC would likely require bits to be changed from zero to one.

Also, the IAP routines work on a minimum block size of 256 byte, which means you’d have to copy the whole block to ram, modify it with the new data, and then program the block back to flash.

But, as Jim already said, it heavily depends on what that data is which brennen wants to store. How often is it going to be changed? If it’s only written once every now and then, and you’re not short on Flash space, using a flash sector of its own would be fine, but if it needs to be written often, or if you’re running out of flash, then an additional EEPROM might be more appropriate.

Regards,

Dominic

I’ve actually considered just getting a really small external EEPROM and hooking it up to the SPI port. After looking at all this, it seems like in the end it might be easier.