AVR code to STM32 - Page 1
Forum section: electronics / general

author: panoss
author_rank: Frequent Contributor
timestamp: November 10, 2020, 01:00:04 pm
content: I have this code from a project with ATMega328:Code:/** constant strings (stored in EEPROM)*/const unsigned char Probing_str[] EEMEM = "Probing...";How can I convert it to STM32 code?

author: langwadt
author_rank: Super Contributor
timestamp: November 10, 2020, 01:13:02 pm
content: Quote from: panoss on November 10, 2020, 01:00:04 pmnothing in those lines of code needs convertion

author: panoss
author_rank: Frequent Contributor
timestamp: November 10, 2020, 02:57:21 pm
content: But it does not compile in Atollic TrueStudio:

author: SiliconWizard
author_rank: Super Contributor
timestamp: November 10, 2020, 03:11:24 pm
content: Just remove 'EEMEM', which is not defined (AFAIK) on STM32 and has no meaning on this platform.I guess on AVR it means to store said constants in EEPROM as stated in the comment. This is certainly not needed on STM32.If you want your code to still be compatible with AVR, instead of removing EEMEM, you could just define it in the STM32 project as an empty macro:#define EEMEM

author: panoss
author_rank: Frequent Contributor
timestamp: November 10, 2020, 03:28:03 pm
content: I just removed the 'EEMEM'.Thank you guys.

author: ajb
author_rank: Super Contributor
timestamp: November 13, 2020, 09:56:32 pm
content: So this highlights a fundamental difference between AVR and STM32 devices, and the proper way to resolve it depends on what exactly you're trying to do.AVRs (mostly) have three different memories that are accessed in different ways: Flash (where the program is stored, not generally writable by the program), RAM (working memory for variables etc), and EEPROM (nonvolatile memory that your program can rewrite, for example to store user configuration data).On an AVR, all conventional variables, including strings, are generally stored in RAM. However their initialized values need to be stored in program memory so that they can be loaded into RAM at startup, so these objects consume both flash and RAM. But if the object's value never changes, there's no point in copying it to RAM if instead you can just read it from program memory--and RAM is generally a more limited resource. So on AVR, you would use the PROGMEM macro to mark variables as being stored only in flash, and use special accessor macros to read them when needed. EEPROM is similar to flash on AVRs, except that it can be easily written by the application, so it's generally used for things like configuration that may change over the course of the application's life cycle and needs to be retained when power is lost. I'm not sure why this code snippet is storing UI strings in EEPROM, unless maybe the application is running out of flash.(Note that there are some situations where you might want constants copied to RAM, like if it provides meaningfully better performance.)STM32s on the other hand have only Flash and RAM, but they use a contiguous address space that allows you to read from flash directly, just like you'd read from RAM, without the special accessor macros that the AVRs need. You still have the same situation for constants, though, where if you declare them as conventional variables they can end up consuming RAM even though they never need to change and you might prefer to have them in flash. You can give the compiler a hint here by qualifying the values as const, which will tell the compiler that you do not intend to write to them, and cause it to issue a diagnostic if you attempt to. Note here that with pointers it matters where the const qualifier is.Code:const char * foo; // the data pointed to by foo is constantchar const * foo; // same as abovechar * const foo; // the address where foo points is constantYou can be even more specific by telling the compiler where to store that variable in memory. In GCC, this is done using the section attribute. The name of the section must match a section defined in your linker file, so you can either use an existing section or modify the linker file to create a new section.Code:const char * const __attribute__ ((section ("flash"))) foo = "bar";This is useful not just for ensuring that constants end up in flash, but anywhere you want to be very specific about where things are stored. For example, some MCUs have special extra-fast memory regions, or maybe you want to put things in a certain area and then use the MPU to protect them or something. You can even use this to put functions into those extra-fast regions if that would improve application performance.In this particular case, just removing EEMEM will probably work fine, because whatever STM32 you're using almost certainly has way more memory than whatever AVR the project targeted, and the compiler may or may not be able to optimize those values into flash depending on how the application is written and what optimizations are enabled. If it does not, and you want to save some RAM, then look into the other methods above to help get them into flash.If the values of those objects DO need to be changed by the application, then things are much more complicated because most STM32 parts (AFAIK) don't have EEPROM. So you'd have to either fit an external EEPROM, or store them in flash and implement some flash rewriting capability. Flash can only be erased in blocks, so this is not as trivial as EEPROM, and is kind of a pain if you only need to change a few bytes at a time since you will have to rewrite large chunks.

author: brucehoult
author_rank: Super Contributor
timestamp: November 14, 2020, 12:34:33 am
content: Quote from: panoss on November 10, 2020, 01:00:04 pmThat's really a very strange place to store string literals, as EEPROM is generally on AVRs 1/32 the size of flash and thus quite precious. Ok, I guess if you've filled all 32K of flash on a 328 and really really need another 1K rather than going to a bigger chip .. but it's weird.How can I convert it to STM32 code?