В вопросе прикладного программирования

Я работаю над проектом на STM32L152RCT6, где мне нужно создать механизм для самостоятельного обновления кода из вновь созданного файла (HEX-файл). Для этого я реализовал такой механизм, как загрузчик, где он проверяет наличие новой прошивки, если там он должен перепроверить, и если он найден действительным, он должен храниться в "Местоположении приложения".

Я делаю следующие шаги.

  1. Адрес загрузчика = 0x08000000
  2. Адрес приложения = 0x08008000
  3. Где-то в указанном месте он должен проверить наличие нового файла через программу Boot Loader.
  4. Если он признан действительным, он должен быть скопирован на весь HEX (согласно руководству).
  5. Чем запуск кода приложения через переход по этому месту.

Теперь проблема исходит от шага 5, все вышеперечисленные шаги, которые я сделал, даже хранение данных были выполнены правильно (проверьте в утилите STM32), но когда я перехожу к коду приложения, оно не будет работать.

Есть ли необходимость в перекрестной проверке или что-то, чего мне не хватает?

3 ответа

Решение

В отличие от других контроллеров ARM, которые при сбросе напрямую переходят к адресу 0, серия Cortex-M берет начальный адрес из таблицы векторов. Если программа загружается напрямую (без загрузчика), таблица векторов находится в начале двоичного файла (загружается или отображается на адрес 0). Первая запись со смещением 0 является начальным значением указателя стека, вторая запись по адресу 4 называется вектором сброса, она содержит адрес первой команды, которая должна быть выполнена.

Программы, загруженные с помощью загрузчика, обычно сохраняют это расположение и помещают векторную таблицу в начало двоичного файла, 0x08008000 в твоем случае. Тогда вектор сброса будет 0x08008004, Но это ваше приложение, вы должны проверить, куда вы положили таблицу векторов. Подсказка: посмотрите на .map файл, сгенерированный компоновщиком, чтобы быть уверенным. Если это действительно в 0x08008000, затем вы можете перенести управление в вектор сброса приложения так:

void (*app)(void);                   // declare a pointer to a function
app = *(void (**)(void))0x08008004;  // see below
app();                               // invoke the function through the pointer

Сложное приведение во второй строке преобразует физический адрес в указатель на указатель на функцию, принимает указанное значение, которое теперь является указателем на функцию, и присваивает его app,

Затем вы должны управлять переключением на векторную таблицу приложения. Вы можете сделать это либо в загрузчике, либо в приложении, или разделить шаги между ними.

  • Отключите все прерывания и остановите SysTick. Обратите внимание, что SysTick не является прерыванием, не вызывайте NVIC_DisableIRQ() в теме. Я бы сделал этот шаг в загрузчике, чтобы он отвечал за отключение того, что он включил.
  • Присвойте новый адрес таблицы векторов SCB->VTOR, Остерегайтесь, что шаблон SystemInit() функция в system_stm32l1xx.c безусловно изменения SCB->VTOR вернуться к началу вспышки, т.е. 0x08000000, вы должны отредактировать его, чтобы использовать правильное смещение.

Вы также можете загрузить значение указателя стека из таблицы векторов, но это сложно сделать правильно, и в этом нет необходимости, приложение может просто продолжать использовать стек, который был настроен в загрузчике. Просто проверьте, чтобы убедиться, что это разумно.

Вы изменили приложение в соответствии с новой позицией фальши?

Например, Векторная таблица должна быть правильно настроена через

SCB->VTOR = ...

Когда ваш загрузчик запускает приложение, оно должно настроить все обратно на состояние сброса, поскольку приложение может перевести значения сброса по умолчанию. Особенно вам нужно:

  1. Возврат значений всех аппаратных регистров к значениям сброса
  2. Выключите все периферийные часы (не забывайте о SysTick)
  3. Отключить все разрешенные прерывания
  4. Возврат всех часовых доменов к значениям сброса.
  5. Установить адрес таблицы векторов
  6. Загрузите указатель стека с начала таблицы векторов APP.
  7. Позвоните в точку входа APP (начало таблицы vertor + 4).

Ваше приложение должно быть скомпилировано и связано с использованием пользовательского сценария компоновщика, где начальная точка FLASH равна 0x8008000.

например:

FLASH (rx) : ORIGIN = 0x8000000 + 32K, LENGTH = 512K - 32K

SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;

где значение FLASH_BASE должно быть равно адресу значения IROM в KEIL

пример:

#define FLASH_BASE      0x08004000

Конфигурация Keil

Другие вопросы по тегам