ARM Flash Memory
This post describes how to store data in the flash memory of the AT91SAM7S256 microprocessor. I wrote it because I could not find a straight-forward description on the net and also because I am bored and have nothing much else to write about today.
The Flash memory is mapped into the chip’s address space from address 0×00100000 to 0x0013FFFF. To read it, you can simply read bytes from that area of memory.
Writing to the flash is a little more complex of course. Firstly you need to set up the flash write cycle timer. This needs to be initialized with the number of CPU clock cycles required to cause a 1.5 microsecond delay. On my Olimex board with an 18.432MHz oscillator, that number works out to be 27.648 – I round it up to 28. The following line of code calculates the correct value based on the clock frequency (MCK) and programs that into the ARM memory controller.
mc->MC_FMR = AT91C_MC_FWS_1FWS | (1 + (((MCK * 15) / 10000000)) << 16);
Once that is done, we are ready to write. The chip writes one page at a time. The page size for this particular chip is 256 bytes. So that means a 256 byte section of Flash memory will be erased and completely overwritten.
Overwritten by what though? Well, you need to write your data to the section of memory where it is to be stored. You must keep your writes within the 256 byte page and you must only use 32 bit writes according to the official Atmel documentation.
Once you have written your data, it goes into an invisible RAM buffer and can then be transferred to the Flash memory by writing to the command register like so:
mc->MC_FCR = AT91C_MC_WRITE_KEY | AT91C_MC_FCMD_START_PROG | (page << 8 );
That will begin the write process. It will take some time (up to 6 milliseconds!) and you will not be able to read the data or write to any other Flash page until it is complete. You can detect when the write is complete by monitoring the FRDY bit in the status register.
The value AT91C_MC_WRITE_KEY is 0x5A000000. This is a magic number which is required for the chip to accept the flash write command (to prevent accidental overwriting I suppose).
As usual, I have prepared some example code which will compile and run on the Olimex SAM7-P256 board. Download it here:
To compile and run, type the following. You will need to have the toolchain and C library set up as described in my previous articles here and here.
tar jxvf ArmFlashTest.tar.bz2 cd FlashTest make ./startarm ./runram
As with my last example, the program is accessed via the serial port at 9600bps. Start your terminal program (I use GtkTerm) before you run the program. You will be prompted to type in a line of text. Once you press ENTER, your text will be stored in Flash. You may now run the program again and you should see your line retrieved from the Flash.
You could use this example code to store configuration data in your own ARM-based applications. This code is free to use for any purpose.
UPDATE: Dan Ashbrook kindly pointed out that my port assignments for the second serial port are incorrect in Board.h. I have now corrected the file, you can download it here: ArmFlashTest.tar.bz2

Dear Engineer
I have to write to flash on our AT91SAM7S256 from within the application. So I use the functions that you written, note i use IAR embedded workbench IDE, and ofter when it comes to the actual write then the system just hangs after the line:
mc->MC_FCR = AT91C_MC_WRITE_KEY | AT91C_MC_FCMD_START_PROG | (page
It’s probably getting caught up in the while loop a few lines down.
I’ve never used IAR but if it has any optimization options on the compiler, turn them off and try it again.
If that doesn’t fix it, I’d try checking the state of the AT91C_MC_FRDY bit before attempting the write and see if it is set. If not, there may be some problem with the initialization of the flash memory. Check the timing constant is correct for your clock speed, also make sure you have not activated any of the security features of the chip.
Dear Eng. Adam
i was form what you tell me, and i found that after i comment the
mc->MC_FCR = AT91C_MC_WRITE_KEY | AT91C_MC_FCMD_START_PROG | (page MC_FMR = AT91C_MC_FWS_0FWS | ((MCK*15) / 10000000) MC_FSR & AT91C_MC_FRDY));
AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, 0×01);
for (int j = 0; jMC_FCR = AT91C_MC_KEY | AT91C_MC_FCMD_START_PROG | (AT91C_MC_PAGEN & (page MC_FCR = AT91C_MC_WRITE_KEY | AT91C_MC_FCMD_START_PROG | (page MC_FSR & AT91C_MC_PROGE))
return 0;
// Wait for write cycle to complete.
while(0 == (mc->MC_FSR & AT91C_MC_FRDY));
return 1;
}
Dear Eng.Adam
i am sory i don’t know why the my last reply appear as you see, i was telling you that i was formed what you telled me, but i found after i comment the line:
mc->MC_FCR = AT91C_MC_WRITE_KEY | AT91C_MC_FCMD_START_PROG | (page MC_FMR = AT91C_MC_FWS_0FWS | ((MCK*15) / 10000000)
i am sory i don’t know why the my last tow replies appear as you see, was telling you that i was formed what you telled me, but i found after i comment the line of writing as you write in your code the data is writen correctly and at the specific address, note that my MCK = 48054857, and i initialze the flash by write
mc->MC_FMR = AT91C_MC_FWS_0FWS | ((MCK*15) / 10000000)
I couldn’t tell by your last post whether you have solved the problem yet Ahmed. I can see you are running a much faster clock speed than I am. I would try adding a wait state or two – eg. change 0FWS to 1FWS or even 2FWS.
I think you can only get away with zero wait states when you are running at less than 30MHz.
i actualy try to change the wait state form 0FWS to 3FWS but also the system hangs, did you thing that the system go to serve an interrupt, and if is it, how can i stop all interrupts, note i use the code at the Disabling Interrupts at Processor Level pdf which atmel publish, and ther is no effect, so i sought that as i am sure that the data is written wright i generate an intterrupt after finsh writting the data and complete the code from the ISR, is that idea wright.
regards
Interrupts are usually disabled by default unless you turn them on. My code does not set up any interrupts. Are you running the code as I wrote it or have you integrated it into another project ?
Another thing I thought of is to check that the Flash programming voltage is correct. I assume from your last post that you are not targeting the Olimex board.
Pingback by Adam Pierce » Updates to ARM tutorials — 28 September 2007 @ 10:08 pm
[...] If you try and modify the Flash Memory or the Hello World example code to send the output to the 2nd serial port, it does not work due to some incorrect port assignments in Board.h. I have replaced the original example code with the corrected version so you can download it again. [...]
I have the same problem as Ahmed. I imported your source code to my project. I use GNU gcc and OpenOcd and run my code from flash. I thought the solution is to move flashWrite to ram at run time and therefore used __attribute__ ((section (“.data”))) in declaration of flashWrite. but the problem still exist and my code hangs at the line:
mc->MC_FCR = AT91C_MC_WRITE_KEY | AT91C_MC_FCMD_START_PROG | (page
Its interesting that the buffer is written on the flash correctly but the code is hanged there.
Here are some things to check:
1. Is the write cycle timer in MC_FMR set correctly for your clock speed ?
2. Are you using 32 bit write operations ?
3. Does your chip have the correct programming voltage applied ?
4. Do you have any locks set on the flash memory ?
5. Is the page number correct ?
6. Does the address you are writing overwrite your application’s code ?
7. And of course, read the manual: http://www.atmel.com/dyn/resources/prod_documents/doc6175.pdf
I have compiled your code with the IAR compiler and it worked first time. Next I tried it with the GCC compiler and I have the same problem as the other people above. (The code is exacaly the same except for the startup code)
The code does not execute beyond the point mentioned (if I set a break point). If I break the code with the debugger after it stopped it PC is 0x0000C (some exeption). To make things more interesting the code does not crash if I step it with the debugger. Also note, irrespective if the program crash or not, the flash is always written successfully. (I have checked all the things you mentioned and they look OK)
Well I have solved my problem (point 13). While I have placed the flash write in RAM (as it should be), I did not place one of my timer interrupts in RAM which caused an load abort interrupt to be generated if the timer interrupt took place while the flash was still being written.
Another option might be to disable the interrupts while the flash is written.
Phot,
Is there any chance you could post some sample gcc code somewhere?
My code is hanging too, but I’m unable to fix it. Everthing seems
to be set right; write cycle timer, executing from ram, using the
example code, but it hangs just as FCR is written :/
Paul.
Hi Adam,
thanks for this great example.
The problems, that some users might have, seems to be related to the type conversion that’s going on. When you try to read the char buffer (char buf[96];) with 4-Byte alignment then this only works if the address of buf is (coincidentally or otherwise) 4-byte aligned! Otherwise the uC will throw a data abort exception. The code works perfectly if the 32bit word is assembled from the char array without the pointer casting, like so:
——————————————
RUNFROMRAM int FlashWrite(unsigned int address, char *data, unsigned int size)
{
unsigned int i;
unsigned int page;
unsigned int buf;
unsigned int *dest = (unsigned int *) address;
size = (size + 3) / 4;
for(i = 0; i < size; i++)
{
buf = (*(data+4*i)) | (*(data+4*i+1) << 8) | (*(data+4*i+2) << 16) | (*(data+4*i+3) <MC_FCR = AT91C_MC_WRITE_KEY | AT91C_MC_FCMD_START_PROG | (page << 8); // Write the page to Flash memory.
—————————————————
Hope this helps those users who found themselves stuck in exceptions!
Regards
Stefan
For some reason the code displays garbled, so here again:
for(i = 0; i < size; i++)
{
buf = (*(data+4*i)) | (*(data+4*i+1) << 8 ) | (*(data+4*i+2) << 16) | (*(data+4*i+3) << 24);
*(dest+i) = buf;
}
Thanks for posting that Stefan! I’ll give it a try.
Hi,
I know its a stupid question, but I am kinda new in ARM, but I want to ask this that, what is a code memory and data memory which my IAR compiler gives me the values atthe end of the map file and the list file.
I am trying to find out how much RAM and ROM my program is taking on aduc7024.
The range is 64k rom and 8k ram.
I hope you can help?…
Regards,
Zulu.
You’ll find this on any processor.
Code memory is where the program is stored – this would be assigned to ROM (actually flash memory in the ARM).
Data memory is where the program stores its data – this would be assigned to RAM.
You might also see an allocation for stack space which is in RAM too.
You can compare the numbers in the map file with the memory map of your particular chip to see if your program is going to fit in the available memory.
Hi again,
I have started using quick start kit from ADI, using aduc7024. Every thing worked fine but from yesterday I am unable to debug using ROM Monitor utility(it’s the only utility using rs232 since I dont have any jtag device),
I get a communication error that unable to connect to ROM monitor after two attempts, try again? When I say no, it gives me the error message;
Mon Mar 03 22:55:03 2008: Failed to load debugee: D:\aduc702x\Debug\Exe\1.d79
But when I try programming/downloading the code into in microcontroller its does fine and the program is run.
So no hardware problem in my opinion,?… Do you any other debuggers(evaluation/otherwise) using rs232 instead of jtag etc.
Any ideas?….
Regards,
Zulu.
If you can’t get a debugger to work, you could just write some extra code into your application to dump state, variables and so on out the serial port.
HI Adam,
Ok things are going fine on the debugger side but I am unable to generate accurate timer delays using IAR compiler for aduc7024. The code for a simple 1msec delay is
int main()
{
GP0CON = 0×00; // for p4.2
while(1){ //infinite loop
T0LD = 0xA000; // Counter Value
T0CON = 0xC0 // count down,system core clock divided by 1
// periodic mode
while(T0VAL!=0){} //producing delay
T0CON=0;
GP4DAT ^= 0×04000000; //complementing pin4.2
}
}
But on oscilloscope when I check the pin4.2 the result is not 1msec.
but a greater value, I have checked powcon and pllcon registers,their values are both 0.
Please Advise.
Hello again,
Ok, I’ve got the simulator working but when using timers (timer0 and timer1) , I am unable to get the proper delay on the oscilloscope, (e.g. on pin 4.2). If I want a delay of 1msec, I usually get a higher value delay, the main code is;
int main() //in aduc7024 40960000 instruction/sec is the max processing speed
{
WHILE(1) //infinite loop
{
T1LD=0*0A000; //40960000 * 0.001 = 40960 =A000 hex
T1CON=0*0C0;
GP0CON = 0×00; // for p4.2
while(T1VAL!=0){} //wait for the t1ld value to become zero
GP4DAT ^= 0×04000000; //complement pin 4.2 level
T1CON0;
}
}
The powcon and pllcon registers are both 0. To get the desired result what changes do I need to make?
Sorry Zulu, this article is about the ARM Flash Memory, not the timers. I have never used the timers on the ARM so I’m afraid you’re on your own with this one.
hi adam
can u tell me plz- where to see that how much code memory & programm memory taken by target(ARM processor) in ARM developer suite….Actualy .mcp file is showing that…but data mem is 0 though it is used
The linker outputs a map file which should list all the memory segments and how large they are. In the map file, look for lines like this:
.text 0×00202000 0x631c
This shows the start address and size of a segment, in this example the “.text” (code) segment which has a size of 0x631c (25372) bytes.
If you are writing in C, there is also RAM used by the stack and the heap which cannot be easily calculated at compile time.
Hi Adam,
Have you tried writing multiple pages at a time? My single page write in my project works. But for multiple writes… I put a loop to call my write function multiple time. It always gives me a prefetch abort if I run the program. However if I step over the function each time, it writes the pages successfully. I am using IAR btw.
I tried to put a loop on your code as well. Same thing happens. Umm, am I using the right approach? any idea?
Thank you.
Evon
hi Adam,
I figured out what my problem is. My program is running from flash.
Thnx for this information..
This information was useful for us to directly find the number of bytes
occupying by ROM and RAM areas…
Regards,
Kiran