2013-03-19 1 views
4

Я использую 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 нагрузки с заданным значением линкера, который в обоих случаях излишним. Если они пострадали от этого странного поведения, они бы этого не заметили.

+0

В случае, если не вектор сброса в 'точки g_pfnVectors' в' 08000960', не '08000961'? –

+0

От _Определенное руководство к ARM Cortex-M3, Joseph Yiu_, 3.7 Сброс последовательности: «Сброс вектора (начальный адрес выполнения программы, LSB должен быть установлен в 1 для указания состояния Thumb)». Что говорит о том, что 8000961 на самом деле является адресом 08000960. – BlueSky

+0

Это имеет смысл. Не вижу ничего явно неправильного, возможно, это странное взаимодействие с вашим отладчиком. –

ответ

3

Звучит как ошибка в вашем отладчике. Вероятно, он устанавливает точку останова в первой команде и либо полностью ее пропускает, либо каким-то образом переустанавливает ее, работает неправильно. Проблема может быть осложнена тем фактом, что вектор сбрасывает, возможно, просто невозможно надежно остановиться при первой инструкции. Поскольку помощь NOPs, я бы рекомендовал оставить их на месте, пока вы разрабатываете свою программу.

Однако есть альтернативное решение. Поскольку маловероятно, что вам нужно будет изменить массив, вам это действительно не нужно в разделе для записи. Для того, чтобы компилятор поместить массив в вспышки, как правило, это достаточно, чтобы объявить его как сопзЬ:

GPIO_TypeDef* const GPIO_PORT[LEDn] = {LED3_GPIO_PORT, LED4_GPIO_PORT}; 
+0

Да, я оставил там NOP. Во всяком случае, это всего лишь пример проекта, который я взял из пакета freeRTOS. Я не являюсь автором кода, но я согласен с вами в том, что там нужен 'const'. Благодарю. – BlueSky

1

Ничто не скачет сразу, что может быть неправильным. Во-первых, как вы отлаживаете этот код? Вы присоединяете отладчик, а затем отправляете перезагрузку процессора через JTAG?Я бы постарался поставить b Reset_Handler там сразу после вашего лейбла Reset_Handler: в качестве вашей первой инструкции, включить его, включить панель, а затем подключить JTAG, чтобы вы могли свести к минимуму любую возможную странность от отладчика. Затем установите для ПК команду mov и посмотрите, работает ли она. Является ли загрузчик или загрузочный диск, запускающий этот код? Это может быть что-то странное с инструкцией или кешем данных.

+0

Я использую сервер texane gdb (usb to swd) для загрузки и отладки изображения. Когда я выполняю «b ResetHandler», ПК уже указывает на «8000962», поэтому первая инструкция сразу же пропустит. – BlueSky