[Пример загрузчика]
Готовый пример загрузчика, который загружает образ программы пользователя через сеть Ethernet по протоколу TFTP или HTTP, можно найти в проекте LwIP_IAP из пакета библиотек STM32Cube (см. папку Projects\STM324x9I_EVAL\Applications\LwIP).
Идея загрузчика состоит в том, что загрузчик находится в младших адресах Flash (с адреса 0x08000000), и он первым получает управление при включении питания/сбросе. Программа пользователя находится дальше в памяти, в других секторах Flash (например с адреса 0x08020000).
Итак, при включении питания всегда запускается загрузчик. В этот момент код принимает решение - должен ли оставаться активным загрузчик (чтобы иметь возможность переписать основную программу), или же нужно передать управление в основную программу. Обычно это делается по так называемому условию загрузки - например, нажата ли при включении питания какая-нибудь кнопка.
[Как изменить адрес старта загружаемого приложения]
Чтобы и загрузчик, и программа пользователя находились в памяти Flash одновременно, их необходимо разнести в памяти по отдельным секторам Flash. В примере, приведенном здесь, загрузчик находится начиная с сектора 0 и может занимать секторы 0, 1, 2, 3 и 4 (адресное пространство 0x08000000 - 0x0801FFFF, размер 128 кбайт). Вся остальная память Flash, начиная с сектора 5 (сектора 5 .. 23, адресное пространство 0x08020000 - 0x081FFFFF, размер 1966080 байт), может быть использована под код пользователя.
Таблица 6. Модуль Flash - организация 2 мегабайта dual bank organization (STM32F42xxx и STM32F43xxx).
Блок |
Банк |
Сектор |
Адреса в памяти |
Размер, кбайт |
Основная память |
Bank 1 |
0 |
0x08000000 - 0x08003FFF |
16 |
1 |
0x08004000 - 0x08007FFF |
16 |
2 |
0x08008000 - 0x0800BFFF |
16 |
3 |
0x0800C000 - 0x0800FFFF |
16 |
4 |
0x08010000 - 0x0801FFFF |
64 |
5 |
0x08020000 - 0x0803FFFF |
128 |
6 |
0x08040000 - 0x0805FFFF |
128 |
.. |
.. |
.. |
11 |
0x080E0000 - 0x080FFFFF |
128 |
Bank 2 |
12 |
0x08100000 - 0x08103FFF |
16 |
13 |
0x08104000 - 0x08107FFF |
16 |
14 |
0x08108000 - 0x0810BFFF |
16 |
15 |
0x0810C000 - 0x0810FFFF |
16 |
16 |
0x08110000 - 0x0811FFFF |
64 |
17 |
0x08120000 - 0x0813FFFF |
128 |
18 |
0x08140000 - 0x0815FFFF |
128 |
.. |
.. |
.. |
23 |
0x081E0000 - 0x081FFFFF |
128 |
Системная память |
0x1FFF0000 - 0x1FFF77FF |
30 |
OTP [3] |
0x1FFF7800 - 0x1FFF7A0F |
528 байт |
Байты опций [3] |
Bank 1 |
|
0x1FFFC000 - 0x1FFFC00F |
16 байт |
Bank 2 |
|
0x1FFEC000 - 0x1FFEC00F |
16 байт |
Чтобы приложение пользователя могло находиться начиная с адреса 0x08020000, необходимо внести некоторые изменение в проект приложения. Процесс по шагам:
1. Откройте в текстовом редакторе файл конфигурации линкера *.icf, и внесите в него следующие изменения (помечено красным цветом):
/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x08020000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x08020000;
define symbol __ICFEDIT_region_ROM_end__ = 0x081FFFFF;
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__ = 0x2002FFFF;
define symbol __ICFEDIT_region_CCMRAM_start__ = 0x10000000;
define symbol __ICFEDIT_region_CCMRAM_end__ = 0x1000FFFF;
define symbol __ICFEDIT_region_SDRAM_start__ = 0xC0000000;
define symbol __ICFEDIT_region_SDRAM_end__ = 0xC1FFFFFF;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__ = 0x400;
define symbol __ICFEDIT_size_heap__ = 0x200;
/**** End of ICF editor section. ###ICF###*/
define memory mem with size = 4G;
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
define region SDRAM_region = mem:[from __ICFEDIT_region_SDRAM_start__ to __ICFEDIT_region_SDRAM_end__];
define region CCMRAM_region = mem:[from __ICFEDIT_region_CCMRAM_start__ to __ICFEDIT_region_CCMRAM_end__];
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
initialize by copy { readwrite };
do not initialize { section .noinit };
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
place in ROM_region { readonly };
place in RAM_region { readwrite,
block CSTACK, block HEAP };
place in SDRAM_region { section SDRAM_DATA };
2. Откройте в редакторе файл system_stm32f4xx.c, и внесите в функцию SystemInit следующие изменения (помечено красным цветом):
/** * @brief Setup the microcontroller system
* Initialize the FPU setting, vector table location and External memory
* configuration.
* @param None
* @retval None */
void SystemInit(void)
{
/* FPU settings ------------------------------------------------------------*/
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
#endif
/* Reset the RCC clock configuration to the default reset state ------------*/
/* Set HSION bit */
RCC->CR |= (uint32_t)0x00000001;
/* Reset CFGR register */
RCC->CFGR = 0x00000000;
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* Reset PLLCFGR register */
RCC->PLLCFGR = 0x24003010;
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
/* Disable all interrupts */
RCC->CIR = 0x00000000;
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
/* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
//SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
SCB->VTOR = FLASH_BASE
| 0x00020000
| VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
}