Разбираемся как устроена память микроконтроллера на примере STM32F205VGT6.
Так же мы используем CubeMX для подготовки проекта.
Где хранятся данные , где стек, где код программы?
Генерим сначала пустой проект, оставляем только пустой main().
читаем ld файл
Linker script for STM32F205VG Device with ** 1024KByte FLASH, 128KByte RAM.
ld файл это основа, здесь CubeMx прописывает все исходные параметры памяти, стека, кода. Именно его надо спокойно/внимательно изучить, здесь все очевидно на самом деле.
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
}
Стек в микроконтроллерах на ядрах ARM растёт сверху вниз.
в ld файле:
_estack = 0x20020000; /* end of RAM */ // 0x20000=131072
RAM по даташиту Up to 128 4 Kbytes of SRAM. То есть есть еще какие-то 4Kb SRAM в конце...
Стек располагается отдельно от остальных блоков памяти, в конце ОЗУ. Конец ОЗУ по мнению CubeMX это 0x20020000=..131072 примерно (128 4Kb).
Для контроля минимальных запасов стека и кучи в CubeMX есть такие установки
в ld файле:
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
(_user_heap_stack = _Min_Heap_Size _Min_Stack_Size )
list полезный по информации файл на выходе сборки
.text — /* The program code and other data goes into FLASH */ , это скомпилированный машинный код - помещается во FLASH;
.data — /* Initialized data sections goes into RAM, load LMA copy after code */ - Переменные, это помещается в RAM; и зачем-то копия помещается еще во FLASH.
.rodata — /* Constant data goes into FLASH */ - аналог .data для неизменяемых данных, но помещается во FLASH;
.bss — /* Uninitialized data section */ , глобальные и статические переменные, которые при старте содержат нулевое значение - помещаются в RAM.
Момент истины
FLASH может содержать только неизменяемые данные , т.е. их нельзя в процессе исполнения перезаписать. (FLASH (rx) ) rx = read execute . Отсюда и идет весь этот винигред.
Sections:
Idx Name Size VMA LMA File off Algn
0 .isr_vector 00000184 08000000 08000000 00010000 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .text 0000015c 08000184 08000184 00010184 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .rodata 00000000 080002e0 080002e8 000102e8 2**0
CONTENTS, ALLOC, LOAD, DATA
3 .init_array 00000004 080002e0 080002e0 000102e0 2**2
CONTENTS, ALLOC, LOAD, DATA
4 .fini_array 00000004 080002e4 080002e4 000102e4 2**2
CONTENTS, ALLOC, LOAD, DATA
5 .data 00000000 20000000 20000000 000102e8 2**0
CONTENTS, ALLOC, LOAD, DATA
6 .bss 00000020 20000000 080002e8 00020000 2**2
ALLOC
7 ._user_heap_stack 00000600 20000020 080002e8 00020020 2**0
ALLOC
ld файл прописывает где и куда какие данные сохранить
Все очевидно :
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
>RAM - это помещается в RAM !
И так далее...
файл startup_stm32f205xx.s
Этот файл генерируется CubeMX. Он на ассемблере.
Смысл его в том, чтобы начать выполнение программы: для этого надо сначала установить указатель стека на начало стека :
Reset_Handler:
ldr sp, =_estack /* set stack pointer */
Теперь для закрепления понимания поэкспериментируем
добавим массив :
char buf[10000];
main()
{..
эффекта изменения распределения памяти не произойдет
сделаем так : char buf[10000]={0}; - ничего не меняется
теперь в main сделаем так :
for(int i=0; i < sizeof(buf); i )
buf[i]=1;
и .bss увеличивается с 00000020 до 00002730 (10032!) . То есть ушло в RAM!
теперь делаем так :
const char buf[10000]={0};
main
{
char ch=0;
for(int i=0; i < sizeof(buf); i )
char ch=buf[i];
printf("%c",ch);
И .rodata увеличивается с 10 до 00002784 (10116) ! То есть ушло во FLASH (кстати только при условии явной инициализации={0}).
Все логично !
Выводы такие :
Побольше const
Если RAM памяти не хватает или не хватает стека (он всегда есть часть RAM), то можно попробовать все что не меняется обозвать const , инициализировать обязательно и тогда это попадет не в RAM , а в FLASH.
section `._user_heap_stack' will not fit in region `RAM'
Вот такая бяка появляется, когда RAM не хватает, например добавили нового кода , сторонние библиотеки ....
У меня (на самом деле) эта ошибки ушла после удаления файла startupxxx.s и перегенерации заново проекта(и файла startup) из CubeMx.
Файлы для скачивания
*
пустышка для изучения распределения памяти в контроллере STM32