STM8 equivalent of AVR's PROGMEM/__flash - Page 1
Forum section: electronics / general

author: HwAoRrDk
author_rank: Super Contributor
timestamp: January 09, 2020, 04:44:32 pm
content: I am experimenting with the STM8 platform, writing some code in C and compiling with SDCC, and I'm trying to determine whether anything special needs to be done to place constant data (arrays, strings, etc.) in to flash program memory - like one might do on the AVR/Arduino platform withPROGMEMor__flash.I've been looking at the assembly listing and map files that SDCC spits out, and Ithinkit may be intelligent enough to place anything that's declaredstatic constin flash. But I'm not sure, because this is the first time I've used both SDCC and the STM8 platform, so I'm not familiar with how the compiler does things nor with the assembly language. Can anyone help confirm to me that things are (or aren't) how I think they are?I have the following array (UART BRR register constants for various baud rates):Code:const static uart_baud_cfg_t uart_baud_cfg[] = {{ .brr1 = 0xA0, .brr2 = 0x1B }, // 2400{ .brr1 = 0x68, .brr2 = 0x03 }, // 9600{ .brr1 = 0x34, .brr2 = 0x01 }, // 19200/* etc... */};The map file appears to say thatuart_baud_cfgis placed in the 'CONST' area:Code:Area Addr Size Decimal Bytes (Attributes)-------------------------------- ---- ---- ------- ----- ------------CONST 0000808C 0000003C = 60. bytes (REL,CON)Value Global Global Defined In Module----- -------------------------------- ------------------------0000808C Fserial_test$__str_0$0_0$0 serial_test000080AD Fuart$uart_baud_cfg$0_0$0 uartAddress 0x80AD is indeed in the flash memory area (STM8 has a linear address space, where I believe flash starts at 0x8000), and that is exactly where that data has been placed in the compiled binary firmware file.If I look at the assembly code for the lines where I am accessing the array, it appears to be loading directly from the address specified by the symbol_uart_baud_cfg, which is defined later on as, again, being data in the 'CONST' area:Code:000069 175C$uart.c$87$1_0$24 ==.176 ;uart.c: 87: UART1_BRR1 = uart_baud_cfg.brr1;000069 5F [ 1] 177clrwx00006A 7B 03 [ 1] 178lda, (0x03, sp)00006C 97 [ 1] 179ldxl, a00006D 58 [ 2] 180sllwx00006E 1Cr00r00 [ 2] 181addwx, #(_uart_baud_cfg + 0)000071 F6 [ 1] 182lda, (x)000072 C7 52 32 [ 1] 183ld0x5232, a000075 184C$uart.c$88$1_0$24 ==.185 ;uart.c: 88: UART1_BRR2 = uart_baud_cfg.brr2;000075 E6 01 [ 1] 186lda, (0x1, x)000077 C7 52 33 [ 1] 187ld0x5233, a283.area CONST000000 284 Fuart$uart_baud_cfg$0_0$0 == .000000 285 _uart_baud_cfg:000000 A0 286.db #0xa0; 160000001 1B 287.db #0x1b; 27000002 68 288.db #0x68; 104'h'000003 03 289.db #0x03; 3000004 34 290.db #0x34; 52'4'000005 01 291.db #0x01; 1; etc...So, is my array definitelyonlybeing included in flash and nowhere else? And that declaring something asstatic constis all I need to do?One doubt I have is that I have read some tutorials that talk about manually marking variables with SDCC-specific__at(<addr>)attributes (using an 0x8000+ address) if you want stuff put in flash. But that seems a pain, as you'd have to do all the address bookkeeping manually, making sure there is no overlap, doesn't conflict with code, etc. and I would definitely rather avoid all that.

author: rhodges
author_rank: Frequent Contributor
timestamp: January 09, 2020, 06:07:06 pm
content: I just checked some of my STM8 code, and verified that const does get into flash with the program code. Here is an example from the C source, the listing, and map files.C source:Code:static const char kb_default[] = "0123456789ABCDEF";listing "lst" file:Code:1036 .area CODE1037 .area CONST000000 1038 _kb_default:000000 30 31 32 33 34 35 36 1039 .ascii "0123456789ABCDEF"37 38 39 41 42 43 4445 46000010 00 1040 .db 0x00In the "map" file you can see it's in main flash:Code:00008A12 _tm1638_kmap lib_tm163800008B12 _kb_default lib_tm163800008B23 _segs_1638_digits lib_tm1638You can find my STM8 libraries, test code, and projects here:https://github.com/unfrozenFeel free to ask if you have questions!

author: HwAoRrDk
author_rank: Super Contributor
timestamp: January 09, 2020, 06:32:19 pm
content: Okay, so I'm right in thinking I don't need to do anything special? That's nice and convenient.Even better, I just noticed that even string literals appear to be placed in to flash. A format string (from aprintf()call inmain()) appears to be present in flash immediately before my BRR constants array! I did nothing other than supply the string literal as a direct argument to the function, and it has picked it up.Thanks for the link to your libraries.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: January 09, 2020, 06:38:12 pm
content: Hah, your libraries have already proved useful! I was just looking at the UART library and noticed I was not writing to the BRR registers in the correct order.The reference manual does indeed say that BRR2 should be written first. Don't know why I missed that. Everything seemed to work fine for me even when writing BRR1 first, though...

author: ajb
author_rank: Super Contributor
timestamp: January 09, 2020, 11:44:52 pm
content: I'm not sure about SDCC, but some compilers allow you to specify memory sections for objects. The compiler should be smart enough to make this unnecessary for constants that simply need to go somewhere in flash, but there are many cases (mostly on more sophisticated platforms than STM8) where you want to be more specific. For instance, maybe you care about which page of flash the data goes into for some reason, or you need to exclude certain data from cache, or put it into a tightly coupled memory section, or you want to preserve data across a reset (like passing commands to a bootloader).In GCC, this would be done using the section attribute:Code:__attribute__((section(".somelabel"))) const char[] label = "blahblahblah";The "somelabel" would need to match a labelled section in the linker file. In the linker file you can also specify the region the section goes into as well as any necessary attributes for the section.

author: mikerj
author_rank: Super Contributor
timestamp: January 10, 2020, 11:58:24 am
content: Quote from: HwAoRrDk on January 09, 2020, 06:32:19 pmPROGMEM was just a GCC hack to work around the separate data/program memory spaces of the AVR. Most other compilers in common use for Harvard architecture micros put const objects in program memory if possible.