Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: RL-ARM и bootloader
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
EXeGLuMATOR
Имеется следующий проектик, как водится, состоящий из двух частей. Бутлоадер и основная программа. Причем в основной программе также есть блок перепрошивки "самой себя".
Используется RL-ARM.
Вопрос в следующем - как после перпрошивки перезапустить проц? Собсно как перезапустить более или менее понятно. Проблема в том, что после перезапуска все уходит в HardFault при вызове os_sys_init().
Т.е. перешиваемся, рестартуем, код запускается, но как только доходит до инита операционки - вылет.
Кто знает, как это победить?

Компилятор ессно Keil. sm.gif
jcxz
как делаете рестарт?
EXeGLuMATOR
Цитата(jcxz @ May 3 2012, 14:44) *
как делаете рестарт?


А по всякому пробовал. Благо вариантов в ветке представлено. sm.gif
И так:
Код
        static const uint16_t code[] =
        {
                0xF850, 0xDB04, // LDR.W SP, [R0], #4  
                0x6800,         // LDR.W R0, [R0]      
                0x4700,         // BX R0                
        };
        ((void (*)(uint32_t))(1 + (int)code))(PAYLOAD_START_ADDR);


И так:
Код
  typedef  void (*pFunction)(void);
  pFunction Jump_To_Application;
  uint32_t JumpAddress;
    
   void (*user_code_entry)(void);
    user_code_entry = ((void (*)(void))(PAYLOAD_START_ADDR+4));
    user_code_entry();


И так, что в общем идентично предыдущему, но без смещения:
Код
void execute_user_code(void)
{
    void (*user_code_entry)(void);
    user_code_entry = (void (*)(void))USER_START_SECTOR_ADDRESS;
    user_code_entry();
}


Результат один. Перезапуск удается, код запускается, инитится вся периферия, но как только дело доходит до запуска непосредственно оси функцией os_sys_init(TaskInit); - все вылетает в HARD Fault Handler. Причем изначально все запускается и работает без нареканий. Программа скомпилирована, заружена и запущена без лоадера, с адреса 0. В качестве эксперимента просто пытаюсь рестартовать проц из самой проги. Потом уже все остальное. На 23хх процах была подобная фигня при перезагрузке лоадером - вылечилось дефайнами RAM_INTVEC RAM_MODE REMAP. Сейчас не проходит. Где-то что-то упускаю. sad.gif
_Артём_
Цитата(EXeGLuMATOR @ May 3 2012, 14:48) *
Результат один. Перезапуск удается, код запускается, инитится вся периферия, но как только дело доходит до запуска непосредственно оси функцией os_sys_init(TaskInit); - все вылетает в HARD Fault Handler. Причем изначально все запускается и работает без нареканий. Программа скомпилирована, заружена и запущена без лоадера, с адреса 0. В качестве эксперимента просто пытаюсь рестартовать проц из самой проги. Потом уже все остальное. На 23хх процах была подобная фигня при перезагрузке лоадером - вылечилось дефайнами RAM_INTVEC RAM_MODE REMAP. Сейчас не проходит. Где-то что-то упускаю. sad.gif

У вас в boot-е используется Systick?
Может bootloader создаёт дополнительную задержку и происходит прерывание таймера SysTick раньше чем ОСь проинициализировалась?
AlexandrY
Цитата(EXeGLuMATOR @ May 3 2012, 12:01) *
Т.е. перешиваемся, рестартуем, код запускается, но как только доходит до инита операционки - вылет.
Кто знает, как это победить?

Компилятор ессно Keil. sm.gif


Вот такой код работает в моих приложениях под RL-ARM

Код
/*------------------------------------------------------------------------------

------------------------------------------------------------------------------*/
__asm void Select_msp (void)
{
  MOVNE   R0,#0x00    
  MSR     CONTROL,R0
  BX      LR

  ALIGN
}


/*------------------------------------------------------------------------------

------------------------------------------------------------------------------*/
static void Goto_app(void)
{
  // Запрещаем все источники прерываний
  SysTick->CTRL  = 0;
  NVICx->ICER[0] = 0xFFFFFFFF;
  NVICx->ICER[1] = 0xFFFFFFFF;

  Select_msp();  
  __MSR_MSP(*(vu32*) PROGRAMM_AREA_BEG_ADDR);
  APP_entry =  (fnc)(*(vu32*) (PROGRAMM_AREA_BEG_ADDR + 4));

  APP_entry();
}
jcxz
Цитата(EXeGLuMATOR @ May 3 2012, 17:48) *
А по всякому пробовал. Благо вариантов в ветке представлено. sm.gif

И ни одного правильного Вы не использовали wink.gif
Цитата(EXeGLuMATOR @ May 3 2012, 17:48) *
Результат один. Перезапуск удается, код запускается, инитится вся периферия, но как только дело доходит до запуска непосредственно оси функцией os_sys_init(TaskInit); - все вылетает в HARD Fault Handler. Причем изначально все запускается и работает без нареканий. Программа скомпилирована, заружена и запущена без лоадера, с адреса 0. В качестве эксперимента просто пытаюсь рестартовать проц из самой проги. Потом уже все остальное. На 23хх процах была подобная фигня при перезагрузке лоадером - вылечилось дефайнами RAM_INTVEC RAM_MODE REMAP. Сейчас не проходит. Где-то что-то упускаю. sad.gif

Вы разницу понимаете между аппаратным ресетом, после которого у вас всё работает и тем, что вы делаете в приведённых примерах?
Разница в том, что в первом случае вся периферия процессора изначально находится в дефолтном состоянии, а во втором - нет.
У вас инициализирующий код где-то завязан на это дефолтное состояние после сброса.
Я уже приводил правильный способ сброса - аппаратный сброс через внутренний сторожевик.
Либо через внешний (который у должен быть в любом нормальном устройстве) блокированием импульсов WDI.
После него все узлы контроллера будут находиться в дефолтном состоянии, почти как после включения питания (отличие только, что внешние устройства на плате не будут в дефолтном состоянии).
Sanya_kv
EXeGLuMATOR
А какое ядро Вы используете ARM 7 или Cortex XX
Предполагаю, что функцию перехода на начало основной программы, Вы вызываете из ”User mode”, и как следствие не правильная инициализация стеков в основной программе (Из User mode не все регистры доступны.).
Я, после обновления основной программы из загрузчика, вызываю программное прерывание (Supervisor mode), и от туда запускаю основную программу.
При использовании RL-ARM (в Keil), необходимо использовать SWI(8) или более .
EXeGLuMATOR
Отвлекся на другие дела...
Не совсем может понятно написал. В лоадере RL-ARM не используется. Там все просто. Камушек LPC1343. Используется встроенный HID - драйвер. По HID происходит обносвление основной прошивки. Потом соотв переход на неё. Из встроенной периферии используется помимо USB еще UART - для вывода сообщений. Ну GPIO еще. И собственно все.
Так вот, если заливать и стартовать основной код с адреса 0 - то он сам себя прекрасно перезапускает. Тестовый код тоже простой - ничего не инитится, только ЮАРТ - вывод строчки на терминал и далее - перезагрузка.
Следующий этап - через лоадер. Заливаем софтинку лоадером. Если простая тестовая софтинка - та-же что и впредыдущем этапе - все нормально. Все обновляется, запускается и выполняется переход на основной код. Там тоже все нормально.
Но как только появляется RL-ARM в пользовательском софте - все. Никаких движений после перехода на пользовательский софт. Стартапы одинаковые - тестовый проект сделан на базе основного, только урезан по максимуму.
net
QUOTE (EXeGLuMATOR @ May 21 2012, 17:00) *

странно - у нас из под загрузчика с rtx запускается задача с rtx и никаких проблем нет
так обсуждать тяжеловато все
но проблем быть не должно - может просто явный ляп не видите
EXeGLuMATOR
Да может и явный ляп. Понять-бы где.
На LPC2368 - нужно было стартап править и таблицу SWI.
Здесь не пойму, что не так.
Может кто-нибудь startup_LPC13xx.s и SVC_Table.s от рабочих проектов с RL-ARM в качестве загружаемой софтины выложить?
jcxz
Не очень понятно - зачем упорно пытаться сделать сброс коряво - переходом на стартовый адрес, вместо корректного ресета через сторожевик???
Наверно я чего-то не понимай sm.gif
Если по каким-то религиозным соображениям не нравится сторожевик, то часто в контроллерах есть другие документированные способы сброса.
Например в Cortex-M3: регистр AIRCR (0xE000ED0C).
EXeGLuMATOR
Цитата(jcxz @ May 24 2012, 06:14) *
Не очень понятно - зачем упорно пытаться сделать сброс коряво - переходом на стартовый адрес, вместо корректного ресета через сторожевик???
Наверно я чего-то не понимай sm.gif
Если по каким-то религиозным соображениям не нравится сторожевик, то часто в контроллерах есть другие документированные способы сброса.
Например в Cortex-M3: регистр AIRCR (0xE000ED0C).


Ну сбросили камень. Дальше что - опять заходим в лоадер. Мне не сброс нужен а переход из лоадера на основную программу, которая находится далеко не на 0 адресе.
Сергей Борщ
QUOTE (EXeGLuMATOR @ May 24 2012, 07:34) *
Ну сбросили камень. Дальше что - опять заходим в лоадер.

А из него "с чистого листа" BX R0. При этом уверены, что ни прерывания не разрешены, ни запросы на них необслуженные не висят, ну и т.д.
QUOTE (EXeGLuMATOR @ May 24 2012, 07:34) *
Мне не сброс нужен а переход из лоадера на основную программу, которая находится далеко не на 0 адресе.
Программа-то ладно, где у вас вектора от этой программы расположены? Куда попадет инструкция SWI - в загрузчик?
EXeGLuMATOR
Цитата(Сергей Борщ @ May 24 2012, 09:47) *
А из него "с чистого листа" BX R0. При этом уверены, что ни прерывания не разрешены, ни запросы на них необслуженные не висят, ну и т.д.
Программа-то ладно, где у вас вектора от этой программы расположены? Куда попадет инструкция SWI - в загрузчик?


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

Вот с тем, где все вектора будут лежать и как их положить куда нужно и хочу разобраться.
jcxz
Цитата(EXeGLuMATOR @ May 24 2012, 11:58) *
Ну так в лоадер-то все равно заходить нужно. Смысл - ведь все работало и так раньше. Ппросто потребовалось перенести проект на другой проц. Не могу понять в чем дело.

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

Значит у вас не работает запуск рабочего ПО и при включении питания, а не только при ресете из него.
Значит - надо вначале добиться этого, а потом сброс через сторожевик сделает его подобным PowerOn.
"Как положить куда нужно" описано в командном файле компоновщика (в IAR это - *.icf)
Сергей Борщ
QUOTE (jcxz @ May 24 2012, 09:52) *
Как положить куда нужно" описано в командном файле компоновщика (в IAR это - *.icf)
Но ведь по этим адресам уже лежат вектора загрузчика wink.gif
EXeGLuMATOR так и не признался, какой у него проц. Поэтому трудно выбрать, куда его направить - в сторону Remap или в сторону регистра VTOR.
EXeGLuMATOR
Ну как-же не признался. sm.gif Вот оно все. Было.

Цитата(EXeGLuMATOR @ May 21 2012, 17:00) *
Отвлекся на другие дела...
Не совсем может понятно написал. В лоадере RL-ARM не используется. Там все просто. Камушек LPC1343. Используется встроенный HID - драйвер. По HID происходит обносвление основной прошивки. Потом соотв переход на неё. Из встроенной периферии используется помимо USB еще UART - для вывода сообщений. Ну GPIO еще. И собственно все.
Так вот, если заливать и стартовать основной код с адреса 0 - то он сам себя прекрасно перезапускает. Тестовый код тоже простой - ничего не инитится, только ЮАРТ - вывод строчки на терминал и далее - перезагрузка.
Следующий этап - через лоадер. Заливаем софтинку лоадером. Если простая тестовая софтинка - та-же что и впредыдущем этапе - все нормально. Все обновляется, запускается и выполняется переход на основной код. Там тоже все нормально.
Но как только появляется RL-ARM в пользовательском софте - все. Никаких движений после перехода на пользовательский софт. Стартапы одинаковые - тестовый проект сделан на базе основного, только урезан по максимуму.


Вот - как-то так.

Аналогичные грабли были и на LPC2368. Но там разобрался.
Цитата
На LPC2368 - нужно было стартап править и таблицу SWI.
Здесь не пойму, что не так.

Может кто-нибудь startup_LPC13xx.s и SVC_Table.s от рабочих проектов с RL-ARM в качестве загружаемой софтины выложить?



Перерыл кучу форумов в том числе и и на Кейле - народ мается теми-же проблемами, но решения что-то не нашел.
Сергей Борщ
QUOTE (EXeGLuMATOR @ May 24 2012, 10:50) *
Ну как-же не признался. sm.gif Вот оно все. Было.
Виноват. Пропустил. Могу посоветовать такой алгоритм:
1) запрещаете прерывания.
2) записываете в SCB->VTOR значение PAYLOAD_START_ADDR.
3) Записывате в MSP значение, взятое по адресу PAYLOAD_START_ADDR. (используйте функцию CMSIS __set_MSP())
4) Делаете переход таким образом:
CODE
    void (*user_code_entry)(void);
    user_code_entry = *((void (**)(void))(PAYLOAD_START_ADDR+4));
    user_code_entry();
Обратите внимание, что вы переходите не на адрес PAYLOAD_START_ADDR+4, а на адрес, который записан в ячейке с адресом PAYLOAD_START_ADDR+4. Ваши же примеры являют какую-то смесь из кода запуска для ARM (переход на первый адрес приложения, по которому располагается вектор исключения, представляющий из себя команду перехода) и кода для Cortex у которого вектор сброса расположен со смещением 4 байта (или sizeof(int)), но он представляет из себя не команду, а указатель. Поэтому очень сомнительно, что ваш предыдущий код хоть как-то работал.

Добавлено: похоже, не все кортексы-M3 одинаково одинаковые. Открыл мануал на 13xx, в нем нет упоминания про VTOR (хотя это часть ядра M3), зато есть упоминание про REMAP. Поищу еще, но, похоже, вам придется делать копирование векторов в ОЗУ и Remap.
EXeGLuMATOR
Цитата(Сергей Борщ @ May 24 2012, 12:05) *
Виноват. Пропустил. Могу посоветовать такой алгоритм:
1) запрещаете прерывания.
2) записываете в SCB->VTOR значение PAYLOAD_START_ADDR.
3) Записывате в MSP значение, взятое по адресу PAYLOAD_START_ADDR. (используйте функцию CMSIS __set_MSP())
4) Делаете переход таким образом:
Код
    void (*user_code_entry)(void);
    user_code_entry = *((void (**)(void))(PAYLOAD_START_ADDR+4));
    user_code_entry();
Обратите внимание, что вы переходите не на адрес PAYLOAD_START_ADDR+4, а на адрес, который записан в ячейке с адресом PAYLOAD_START_ADDR+4. Ваши же примеры являют какую-то смесь из кода запуска для ARM (переход на первый адрес приложения, по которому располагается вектор исключения, представляющий из себя команду перехода) и кода для Cortex у которого вектор сброса расположен со смещением 4 байта (или sizeof(int)), но он представляет из себя не команду, а указатель. Поэтому очень сомнительно, что ваш предыдущий код хоть как-то работал.

Добавлено: похоже, не все кортексы-M3 одинаково одинаковые. Открыл мануал на 13xx, в нем нет упоминания про VTOR (хотя это часть ядра M3), зато есть упоминание про REMAP. Поищу еще, но, похоже, вам придется делать копирование векторов в ОЗУ и Remap.


Спасибо. Проверю. Еще вопросик - какие особенности при компиляции основной программы? С учетом RL-ARM? Ну, помимо адреса старта. sm.gif
Сергей Борщ
QUOTE (Сергей Борщ @ May 24 2012, 11:05) *
похоже, не все кортексы-M3 одинаково одинаковые.
ДА, сочувствую. Им удалось совместить ядро M3 и механизм ремапа из LPC2xxx. Придется вам жертвовать кусочком ОЗУ и делать по-старинке.
В скрипте линкера надо будет откусить от начала ОЗУ кусочек для векторов. При ремапе на нулевые адреса отражается 512 байт ОЗУ (см. рис. 2 в руководстве пользователя). Из них реально под вектора используются: 4 байта на начальный адрес стека, 4 * 15 байт на вектора исключений ядра и 4 * 57 байт для векторов прерываний периферии. Итого 292 байта. Именно столько надо будет зарезервировать.

А стартовать можно примерно так:
CODE
#define APPLICATION_IMAGE_START 0x00002000
#define VECTORS_REMAP_AREA      0x10000000  // start of SRAM
    typedef struct
    {
        typedef void( *handler )( void );
        uint32_t    MSP_init;
        handler     Reset_vector;
        handler     Core_handler[14];
        handler     MCU_handler[57];
    } vectors_t;

    vectors_t const * const pApp_vectors = (vectors_t const * const)APPLICATION_IMAGE_START;
    vectors_t * const pRemap_area = (vectors_t * const)VECTORS_REMAP_AREA;

    // copy application vectors table to remap area
//    memcpy(pRemap_area, pApp_vectors, sizeof(vectors_t));
    uint32_t const * pSrc = (uint32_t const *)pApp_vectors;
    uint32_t * pDst = (uint32_t *)pRemap_area;
    do
    {
        *pDst++ = *pSrc++;
    }
    while(pSrc < (uint32_t const *)(pApp_vectors + 1));

    // Init application main stack pointer
    __set_MSP(pApp_vectors->MSP_init);

    // remap to ram
    LPC_SYSCON->SYSMEMREMAP = 1;

    // start application
    pApplication->Reset_vector();


Да, и еще такая тонкость: этот код (хотя бы начиная с LPC_SYSCON->SYSMEMREMAP = 1) должен располагаться с адреса больше 512. В противном случае его "накроет" после ремапа содержимым ОЗУ.
EXeGLuMATOR
Да, сурово. Повелся на экономию места и цену. И кажущуюся простоту использования ЮСБ. Хотя если не заморачиваться с лоадером - то все нормально.
Кстати о USB - там ведь еще надо учитывать, что RAM с 0x10000000 по 0x10000180 используется hardware USB driver-ом.
Т.е. для лоадера придется откусывать и этот кусок и то, что под вектора. Т.е. получается, что #define VECTORS_REMAP_AREA 0x10000000 // start of SRAM будет выглядеть как #define VECTORS_REMAP_AREA 0x10000180

Ну да ладно - не много то ее там и нужно. Мне больше загрузка и обновление нужны.
Сергей Борщ
QUOTE (EXeGLuMATOR @ May 24 2012, 13:20) *
Т.е. получается, что #define VECTORS_REMAP_AREA 0x10000000 // start of SRAM будет выглядеть как #define VECTORS_REMAP_AREA 0x10000180
Нет, вы не поняли - первые 512 байт ОЗУ отображаются на адреса начиная с 0. Поэтому обращаясь к векторам по адресу 0, 4, 8... проц фактически обращается в ОЗУ по адресам 0x10000000, 0x10000004, 0x10000008 .... И изменить это невозможно. VECTORS_REMAP_AREA должна начинаться с 0x10000000, ни байтом больше, ни байтом меньше.

Боюсь вас разочаровывать, но, похоже вам придется либо отказаться от набортного USB-драйвера, либо от обновлений, либо от еще 292-8 = 284 байтов в области загрузчика, прерываний загрузчика и делать так называемые "трамплины".

Или искать, куда потерялся VTOR.

QUOTE (Сергей Борщ @ May 24 2012, 13:48) *
Или искать, куда потерялся VTOR.
"Легенда меняется. Вы- нищий" (с)"Чокнутые".

Оказывается у меня старательно хранился мануал версии 0.1 от 2009года. В свежем версии 4 от 2011 года VTOR есть. Сейчас пообедаю и напишу, как сделать через него.


Как вариант:
CODE
#define APPLICATION_IMAGE_START 0x00002000
    typedef struct
    {
        typedef void( *handler )( void );
        uint32_t    MSP_init;
        handler     Reset_vector;
        handler     Core_handler[14];
        handler     MCU_handler[57];
    } vectors_t;

    vectors_t const * const pApp_vectors = (vectors_t const * const)APPLICATION_IMAGE_START;

    // activate application's vectors table
    SCB->VTOR = (uintptr_t)pApp_Vectors;
    
    // Init application main stack pointer
    __set_MSP(pApp_vectors->MSP_init);
    
    // start application
    pApplication->Reset_vector();
EXeGLuMATOR
Урррааа! Заработало. Большое спасибо!
Думаю пусть код здесь будет - мало-ли кому пригодится.
Код
typedef void( *handler )( void );

typedef struct
{
   uint32_t    MSP_init;
   handler     Reset_vector;
   handler     Core_handler[14];
   handler     MCU_handler[57];
} vectors_t;

void execute_user_code(void)
{
vectors_t const * const pApp_vectors = (vectors_t const * const)PAYLOAD_START_ADDR;

// activate application's vectors table
SCB->VTOR = (uintptr_t)pApp_vectors;
  
// Init application main stack pointer
__set_MSP(pApp_vectors->MSP_init);
    
// start application
pApp_vectors->Reset_vector();
};


Это все полностью работает. RL-ARM стартует, инитится и вроде даже нормально шевелится. sm.gif Еще полностью все проверю.
Да, не все... sad.gif Поторопился - не работает его встроенное USB. Видимо таки наложение где-то происходит.

З.Ы. Ан нет. все работает. Эт я глюкнул - в ходе экспериментов закомментил обработчик ЮСБ. Но все равно - после обновления прошивки и перехода на основной код ЮСБ таки не работает. А вот если отресетить камень, то после отработки загрузчика ЮСБ работает нормально - у меня в коде загрузчика если не требуется обновления ЮСБ и не инитится. А вот если инитится в лоадере - то что-то не хочет с ходу работать. Видимо тоже есть особенности, пока не ясные.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.