Я использую Sourcery CodeBench Lite 2012.03-56 компилятор и комплект gdb с texane gdb server.Cortex m3 выполнение первой инструкции
Сегодня я хотел попробовать демонстрационный пример FreeRTOS для дешевой платы STM32VLDISCOVERY, я скопировал все исходные файлы, необходимые, скомпилированные без ошибок, но пример не сработал. Я активировал отладчик и заметил, что этот пример терпит неудачу, когда он пытается разыменовать указатель на регистры GPIO. Глобальная переменная массива, которая содержит указатели на регистры GPIO:
GPIO_TypeDef* GPIO_PORT[LEDn] = {LED3_GPIO_PORT, LED4_GPIO_PORT};
не был правильно инициализирован и заполнен некоторыми случайными значениями. Я проверил, что препроцессор определяет LED3_GPIO_PORT и LED3_GPIO_PORT, и они были действительны.
После некоторых исследований, где может возникнуть проблема, я посмотрел начальный файл, предоставленный для trueSTUDIO, найденный в CMSIS lib. Исходный файл startup_stm32f10x_md_vl.S:
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
...
Во время отладки я заметил, что регистр r1 никогда не инициализируется на нуль первой инструкции варисторов r1, # 0. Регистр r1 используется в качестве счетчика в цикле, поэтому, когда выполнение достигает цикла LoopCopyDataInit, он никогда не входит в цикл, так как регистр r1 загружается некоторыми данными мусора из предыдущего выполнения. В результате этого код запуска никогда не инициализирует раздел .data.
Когда я поместил два NOP инструкции перед варисторами r1, # 0 инструкции, то регистр r1 был инициализирована в 0, и пример начал работать:
Модифицированная часть startup_stm32f10x_md_vl.S файла:
/* Copy the data segment initializers from flash to SRAM */
nop
nop
movs r1, #0
b LoopCopyDataInit
Это демонтаж соответствующих частей конечного кода:
Disassembly of section .isr_vector:
08000000 <g_pfnVectors>:
8000000: 20002000 andcs r2, r0, r0
8000004: 08000961 stmdaeq r0, {r0, r5, r6, r8, fp}
...
Disassembly of section .text:
...
8000960 <Reset_Handler>:
8000960: 2100 movs r1, #0
8000962: f000 b804 b.w 800096e <LoopCopyDataInit>
08000966 <CopyDataInit>:
8000966: 4b0d ldr r3, [pc, #52] ; (800099c <LoopFillZerobss+0x16>)
8000968: 585b ldr r3, [r3, r1]
800096a: 5043 str r3, [r0, r1]
800096c: 3104 adds r1, #4
Как вы можете видеть ISR вектор TABL e правильно указывает на адрес Reset_Handler. Итак, что происходит? Почему первая инструкция movs r1, # 0 не была выполнена в оригинальном стартовом коде?
EDIT:
Исходный код работает, когда я снова отключить питание платы и включите его обратно. Я могу перезагрузить MCU несколько раз, и он работает. Когда я запускаю gdb-сервер, тогда код не работает, даже после сброса. Мне нужно снова активировать цикл, чтобы работать. Я предполагаю, что это какая-то отвратительная странность.
Примечание:
Я посмотрел, что код запуска и другие люди, использующие этот MCU и они либо отключить прерывания или регистр SP нагрузки с заданным значением линкера, который в обоих случаях излишним. Если они пострадали от этого странного поведения, они бы этого не заметили.
В случае, если не вектор сброса в 'точки g_pfnVectors' в' 08000960', не '08000961'? –
От _Определенное руководство к ARM Cortex-M3, Joseph Yiu_, 3.7 Сброс последовательности: «Сброс вектора (начальный адрес выполнения программы, LSB должен быть установлен в 1 для указания состояния Thumb)». Что говорит о том, что 8000961 на самом деле является адресом 08000960. – BlueSky
Это имеет смысл. Не вижу ничего явно неправильного, возможно, это странное взаимодействие с вашим отладчиком. –