Linker scripts for STM32F429, STM32F427
С точки зрения программирования внутреняя память микроконтроллера stm32f429 состоит из шести областей, у каждой из которых есть уникальные свойства (см. Memory mapping, DM00071990.pdf, STM32F427xx and STM32F429xx datasheet, p.84):
-- флеш-память (Flash memory), содержимое которой не изменяется во время работы программы;
-- CCM data RAM (64 KB data SRAM), с которой может работать только ядро (см. Figure 5. STM32F427xx and STM32F429xx Multi-AHB matrix, p.21 там же);
-- SRAM1, с которой ядро может работать используя шину данных; эту область памяти руководства рекомендуют отображать в нулевые адреса (см. 2.3.1 Embedded SRAM, DM00031020.pdf, RM0090 Reference manual, p.68);
-- SRAM2 и SRAM3, для доступа к которым ядро может использовать только системную шину;
-- Backup SRAM, питание которой может осуществляться от внешней батарейки.
Кроме того к микроконтроллеру может подключаться несколько микросхем внешней памяти (каждая также со своими уникальными свойствами).
При программировании необходимо учитывать наличие и свойства этих областей памяти, для примера: буфера для перефрийных устройств при использовании модулей DMA не могут располагаться в памяти CCMRAM; буфера устройств активно использующих память имеет смысл разнести по разным областям памяти, в этом случае будет обеспечена их параллельная бесконфликтная работа.
С другой стороны, компилятор GCC разделяет единое адресное пространство памяти на четыре следующих сегмента:
-- сегмент кода .text;
-- сегмент инициализированных данных .data;
-- сегмент неинициализированных данных .bss;
-- сегмент данных только для чтения .rodata (в этот сегмент попадают данные используемые для инициализации переменных с областью размещения auto).
Размещением указанных сегментов по конкретным адресам в памяти микроконтроллера занимается линковщик (программа ld). Это размещение выполняется в соответствии со скриптами (программами) линковки.
Стандартные скрипты линковки крайне просты и не учитывают всего многообразия видов памяти микроконтроллеров. Поэтому были написаны специализированные скрипты линковки и соответствующим образом изменена процедура инициализации памяти микроконтроллера.
Скрипт линковки разделён на два файла:
-- ldscripts/mem.ld (или fast-mem.ld), в котором описывается конфигурация памяти микроконтроллера;
-- ldscripts/sections.ld, в котором указано размещение стандартных и специализированных сегментов программы по областям памяти микроконтроллера.
В качестве основной памяти для переменных используется область памяти CCMRAM, стек располагается также в памяти CCMRAM.
Размещение области динамически распределяемой памяти (кучи) может быть задано индивидуально с помощью определения REGION_HEAP в файле mem.ld (fast-mem.ld); сейчас эта область размещается в основной памяти (REGION_HEAP совпадает с CCMRAM).
Для указания в программе размещения переменных в определённых областях памяти предлагаются следующие макросы (см.файл sections.h):
RO_DATA размещение переменной во флеш-памяти; NOINIT размещение неинициализированной переменной в обычной памяти (REGION_DATA, размещение задаётся в скрипте линковки); BACKUP_NOINIT размещение неинициализированной переменной в памяти Backup SRAM; EXTMEM_NOINIT размещение неинициализированной переменной во внешней памяти; BIT_BAND_DATA размещение инициализированной битовой переменной; BIT_BAND_BSS размещение битовой переменной с начальным значением 0; BIT_BAND_NOINIT размещение неинициализированной битовой переменной; CCMRAM_DATA размещение инициализированной переменной в памяти CCMRAM; CCMRAM_BSS размещение переменной с начальным значением 0 в памяти CCMRAM; CCMRAM_NOINIT размещение неинициализированной переменной в памяти CCMRAM.
Аналогично последним трём макросам определены макросы для резмещения переменных в областях памяти SRAM1, SRAM2 и SRAM3: SRAMx_DATA, SRAMx_BSS, SRAMx_NOINIT, где x может принимать значения 1, 2 или 3.
Общий формат использования макросов: MACRO_NAME( <type>, <var name> [,<init value>] ), где <type> -- тип переменной (например, short int); <var name> -- имя переменной; <init value> -- необязательное присвоение начального значения переменной (только для xxx_DATA).
Пример использования макросов:
#include "sections.h"
SRAM2_NOINIT( unsigned char, BigRingBuf[1024] ); CCMRAM_BSS( unsigned long int, FastCounter ); CCMRAM_DATA( unsigned long int, FastFlags, = 0x8008 ); RO_DATA( const unsigned char, HelloWorldText[], = "Hello World!" );
Процедура инициализации выполняет функции, ссылки на которые находятся в сегментах .preinit_array_sysinit, .preinit_array_platform и .preinit_array (см. файл sections.ld); затем обнуляет сегменты .bss, инициализирует (с помощью функции memcpy) данные в сегментах .data и выполняет функции, ссылки на которые находятся в сегменте .init_array. После этого управление передаётся в функцию main. После возврата из функции main выполняются функции, ссылки на которые находятся в сегменте .fini_array.
Код процедуры инициализации находится в файле startup.S.