Я использую Keil µVision для встроенного проекта, который возвращается к загрузчику для обновления.Ранее Keil использовал ARMCC в качестве компилятора, и следующий код работал нормально.
void run_bootloader(void)
{
uint32_t runBootloaderAddress;
// Read the entry point from bootloader's vector table
runBootloaderAddress = *(uint32_t*)(0x00000004);
void (*runBootloader)(void) = (void (*) (void))runBootloaderAddress;
runBootloader();
}
Keil переключается на Clang в их более новых версиях, и я пытаюсь перенести код поверх.Этот код теперь вызывает сброс при вызове runBootloader()
.
Сгенерированная сборка, конечно, отличается.Поэтому я вытащил сгенерированную сборку ARMCC из списка и записал ее как встроенный ассемблер.
void run_bootloader(void)
{
__asm("PUSH {r4-r6,lr}");
__asm("MOVS r0,#0");
__asm("LDR r4,[r0,#4]");
__asm("MOV r5,r4");
__asm("BLX r5");
__asm("POP {r4-r6,pc}");
}
Пошагово, значения в регистрах, похоже, меняются так же, как и раньше.Но версия ARMCC переходит на загрузчик на BLX
, а версия Clang сбрасывается.Адрес, извлеченный из таблицы векторов, в обоих случаях одинаков.
Я видел упоминания о том, что Clang не допускает такого рода вещей, как комментарий к этому ответу .Но должен быть способ вернуться к загрузчику.Что мне не хватает?Есть ли какие-либо настройки в компоновщике, которые мне нужно включить, чтобы разрешить такое поведение?
Обновление
Некоторые комментарии приводят меня к поиску лучшего способа сброса, который приводит меня к эта статья , в которой обсуждается сброс процессора путем записи в бит SYSTEMRESETREQ
регистра управления прерываниями и сбросом приложения (AIRCR
).Что привело меня к поиску этой функции в заголовочном файле CMSIS.Я унаследовал код, я не знаю, почему он не использовался.
/**
\brief System Reset
\details Initiates a system reset request to reset the MCU.
*/
__STATIC_INLINE void __NVIC_SystemReset(void)
{
__DSB(); /* Ensure all outstanding memory accesses included
buffered write are completed before reset */
SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */
__DSB(); /* Ensure completion of memory access */
for(;;) /* wait until reset */
{
__NOP();
}
}
Однако приложение по-прежнему перезагружается без запуска загрузчика.
Дополнительная информация
Загрузчик и приложение - это отдельные проекты.Приложение работает под управлением ОС Keil RTX со слоем CMSIS.Я думаю, что приложение работает в собственном адресном пространстве и не знает о загрузчике.Поэтому, когда он сбрасывается, он сбрасывается только в пределах своего собственного адресного пространства, и загрузчик никогда не запускается.
Я попытался сообщить приложению о загрузчике, добавив это в мой файл разброса.
LR_IROM0 0x00 0x00012000 {
ER_IROM0 0x0 0x00012000 {
.ANY (+RO)
}
}
Но результаты совпадают.
Чтобы уточнить, я действительно пытаюсь перезагрузить процессор.Я пытаюсь перейти к загрузчику, сообщая ему, что это не обычная загрузка, а скорее обновление.
Версии набора инструментов
PS C:\Keil_v5\ARM\ARMCC\bin> .\armcc.exe --version_number
5060750
PS C:\Keil_v5\ARM\ARMCLANG\bin> .\armclang.exe --version
Product: MDK Plus 5.25 (Flex)
Component: ARM Compiler 6.9
Tool: armclang [5ced1d00]
Target: unspecified-arm-none-unspecified
Генерируемая сборка
C Код:
void run_bootloader(void)
{
volatile uint32_t runBootloaderAddress;
// Read the entry point from bootloader's vector table
runBootloaderAddress = *(uint32_t*)(0x00000004);
void (*runBootloader)(void) = (void (*) (void))runBootloaderAddress;
runBootloader();
}
ARMCC:
AREA ||i.run_bootloader||, CODE, READONLY, ALIGN=1
run_bootloader PROC
;;;1335 }
;;;1336 void run_bootloader(void)
000000 b570 PUSH {r4-r6,lr}
;;;1337 {
;;;1338 uint32_t runBootloaderAddress;
;;;1339
;;;1340 // Read the entry point from bootloader's vector table
;;;1341 runBootloaderAddress = *(uint32_t*)(0x00000004);
000002 2000 MOVS r0,#0
000004 6844 LDR r4,[r0,#4]
;;;1342 void (*runBootloader)(void) = (void (*) (void))runBootloaderAddress;
000006 4625 MOV r5,r4
;;;1343 runBootloader();
000008 47a8 BLX r5
;;;1344 }
00000a bd70 POP {r4-r6,pc}
;;;1345
ENDP
Звон:
.section .text.run_bootloader,"ax",%progbits
.hidden run_bootloader @ -- Begin function run_bootloader
.globl run_bootloader
.p2align 2
.type run_bootloader,%function
.code 16 @ @run_bootloader
.thumb_func
run_bootloader:
.Lfunc_begin2:
.loc 2 1338 0 @ ../_Primary/source/can_tools.c:1338:0
.fnstart
.cfi_startproc
@ BB#0:
.save {r7, lr}
push {r7, lr}
.Lcfi8:
.cfi_def_cfa_offset 8
.Lcfi9:
.cfi_offset lr, -4
.Lcfi10:
.cfi_offset r7, -8
.pad #8
sub sp, #8
.Lcfi11:
.cfi_def_cfa_offset 16
.Ltmp8:
.loc 2 1343 28 prologue_end @ ../_Primary/source/can_tools.c:1343:28
movs r0, #4
ldr r0, [r0]
.loc 2 1343 26 is_stmt 0 @ ../_Primary/source/can_tools.c:1343:26
str r0, [sp, #4]
.loc 2 1344 52 is_stmt 1 @ ../_Primary/source/can_tools.c:1344:52
ldr r0, [sp, #4]
.loc 2 1344 12 is_stmt 0 @ ../_Primary/source/can_tools.c:1344:12
str r0, [sp]
.loc 2 1345 5 is_stmt 1 @ ../_Primary/source/can_tools.c:1345:5
ldr r0, [sp]
blx r0
.loc 2 1346 1 @ ../_Primary/source/can_tools.c:1346:1
add sp, #8
pop {r7, pc}
.Ltmp9:
.Lfunc_end2:
.size run_bootloader, .Lfunc_end2-run_bootloader
.cfi_endproc
.cantunwind
.fnend
@ -- End function