|
RL-ARM и bootloader, Запуск основной программы после перепрошивки |
|
|
|
May 3 2012, 09:01
|
Частый гость
 
Группа: Свой
Сообщений: 182
Регистрация: 30-01-05
Из: Volgograd
Пользователь №: 2 305

|
Имеется следующий проектик, как водится, состоящий из двух частей. Бутлоадер и основная программа. Причем в основной программе также есть блок перепрошивки "самой себя". Используется RL-ARM. Вопрос в следующем - как после перпрошивки перезапустить проц? Собсно как перезапустить более или менее понятно. Проблема в том, что после перезапуска все уходит в HardFault при вызове os_sys_init(). Т.е. перешиваемся, рестартуем, код запускается, но как только доходит до инита операционки - вылет. Кто знает, как это победить? Компилятор ессно Keil.
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 22)
|
May 3 2012, 11:48
|
Частый гость
 
Группа: Свой
Сообщений: 182
Регистрация: 30-01-05
Из: Volgograd
Пользователь №: 2 305

|
Цитата(jcxz @ May 3 2012, 14:44)  как делаете рестарт? А по всякому пробовал. Благо вариантов в ветке представлено.  И так: Код 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. Сейчас не проходит. Где-то что-то упускаю.
|
|
|
|
|
May 3 2012, 15:49
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(EXeGLuMATOR @ May 3 2012, 14:48)  Результат один. Перезапуск удается, код запускается, инитится вся периферия, но как только дело доходит до запуска непосредственно оси функцией os_sys_init(TaskInit); - все вылетает в HARD Fault Handler. Причем изначально все запускается и работает без нареканий. Программа скомпилирована, заружена и запущена без лоадера, с адреса 0. В качестве эксперимента просто пытаюсь рестартовать проц из самой проги. Потом уже все остальное. На 23хх процах была подобная фигня при перезагрузке лоадером - вылечилось дефайнами RAM_INTVEC RAM_MODE REMAP. Сейчас не проходит. Где-то что-то упускаю.  У вас в boot-е используется Systick? Может bootloader создаёт дополнительную задержку и происходит прерывание таймера SysTick раньше чем ОСь проинициализировалась?
|
|
|
|
|
May 3 2012, 17:18
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(EXeGLuMATOR @ May 3 2012, 12:01)  Т.е. перешиваемся, рестартуем, код запускается, но как только доходит до инита операционки - вылет. Кто знает, как это победить? Компилятор ессно Keil.  Вот такой код работает в моих приложениях под 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(); }
|
|
|
|
|
May 4 2012, 01:54
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(EXeGLuMATOR @ May 3 2012, 17:48)  А по всякому пробовал. Благо вариантов в ветке представлено.  И ни одного правильного Вы не использовали  Цитата(EXeGLuMATOR @ May 3 2012, 17:48)  Результат один. Перезапуск удается, код запускается, инитится вся периферия, но как только дело доходит до запуска непосредственно оси функцией os_sys_init(TaskInit); - все вылетает в HARD Fault Handler. Причем изначально все запускается и работает без нареканий. Программа скомпилирована, заружена и запущена без лоадера, с адреса 0. В качестве эксперимента просто пытаюсь рестартовать проц из самой проги. Потом уже все остальное. На 23хх процах была подобная фигня при перезагрузке лоадером - вылечилось дефайнами RAM_INTVEC RAM_MODE REMAP. Сейчас не проходит. Где-то что-то упускаю.  Вы разницу понимаете между аппаратным ресетом, после которого у вас всё работает и тем, что вы делаете в приведённых примерах? Разница в том, что в первом случае вся периферия процессора изначально находится в дефолтном состоянии, а во втором - нет. У вас инициализирующий код где-то завязан на это дефолтное состояние после сброса. Я уже приводил правильный способ сброса - аппаратный сброс через внутренний сторожевик. Либо через внешний (который у должен быть в любом нормальном устройстве) блокированием импульсов WDI. После него все узлы контроллера будут находиться в дефолтном состоянии, почти как после включения питания (отличие только, что внешние устройства на плате не будут в дефолтном состоянии).
|
|
|
|
|
May 23 2012, 05:18
|
Знающий
   
Группа: Свой
Сообщений: 858
Регистрация: 9-08-04
Пользователь №: 473

|
QUOTE (EXeGLuMATOR @ May 21 2012, 17:00)  странно - у нас из под загрузчика с rtx запускается задача с rtx и никаких проблем нет так обсуждать тяжеловато все но проблем быть не должно - может просто явный ляп не видите
|
|
|
|
|
May 24 2012, 04:34
|
Частый гость
 
Группа: Свой
Сообщений: 182
Регистрация: 30-01-05
Из: Volgograd
Пользователь №: 2 305

|
Цитата(jcxz @ May 24 2012, 06:14)  Не очень понятно - зачем упорно пытаться сделать сброс коряво - переходом на стартовый адрес, вместо корректного ресета через сторожевик??? Наверно я чего-то не понимай  Если по каким-то религиозным соображениям не нравится сторожевик, то часто в контроллерах есть другие документированные способы сброса. Например в Cortex-M3: регистр AIRCR (0xE000ED0C). Ну сбросили камень. Дальше что - опять заходим в лоадер. Мне не сброс нужен а переход из лоадера на основную программу, которая находится далеко не на 0 адресе.
|
|
|
|
|
May 24 2012, 05:47
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (EXeGLuMATOR @ May 24 2012, 07:34)  Ну сбросили камень. Дальше что - опять заходим в лоадер. А из него "с чистого листа" BX R0. При этом уверены, что ни прерывания не разрешены, ни запросы на них необслуженные не висят, ну и т.д. QUOTE (EXeGLuMATOR @ May 24 2012, 07:34)  Мне не сброс нужен а переход из лоадера на основную программу, которая находится далеко не на 0 адресе. Программа-то ладно, где у вас вектора от этой программы расположены? Куда попадет инструкция SWI - в загрузчик?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
May 24 2012, 05:58
|
Частый гость
 
Группа: Свой
Сообщений: 182
Регистрация: 30-01-05
Из: Volgograd
Пользователь №: 2 305

|
Цитата(Сергей Борщ @ May 24 2012, 09:47)  А из него "с чистого листа" BX R0. При этом уверены, что ни прерывания не разрешены, ни запросы на них необслуженные не висят, ну и т.д. Программа-то ладно, где у вас вектора от этой программы расположены? Куда попадет инструкция SWI - в загрузчик? Ну так в лоадер-то все равно заходить нужно. Смысл - ведь все работало и так раньше. Ппросто потребовалось перенести проект на другой проц. Не могу понять в чем дело. Вот с тем, где все вектора будут лежать и как их положить куда нужно и хочу разобраться.
|
|
|
|
|
May 24 2012, 07:50
|
Частый гость
 
Группа: Свой
Сообщений: 182
Регистрация: 30-01-05
Из: Volgograd
Пользователь №: 2 305

|
Ну как-же не признался.  Вот оно все. Было. Цитата(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 в качестве загружаемой софтины выложить? Перерыл кучу форумов в том числе и и на Кейле - народ мается теми-же проблемами, но решения что-то не нашел.
|
|
|
|
|
May 24 2012, 08:05
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (EXeGLuMATOR @ May 24 2012, 10:50)  Ну как-же не признался.  Вот оно все. Было. Виноват. Пропустил. Могу посоветовать такой алгоритм: 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.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
May 24 2012, 08:30
|
Частый гость
 
Группа: Свой
Сообщений: 182
Регистрация: 30-01-05
Из: Volgograd
Пользователь №: 2 305

|
Цитата(Сергей Борщ @ 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? Ну, помимо адреса старта.
|
|
|
|
|
May 24 2012, 08:50
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
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. В противном случае его "накроет" после ремапа содержимым ОЗУ.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
May 24 2012, 11:30
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
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();
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
May 25 2012, 08:46
|
Частый гость
 
Группа: Свой
Сообщений: 182
Регистрация: 30-01-05
Из: Volgograd
Пользователь №: 2 305

|
Урррааа! Заработало. Большое спасибо! Думаю пусть код здесь будет - мало-ли кому пригодится. Код 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 стартует, инитится и вроде даже нормально шевелится.  Еще полностью все проверю. Да, не все...  Поторопился - не работает его встроенное USB. Видимо таки наложение где-то происходит. З.Ы. Ан нет. все работает. Эт я глюкнул - в ходе экспериментов закомментил обработчик ЮСБ. Но все равно - после обновления прошивки и перехода на основной код ЮСБ таки не работает. А вот если отресетить камень, то после отработки загрузчика ЮСБ работает нормально - у меня в коде загрузчика если не требуется обновления ЮСБ и не инитится. А вот если инитится в лоадере - то что-то не хочет с ходу работать. Видимо тоже есть особенности, пока не ясные.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|