HardFault при запуске кода из оперативной памяти в CortexM0 - PullRequest
5 голосов
/ 29 мая 2019

В настоящее время я разрабатываю прошивку для микроконтроллера Arm Cortex-M0 +, и я столкнулся с довольно интересной проблемой.Я не ищу никаких ответов, а хотел бы поделиться этой проблемой с другими разработчиками, чтобы я мог (надеюсь) пролить свет на проблему, с которой я столкнулся.Я опишу это ниже:

У меня есть программа, которая динамически загружает (должным образом скомпилированный и связанный) код из внешнего Flash-чипа, который будет выполняться прямо из ОЗУ MCU.Интересно, что я могу прекрасно выполнить загруженный в ОЗУ код при пошаговом выполнении (через отладчик), но он всегда будет аварийно завершать работу [формально HardFault] при свободном запуске.Я пытался отключить все прерывания, я дважды проверил инструкции, адреса памяти, выравнивания байтов, все, но я все еще не могу определить причину исключения.

У некоторых из вас есть какой-нибудь намек на то, чтомогло случиться?Мне очень интересно узнать больше о вашем опыте!Спасибо,

Обновление 1 (30/05)

Свободный запуск в этом случае означает, что установка точки останова непосредственно перед переходом к ОЗУ невозможна,Всякий раз, когда я захожу в ветку и выполняю инструкции в оперативной памяти, она будет работать правильно и возвращаться.Везде, где нет точки останова (и, таким образом, MCU выполняет масштабирование с переходом), наблюдается HardFault.Обратите внимание, что он будет зависать даже при загрузке с включенным отладчиком, но без установленной точки останова.

Обновление 2 (30/05)

Я использую Cypress S6E1C3 Серия Arm Cortex M0 + FM0 + Микроконтроллер .

Обновление 3 (30/05)

После копания и игры с кодом, яможет заставить его работать правильно!Однако это вызвало больше вопросов, чем ответов для меняЧитая официальную документацию ARM об инструкции BLX ( BLX ), я обнаружил, что младший бит адреса ветвления определяет режим команды процессора (1 заставляет его работать в режиме большого пальца).Явно установив этот бит, заставляет код работать всегда, даже в режиме свободного запуска .Дело в том, что код в ОЗУ не был скомпилирован в режиме Thumb, и нет очевидной причины, по которой при пошаговом выполнении кода с помощью отладчика режим команд может измениться ...Есть идеи?

К.

Ответы [ 2 ]

2 голосов
/ 31 мая 2019

Проблема была в адресе филиала (как правильно указано @PeterCordes).Переход к ОЗУ выполнялся с помощью следующего кода (слегка скорректированного для этой аудитории):

// Prepare address and Function Pointer
uint32_t codeBufferAddress = reinterpret_cast<uint32_t>(&buffer) + offset;
void(*methodFromRAM)(void*) = reinterpret_cast<void(*)(void*)>(codeBufferAddress | 0x01);

// Branch to RAM
// thisPointer holds an object byte-stream...
(*methodFromRAM)(reinterpret_cast<void*>(thisPointer));

Обратите внимание, что в строке 3 codeBufferAddress указано or 0x01 (codeBufferAddress | 0x01), котороегарантирует, что ветвь будет принята в режиме Thumb .К моменту публикации этого вопроса значение codeBufferAddress равнялось 0x20003E40, что явно не устанавливает LSBit и, следовательно, заставило бы MCU работать в режиме ARM .

* 1014.* Я думаю, что компилятор не сможет вывести и настроить режим ветвления, потому что адрес динамически генерируется (хотя я думаю, что он может быть немного умнее и заставить все ветви работать в Режим Thumb , так как мой MCU может декодировать только Thumb).

В любом случае, при работе в пошаговом режиме я не мог наблюдать никаких изменений в целевом адресе, и пока я могу толькодумаю, это заставляет MCU работать в режиме Thumb Mode ... но это только предположение.Есть идеи?

К.

1 голос
/ 30 мая 2019

только Cortex-M поддерживает режим Thumb, а не режим ARM , поэтому сообщение вашего компилятора компилятору для Cortex-M0 + гарантирует, что он создаст код Thumb2.

Вот почему вам нужно установить младший бит целевого адреса.

https://en.wikipedia.org/wiki/ARM_Cortex-M#Instruction_sets

В архитектурах Cortex-M поддерживаются только наборы команд Thumb-1 и Thumb-2;устаревший 32-битный набор команд ARM не поддерживается.

Если вы действительно посмотрите на байты кода в памяти, вы увидите, что это инструкции Thumb2.

Единственный вопрос - как вашему отладчику удалось заставить не неисправность. Возможно, он все равно должен специально обрабатывать BLX и не эмулировать отказ-если-переключение на ARM-режим на поведении микроархитектуры только для большого пальца.Или, может быть, простое обращение с одношаговым прерыванием в итоге приводит к правильному возвращению в режиме Thumb.


"legacy" - это немного завышение для режима ARM в целом, я думаю;Я думал, что высокопроизводительные чипы ARM (с большими кэшами команд) могут по-прежнему выигрывать от режима ARM, который делает больше с меньшим количеством инструкций и более легким доступом к большему количеству регистров.Во всяком случае, это просто формулировка Википедии.

...