Этот пример для STM32F051 MCU:
Очень простое приложение, как "Блинки" (без задержек):
// define used registers
#define RCC_AHB1 *(volatile unsigned int *)(0x40021014)
#define GPIOC_MODER *(volatile unsigned int *)(0x48000800)
#define GPIOC_BSRR *(volatile unsigned int *)(0x48000818)
// main program
void mainApp() {
RCC_AHB1 = 1 << 19; // enable clock for GPIOC
GPIOC_MODER = 1 << (9 * 2); // set output on GPIOC.P9
while (1) {
GPIOC_BSRR = 1 << 9; // set output on GPIOC.P9
GPIOC_BSRR = 1 << (9 + 16); // clear output on GPIOC.P9
}
}
// variables for testing memory initialisation
int x = 10;
int y = 0;
int z;
Здесь также очень простой файл запуска написан на C (также будет работать в C++), которые запускают приложение mainApp
и инициализируют статические переменные .data
, инициализированные из ROM и .bss
, установлены только на ноль, есть переменные, инициализированные нулем и неинициализированные переменные.
extern void mainApp();
// external variables defined in linker script
// address in FLASH where are stored initial data for .data section
extern unsigned int _data_load;
// defines start and end of .data section in RAM
extern unsigned int _data_start;
extern unsigned int _data_end;
// defines start and end of .bss section in RAM
extern unsigned int _bss_start;
extern unsigned int _bss_end;
void resetHandler() {
unsigned int *src, *dst;
// copy .data area
src = &_data_load;
dst = &_data_start;
while (dst < &_data_end) {
*dst++ = *src++;
}
// clear .bss area
dst = &_bss_start;
while (dst < &_bss_end) {
*dst++ = 0;
}
mainApp();
while(1);
}
// _stacktop is defined in linker script
extern unsigned int _stacktop;
// vector table, will be placed on begin of FLASH memory, is defined in linker script
// only reset vector defined, need add other used vectors (especially NMI)
__attribute__((section(".vectors"), used)) void *isr_vectors[] = {
&_stacktop, // first vector is not vector but initial stack position
(void *)resetHandler, // vector which is called after MCU start
};
И, наконец компоновщик скрипт, который определяет расположение и размеры памяти, секции для вектора, программы (текст), данные (.data и.ПБС) а stacktop
MEMORY {
FLASH(rx) : ORIGIN = 0x08000000, LENGTH = 64K
SRAM(rwx) : ORIGIN = 0x20000000, LENGTH = 8K
}
SECTIONS {
. = ORIGIN(FLASH);
.text : {
*(.vectors)
*(.text)
} >FLASH
. = ORIGIN(SRAM);
.data ALIGN(4) : {
_data_start = .;
*(.data)
. = ALIGN(4);
_data_end = .;
} >SRAM AT >FLASH
.bss ALIGN(4) (NOLOAD) : {
_bss_start = .;
*(.bss)
. = ALIGN(4);
_bss_end = .;
} >SRAM
_stacktop = ORIGIN(SRAM) + LENGTH(SRAM);
_data_load = LOADADDR(.data);
}
Построить это с этими командами (построить и ссылку на один раз):
$ arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -nostartfiles main.c startup.c -T stm32f051x8.ld -o main.elf
В таблице символов можно увидеть, где хранятся данные:
$ arm-none-eabi-nm -C -l -n -S main.elf
08000000 00000008 T isr_vectors
08000008 00000034 T mainApp
0800003c 0000005c T resetHandler
08000098 A _data_load
20000000 D _data_start
20000000 00000004 D x
20000004 D _data_end
20000004 B _bss_start
20000004 00000004 B y
20000008 B _bss_end
20000008 00000004 B z
20002000 A _stacktop
Также вы можете ознакомиться с перечнем:
arm-none-eabi-objdump -S main.elf
Необработанные двоичные файлы:
arm-none-eabi-objcopy -O binary main.elf main.bin
Какая цепь инструментов вы используете (GNU, я полагаю?). Какую часть ARM вы используете (или, возможно, укажите доску)? Является ли ОЗУ встроенной или внешней? Будет ли код работать с ПЗУ или ОЗУ? Ответ на эти вопросы даст вам лучший ответ. Но, по крайней мере, теперь я могу сказать вам, что objcopy - это именно то, как вы генерируете необработанный двоичный файл (или шестнадцатеричный файл, если на то пошло); как правило, в вашем make-файле, или шаг после сборки в вашей среде IDE. – Clifford
GNU toolchain, встроенная оперативная память, код будет выполнен с ROM. –
Для мигания, если вы не используете статические переменные (только стек), вам не нужно копировать данные из FLASH в SRAM. – vlk