I suspect you are a C language programmer.
IC datasheets are generally written to a target audience of assembly language programmers, who need to be aware of many quirky little details.
Often C language programmers are happy to let pre-written library functions take care of most of those details, rather than re-writing everything from scratch.
Alas, the people who write those libraries often let some of the quirky little details show through.
There are two popular ways to store data to flash memory: let some library functions handle the quirky bits for you, or write your own functions to handle the quirky bits.
Using the library functions
Using "Data EEPROM Emulation" library that you linked.
There are several ways of using its functions to read and write your data, to store your 1024 bytes of data, such as "8 virtual EEPROM banks with 128 bytes in each bank."
Check out the "PIC24/dsPIC33F/dsPIC33E Emulation Checklist" in AN1095.
In principle, it explains how to use that library to store stuff in flash in relatively clear English.
You edit the "DEE Emulation 16-bit.h
" file, add that file and a few other library files to your project.
When your program runs, it calls the DataEEInit()
function during boot-up initialization.
Later your program calls DataEERead()
to read the latest version of your data values from flash, or calls DataEEWrite()
to write new version of your data values to flash, or both.
Since it does wear-leveling, the latest version of the data is stored at different addresses at different times -- it allocates the memory for you, and keeps track of the address of the latest version of your data. So there's no point in creating your own variable "nvram" at some fixed address to refer to that data, since even if that happens to point to the correct address at one time, sooner or later that data will move to some other address, and that variable will be left pointing to old stale data.
writing your own library functions
The __builtin_tblpage()
gives the "high part" of an address when divided up in the right way for the TBLRD
and TBLWT
instructions to read and write flash.
The __builtin_psvpage()
gives the "high part" of an address when divided up in the right way for PSV to read flash. (My understanding is that the only way for a program running on that chip to write values to its program flash is with the TBLWT instruction; those values can later be read with either TBLRD or PSV).
The slight difference between these two ways of dividing an address into a "high part" and a "low part" is implied in the "dsPIC33FJ32GP302/304,
dsPIC33FJ64GPX02/X04, and
dsPIC33FJ128GPX02/X04
Data Sheet" that you linked to, in 4 pages of the datasheet starting with "4.6 Interfacing Program and Data Memory Spaces" and "TABLE 4-39: PROGRAM SPACE ADDRESS CONSTRUCTION".
1) How do you reliably allocate the memory [at some specific address] ?
Alas, this is different for every programming language, and is different even between different C compilers.
The "MPLAB C30 C Compiler User's Guide" and its documentation updates
would be a good place to look for this information.
I think you will also be interested in the documentation for
void _erase_flash(_prog_addressT dst)
void _write_flash16(_prog_addressT dst, int *src)
_PROGRAM_END
First the programming voltage, it is given in the data sheet under the operating conditions of the memory (page 63):
Vprog Programming voltage 2 - 3.6 V
So if I read your suggestion correct it might have been powered only by that coin cell during programming? This might be very very bad indeed. The controller draws a maximum current during write operation (just the flash) of 7 mA. A small coin cell really doesn't cope well with higher currents and it's voltage as well as the capacity dropped probably really fast. Given the datasheet of a CR1220, the voltage drop on a full battery would be at least 0.5 V if you draw 7 mA from it, so it starts out at about 2.35 V, not much headroom.
But I also wonder if your circuit is fine now - have you measured the current it draws and checked all the voltages and their stability if you draw current (connect a resistor decade and vary it a bit)?
Now a possibility on how you might be able to salvage the part. I guess it won't work as you have no trouble connecting to the device, but anyways:
The F103 has a built in bootloader which is accessible if you pull the BOOT pin high during power up. You will also need access to UART1 to be able to communicate with the bootloader. Have a read of section 3.4 of the reference manual. Another good resource is this document.
If you can connect to it, there is a tool (STSW-MCU005STM32 and STM8 Flash loader demonstrator (UM0462)) available from ST which allows to interface with the bootloader and erase or program the chip.
Best Answer
Your compiler might define a name for the last address used by code and/or const data sections. I know in the one I use, it has definitions for the end of code, something like
__text_end__
and const data__rodata_end__
. I can extern these in my C code - something likeextern uint32_t __rodata_end__;
and then use these 'variables' in my code. Once the compiler & linker finish doing their jobs, these values are then automatically substituted into my code where needed.I've tried out a simple project in STM32CubeIDE, and with all the default settings it looks like it provides a symbol called
__fini_array_end
at the last used location in Flash. So you'd probably declare it asextern uint32_t __fini_array_end;
in your code and then use&__fini_array_end
to work out the start of the next page to use as simulated EEPROM.Depending on how your project's linker is configures, you might find a different arrangement of sections in flash. The default project which STM32CubeIDE created for me put
__fini_array_end
at the end. So you'll have to look at your map file to see what symbol is at the end for your project and use that instead. Somewhere down near the end of your .map file you'll see the addresses of the symbols change from the 0x080xxxxx range (Flash) to 0x2000xxxx (RAM). You might find some others like__init_array_end
,__preinit_array_end
, etc.If you're looking through the .map file and see the .data, .bss and other sections in the 0x2000xxxx range then you've gone too far and need to scroll back up a little to get back to the end of the 0x080xxxxx range.