Цитата(smk @ Nov 2 2014, 17:22)

Суть вопроса такова. Понадобился бутлоадер.
Многие ответили, но обще. Я приведу примеры и "трюки" из собственного загрузчика, тем более, что предпосылки STM32 и KEIL совпадают.
1. Загрузчик нужно располагать с начала флэша, тогда управление при старте передается сразу к нему.
2. С точки зрения создания и отладки загрузчик представляет собой обычную программу.
3. Пользовательская программа являет собой также обычную программу, которая, однако, располагается с некоего фиксированного адреса после загрузчика. С какого именно, станет ясно, когда размер загрузчика определится более-менее. Этот адрес следует знать затем и загрузчику, чтобы упростить ему задачу поиска приложения в памяти, хотя можно применить и другие методы поиска.
4. Для основной программы необходимо:
4.1. соответствующим образом настроить проект KEIL и, как это сделал я, создать свой файл скаттера для компоновщика, например, когда первые 16К для загрузчика зарезервированы:
CODE
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
;
; FlashSize = 0x00040000 (256K):
;
; Boot Loader 16K
;
;LR_IROM1 0x08000000 0x4000 {
; ER_IROM1 0x08000000 0x4000 {
; *.o (RESET, +First)
; }
;}
;
; Main Code from 16K
;
LR_IROM2 (0x08000000 + 0x4000) (0x40000-0x4000) { ; load region size_region
ER_IROM2 (0x08000000 + 0x4000) (0x40000-0x4000) { ; load address = execution address
*.o (USER_VECTORS, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x0000C000 { ; RW data
.ANY (+RW +ZI)
}
}
4.2. start-up код (файл *.s) следут модифицировать так, чтобы он сразу переназначал таблицу векторов пользовательской программы:
CODE
; Vector Table Mapped to Address 0 at Reset
; AREA RESET, DATA, READONLY, ALIGN=9 ; 2^9=512
;
;__Boot DCD __initial_sp ; Top of Stack
; DCD Reset_Handler ; Reset Handler
; Future user program vector table at 0x4000
AREA USER_VECTORS, DATA, READONLY, ALIGN=9 ; 2^9=512
EXPORT __Vectors
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
...
AREA |.text|, CODE, READONLY
VTOR EQU (0xE000E000 + 0x0D08)
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
MOV32 R1, #VTOR ; Load VTOR register address
LDR R0, =__Vectors ; Load user program vector table address
STR R0, [R1] ; Store to VTOR to relocate the vector table
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
4.3. Обратите внимание на закомментированные строки в начале скаттера (LR_IROM1) и start-up файла (AREA RESET). Они определяют вектор по адресу 0. Эти строки можно раскомментировать, чтобы отлаживать основную программу, пока загрузчик еще не готов или сам в память не загружен.
5. Для определения версии основной программы я использовал дату и время ее компиляции.
5.1. В любом месте кода можно разместить строки:
CODE
//------------------------------------------------------------------------------
//
// Compilation time stamp
//
const char _cd[] = __DATE__;
const char _ct[] = __TIME__;
Эти строки представляют собой генерируемые компилятором дату и время. Встроенные макросы __DATE__ и __TIME__ описаны в помощи KEIL.
5.2. В start-up файле можно поместить некоторый дескриптор со ссылками на эти строки:
CODE
IMPORT |Load$$LR$$LR_IROM2$$Length|
IMPORT _cd
IMPORT _ct
DCB "DSC="
DCD __Vectors ; load address
DCD |Load$$LR$$LR_IROM2$$Length|; Image length (.bin file length)
DCD _cd ; -> date stamp as Jan 01 2012
DCD _ct ; -> time as HH:MM:SS
Фактически, это есть некая структура, которую я располагаю между таблицей векторов и Reset_Handler. Эта структура содержит уникальную строку "DSC=", затем идет указатель на таблицу векторов (фактически те самые 0x4000), затем длина образа программы, после чего указатели на строки даты и времени компиляции. Для загрузчика эту структуру легко найти (уж точно в первых 512 байтах кода пользовательской программы) и почерпнуть оттуда версию и длину приложения.
6. Загрузчик передает управление приложению, загрузив SP из первого слова таблицы векторов, и переходом по адресу из второго слова. Следует помнить, что нужно предварительно остановить периферию, которую использовал загрузчик, и SysTick.
7. Мой загрузчик использует SD карту как источник обновления. При старте он ищет файл с образом приложения, сравнивает версии и, если необходимо, - обновляет приложение.
Сообщение отредактировал KnightIgor - Nov 2 2014, 20:36