Force Variable to be Stored in FLASH in C Using ARM Processor - c

I know I can force an array into FLASH in ARM by declaring it "const". But this is not truly an array of consts: I want to be able to write to it regularly. I have three large arrays that take up ~50k of the 128kB of SRAM I have available, but I have an order of magnitude more FLASH than I need. How can I force these three arrays into FLASH without declaring them const? Using IAR, BTW.
Tried using the __no_init keyword; according to the linker map files this had no effect.

To answer the original question, you can write a linker script to force any variable to reside in a predetermined area of memory (declaring them const does not force the compiler to put it in FLASH, it is merely a strong suggestion).
On the other hand, overabundance of FLASH is not in itself a good reason to keep a non-const array in flash. Among the reasons are: 1) depending on the chip, the access to FLASH memory can be much slower than RAM access (especially for writing) 2) FLASH can only be rewritten a limited number of times: it is not a problem for an occasional rewrite but if your code constantly rewrites FLASH memory, you can ruin it rather quicky. 3) There are special procedures to write to FLASH (ARM makes it easy but it is still not as simple as writing to RAM).

The C language, compilers, etc are not able to generate chip/board specific flash routines. If you wish to use flash pages to store read/write data you are going to have to have at least a page worth of ram and some read/write routines. You would need to have very many of these variables to overcome the cost of ram and execution time needed to keep the master copy in flash. In general every time you write the value to flash, you will need to read out the whole page, erase the page, then write back the whole page with the one item changed. Now if you know how your flash works (Generally it is erase to ones and write zeros) you could read the prior version, compare differences and if an erase is not needed then do a write of that one item.
if you dont have dozens of variables you wish to do this with then, dont bother. You would want to declare a const something offset for each variable in this flash and have a read/write routine
const unsigned int off_items=0x000;
const unsigned int off_dollars=0x004;
...
unsigned int flash_read_nv ( unsigned int offset );
void flash_write_nv ( unsigned int offset, unsigned int data);
so this code that uses .data:
items++;
dollars=items*5;
Using your desire to keep the variables in flash becomes:
unsigned int ra,rb;
ra= flash_read_nv(off_items);
rb= flash_read_nv(off_dollars);
ra++;
rb=ra*5;
flash_write_nv(off_items,ra);
flash_write_nv(off_dollars,ra);
And of course the flash writes take hundreds to thousands of clock cycles or more to execute. Plus require 64, 128, or 256 bytes of ram (or more) depending on the flash page size.

Believe it or not, this page is the best thing that pops up when looking how to store data in flash with the AVR ARM compiler.
On page 359 of the manual (the one that comes with v7.50 of the compiler), does show this as a way to put data in flash:
#define FLASH _Pragma("location=\"FLASH\"")
On page 332 of the manual, however, it says this:
"Static and global objects declared const are allocated in ROM."
I tested it and it seems the pragma is unnecessary with the IAR compiler, as specifying const puts it in flash already (as stated in the original question).
From the other answers, it seems like the OP didn't really want to use flash. If anyone like me comes to this page to figure out how to store data in flash with the AVR ARM compiler, however, I hope my answer saves them some time.

In IAR, you can declare your array as follows:
__root __no_init const uint8_t myVect[50000] #0x12345678
Where, of course, 0x12345678 is the address in FLASH.

Related

Reserving space in SRAM for SRAM decay experiment (C ; AVR atmega644p ; Atmel Studio 7)

I am looking to perform some experiments on an atmega644p looking at evaluating the amount of decay in SRAM between power cycles. My method is to set a number of bytes in SRAM to 0xFF, then when the mcu powers back up, count the number of remaining 1s in these bytes.
For this to work, I need to read and write the array of 1s to/from a known memory address in SRAM. So far I have code which writes the values to a specific address using a pointer set to 0x1000, and then on power up I begin reading the array from this address. However, I need a way of guaranteeing that this section of SRAM memory (say, 0x100 + 64 bytes) is not allocated to other variables/overwritten before it can be read.
I have looked online at the possibility of allocating memory segments - I don't know if this is a good solution in this case, and am not even too sure how to go about doing this. Can anyone suggest a neat way of approaching this?
Please ask any questions for clarification.
Thanks for your help.
If you're using AVR/GNU, then when C app starts it clears whole the memory and initializes global variables as required.
To avoid that, you can configure the linker to exclude all start files using options -nostartfiles -nodefaultlibs -nostdlib
If you're using Atmel Studio you can configure it like this:
After that you can mark your main for it to be called as initialization code:
int main(void) __attribute__((naked, section(".init9")));
Now you'll have the "naked" code, which does not perform ANY initialization.
That means you need at least to initialize the stack pointer and clear register r1 (which is assumed by avr-gcc to contain zero):
int main(void) {
asm volatile (
"clr r1\n" // load zero into r1
"cli" // clear I flag
);
SPL = (uint8_t)RAMEND;
SPH = (uint8_t)(RAMEND >> 8);
... // here goes your code
for(;;); // do not leave main()!
}
After this you'll have ALL global variables uninitialized. You can declare, for example a global array and check its content on startup.
You'll need to come up with a custom region in RAM by reserving space for it in your linker file. It is important that it is marked "no init" or similar, or otherwise .bss initialization and similar might happen on it before main() is called. How to do this is linker-specific.
However, writing software for this seems needlessly cumbersome. Simply use an in-circuit debugger:
Ensure that you are using a debugger which does not power the target.
Download a program which uses no RAM at all into flash. Confirm this by checking the map file.
Set the whole RAM to 0xFF through the debugger.
Remove power while keeping the in-circuit debugger connected.
Wait x time units.
Power up, hit MCU reset in the debugger, memory dump the whole RAM.
Any half-decent tool chain should be able to do this for you.

Is there a case when const data should be load in RAM rather then direct flash access

I've used few types microcontrollers.
When I write code like this:
const int var = 5;
usually var is kept in flash. I understand that const variables are not always kept only in flash. Sometimes (depending compiler, processor, options like pic etc.) they are loaded from flash to RAM before main. Is there a case, when it is better to load var into RAM?
Many microcontrollers have a unified address space, but some (such as AVRs) do not. When there are multiple address spaces, then you may need to use different instructions to access data in those spaces. (For AVR, the LPM (Load Program Memory) instruction must be used to access data in Flash, instead of one of the ordinary LD (Load) instructions.)
If you imagine a pointer to your const variable, a function receiving the pointer would not be able to access the data unless it knows which address space the pointer points into. In a case like that, you either have to copy the data to RAM, even though it's const, or the user of the pointer has to know which instruction to use to access the data.
Assuming a Microcontroller architecture like ARM Cortex or Microchip MIPS (and many others), RAM and Flash are mapped to different parts of the internal address space, like a huge array. So the Assembly commands reading from RAM are the same like reading from Flash. No difference here.
Access times of RAM and Flash shouldn't be too different, so no waiting needed on any of the controllers I've worked with.
The only case I can imagine where storing const vars in flash could cause problems is in some sort of bootloader app, when the flash is written. Of course, writing to a flash range where you are executing from is a bad idea and will cause much heavier problems than overwritten const values.

MSP430 Ram Overflow

The MSP430G2553 only has 512 Bytes of RAM but 16KB of FLASH memory. On this microcontroller, all static/global variables are assigned in RAM under .bss section. All local variables are assigned in RAM under .stack section. All dynamically allocated memory variables (malloc) are assigned in RAM under .sysmem section.
I have a need for this MSP430 to keep track of connected devices via wifi. I have a struct as such:
struct dev
{
char type[20];
char ipAddress[13];
char name[20];
char status[1];
};
This struct takes up 54 bytes of memory for each device. I am planning on having 20+ devices connected that this MSP430 and need to have 20 of these structs. 20 x 54 bytes = 1080 bytes. This is obviously too big for the 512 bytes of ram.
Is there any way to write these structs into FLASH since I have 16KB of memory to use? My understanding of FLASH is variables that are only read-only. These structs will obviously be getting assigned so it is read-write and I am not sure if it is possible.
I don't quite understand why TI would make a device which has 16 KB FLASH and only 512 Bytes of RAM, when all variables requiring read-write operations are stored in RAM. Seems like it is a waste of space.
I have tried to change these sections .bss/.stack/.sysmem to FLASH in the linker file and the MSP430 will not run like this. I have also tried to change the size of the RAM and in linker file and change the memory locations adding another 512 Bytes, but it will not run like this either.
Do I have any options here?
Yes, you can write data into the flash memory. The only problem arises when you want to change the data. You can only erase sectors, which have a size of 512 bytes. So you could take two flash sectors from the flash and store data for 10 devices in each sector.
The flash can be read like RAM though, so you don't need some kind of swapping code, you just address each device entry with a pointer.
The last problem is that flash memory has a limit of erase cycles, here around 10000 cycles. So you might also have to write code to distribute the data to different sectors over time, depending on the amount of expected changes and the desired service durability.
You can store a constant data in the flash/program memory. If you know that some variables/arrays are actually not changing once initialized, you can declare them as static const in your code and the compiler will place them in the .text section, which is usually going to the FLASH memory. If you have dynamic data that doesn't fit in the memory.. well. You are screwed, unless you can think of optimization (like reusing the same space for different things at different times..). Of course there is a possibility to implement some kind of "swapping" functionality with FLASH, if your part has a programmatic access to the FLASH writing. But it is really not that simple.
And for this:
I don't quite understand why TI would make a device which has 16 KB
FLASH and only 512 Bytes of RAM, when all variables requiring
read-write operations are stored in RAM. Seems like it is a waste of
space.
You are getting what you are paying for. Every micro has a specific range of applications it is intended for. If this specific micro is not good for your application, probably it is not in that range.
There's a good bit of extra room you can free up in this struct.
Type type field probably doesn't need to be a char array. You can use a set of symbolic constants with all the possible types.
The IP address also doesn't need to be stored as a string. Assuming IPv4, you only need four bytes.
status doesn't need to be an array of size 1. A simple char will suffice.
So now you have something like this:
struct dev
{
uint32_t ipAddress; // 4 bytes
char name[20]; // 20 bytes
char type; // 1 byte
char status; // 1 byte
}; // 2 bytes padding, total = 28 bytes
It's still not quite enough to fit 20 of these into 512 bytes of memory, but it's better that what you had.
Honestly, your best option is probably to switch to a more capable chipset. The MSP430 G-line is really meant for extremely low power and low performance applications, Ethernet being neither of those (and certainly not multiple TCP/IP connections at the same time!).
As for why they'd make a chip with a huge Flash space and tiny SRAM, well, Flash is cheap and compact, where SRAM is space-expensive on the die, so TI had to make compromises to deliver that MCU for less than $1. As some of the other answers alluded to, you can use that large amount of Flash to write more code, that can encode/compress/decode/decompress data to/from SRAM.
Another option is to use one of the "Wolverine" series of MSP430 chips. Those use a unified FRAM bank rather than separate Flash and SRAM banks.

C loading a const

const arrays get loaded into flash, or else they are in RAM.
How can I load a large const array, apart from typing in thousands of numbers by hand?
I am using the IAR compiler with an STM32F303 (Cortex M4)
You always can write an application which will generate the array from what you need and then just include it in your source file.
What are the numbers? Typically you can use off-line tools to generate C code that holds the numbers in a const array of the suitable type. This is often done for i.e. look-up tables in embedded software, and so on.
You cannot do this at run-time, since it's the linker's job to arrange the segments of the program into the various available memory-blocks.
Also, flash memory is not generally "easy" to write, i.e. you can't typically expect to be able to have a regular C pointer into flash, and just write to it and have it "stick". Programming flash generally requires dancing with the flash memory controller, and keeping in mind things like block erasure, erasing time, minimum programming page size, programming time per page, and so on. Flash memory is not so much RAM, as it is ROM that happens to be reprogrammable in software if you know how.

How to use external memory on a microcontroller

In the past, I've worked a lot with 8 bit AVR's and MSP430's where both the RAM and flash were stored on the chip directly. When you compile and download your program, it sort of "just works" and you don't need to worry about where and how variables are actually stored.
Now I'm starting a project where I'd like to be able to add some external memory to a microcontroller (a TI Stellaris LM3S9D92 if that matters) but I'm not entirely sure how you get your code to use the external RAM. I can see how you configure the external bus pretty much like any other peripheral but what confuses me is how the processor keeps track of when to talk to the external memory and when to talk to the internal one.
From what I can tell, the external RAM is mapped to the same address space as the internal SRAM (internal starts at 0x20000000 and external starts at 0x60000000). Does that mean if I wrote something like this:
int* x= 0x20000000;
int* y= 0x60000000;
Would x and y would point to the first 4 bytes (assuming 32 bit ints) of internal and external RAM respectively? If so, what if I did something like this:
int x[999999999999]; //some super big array that uses all the internal ram
int y[999999999999]; //this would have to be in external ram or it wouldn't fit
I imagine that I'd need to tell something about the boundaries of where each type of memory is or do I have it all wrong and the hardware figures it out on its own? Do linker scripts deal with this? I know they have something to do with memory mapping but I don't know what exactly. After reading about how to set up an ARM cross compiler I get the feeling that something like winavr (avr-gcc) was doing a lot of stuff like this for me behind the scenes so I wouldn't have to deal with it.
Sorry for rambling a bit but I'd really appreciate it if someone could tell me if I'm on the right track with this stuff.
Update
For any future readers I found this after another few hours of googling http://www.bravegnu.org/gnu-eprog/index.html. Combined with answers here it helped me a lot.
Generally that is exactly how it works. You have to properly setup the hardware and/or the hardware may already have things hardcoded at fixed addresses.
You could ask the same question, how does the hardware know that when I write a byte to address 0x21000010 (I just made that up) that that is the uart transmit holding register and that write means I want to send a byte out the uart? The answer because it is hardcoded in the logic that way. Or the logic might have an offset, the uart might be able to move it might be at some other control register contents plus 0x10. change that control register (which itself has some hardcoded address) from 0x21000000, to 0x90000000 and then write to 0x90000010 and another byte goes out the uart.
I would have to look at that particular part, but if it does support external memory, then in theory that is all you have to do know what addresses in the processors address space are mapped to that external memory and reads and writes will cause external memory accesses.
Intel based computers, PC's, tend to like one big flat address space, use the lspci command on your Linux box (if you have one) or some other command if windows or a mac, and you will find that your video card has been given a chunk of address space. If you get through the protection of the cpu/operating system and were to write to an address in that space it will go right out the processor through the pcie controllers and into the video card, either causing havoc or maybe just changing the color of a pixel. You have already dealt with this with your avr and msp430s. Some addresses in the address space are flash, and some are ram, there is some logic outside the cpu core that looks at the cpu cores address bus and makes decisions on where to send that access. So far that flash bank and ram bank and logic are all self contained within the boundaries of the chip, this is not too far of a stretch beyond that the logic responds to an address, and from that creates an external memory cycle, when it is done or the result comes back on a read it completes the internal memory cycle and you go on to the next thing.
Does that make any sense or am I making it worse?
You can use the reserved word register to suggest to the compiler that it put that variable into an internal memory location:
register int iInside;
Use caution; the compiler knows how many bytes of register storage are available, and when all available space is gone it won't matter.
Use register variables only for things that are going to be used very, very frequently, such as counters.

Resources