The short answer is to declare your variable with the const
keyword. If your MCU actually remembers the value of your const
variable (i.e. your sine computation actually works), it pretty much has to be stored in flash memory, otherwise it would be lost at the first reboot after programming.
The long answer has to do with linker script. These scripts are MCU-dependant and tell the linker where to put what. Usually, this script is provided by the IDE, but you can write your own. On my STM32F4 setup, my linker script starts with a such a statement:
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
}
It says that the flash starts at address 0x08000000
and the RAM at address 0x20000000
. These addresses can be found in the datasheet where the memory map is described. The rest of the script can get involved, but at some point something along these lines will be present:
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
This says that all .text
sections (that's how the compiler calls code section) and .rodata
sections (that's how the compiler calls const
variables) are to be put in the flash section.
As suggested above, the .map
file is the primary way you can check what the linker puts where. You tell the linker to generate it using this option:
arm-eabi-gcc -Wl,-Map=my_program.map ...
You can search for your symbole inside this map file, see at which address it has been stored and check that against the memory map specified in the MCU datasheet.
You should notice that the flash is not written, it is erased. An erased flash is full of 0xFF. Your first 256 bytes are totally erased, your third 256-bytes region is partially erased (you only have 0 to 1 bitflips from correct data to corrupted one).
According to the datasheet, this flash is page-erasable (I usually work with erase-blocks bigger than the pages). As seen in page 282, Performing Page Erase by SPM is pretty easy.
You may be interested by section 23.8.1 ( Preventing Flash Corruption
) :
A Flash program corruption can be caused by two situations when the voltage is too low. First, a regular write sequence to the Flash requires a minimum voltage to operate correctly. Secondly, the CPU itself can execute instructions incorrectly, if the supply voltage for executing instructions is too low.
Flash corruption can easily be avoided by following these design recommendations (one is sufficient):
- If there is no need for a Boot Loader update in the system, program the Boot Loader Lock bits to prevent any Boot Loader software updates.
- Keep the AVR RESET active (low) during periods of insufficient power supply voltage.
This can be done by enabling the internal Brown-out Detector (BOD) if the operating volt-age matches the detection level. If not, an external low VCC reset protection circuit can be used. If a reset occurs while a write operation is in progress, the write operation will be completed provided that the power supply voltage is sufficient.
- Keep the AVR core in Power-down sleep mode during periods of low VCC . This will prevent the CPU from attempting to decode and execute instructions, effectively protecting the SPMCSR Register and thus the Flash from unintentional writes.
Best Answer
No, you don't need to disable interrupts to read from Flash. Reading Flash is just like reading RAM. It's only writing which is different: inside the device a "high voltage" (just a couple of volts extra, really) is generated for the gate, and that gate voltage needs there to be longer than just a few nanoseconds to charge the floating gate. That is self-timed by the device.