Артём__ 0 24 сентября, 2012 Опубликовано 24 сентября, 2012 · Жалоба Работает только если в "рабочей программе" не используются прерывания. Если прерывания используются, то "Рабоча программа" нивкакую не стартует. Какие есть догадки, в чем ошибка? Попробуйте по-другому. Например так: typedef void (*ISRPtr) (void); uint32_t *ram_vector_table, *flash_vector_table; ram_vector_table=(uint32_t *)0x10000000; flash_vector_table=(uint32_t *)0x1000; for (uint_fast32_t i=0; i<48; i++) *ram_vector_table++=*flash_vector_table++; LPC_SYSCON->SYSMEMREMAP=1; __set_MSP(*(uint32_t *)0x1000); ISRPtr application_reset_handler=(ISRPtr)(*(uint32_t *)0x1004); application_reset_handler(); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 1 24 сентября, 2012 Опубликовано 24 сентября, 2012 · Жалоба Т.к. у Cortex-M0 нет VTOR и переместить таблицу прерываний нельзя, а все таки понадобился вторичный бутлоадер, я сделал так: в бутлоадере прерывания не используются! И все указатели из таблицы прерываний (кроме ресета) указывают на такую функцию: void handler(void) { asm ( "mrs r0,IPSR\n" "movs r1,#0x1\n" "lsls r1,#10\n" "add r0, r1\n" "lsls r0,#2\n" "ldr r0,[r0]\n" "mov r15, r0"); while(1); } А старт приложения такой последовательностью: asm ("movs r1,#0x1\n" "lsls r1,#12\n" "ldm r1, {r0,r1}\n" "mov r13, r0\n" "mov r15, r1"); while(1); Все работает! Приложение ничем не отличается от обычного, только начинается с адреса 0x1000 по которому лежит обычная таблица прерываний. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 24 сентября, 2012 Опубликовано 24 сентября, 2012 · Жалоба Вот код бутлоадера:Для вставки кода в сообщения есть кнопочка на форме ввода. Используйте ее, пожалуйста. Здесь так принято. uint32_t const * pSrc = (uint32_t const *)0x00001000; //копируем первые 200 байт флеша, начиная с адреса 0х1000 в ОЗУ uint32_t * pDst = (uint32_t *)0x10000000; #define VECTORS_COUNT 128 for(uint_fast8_t i = 0; i < VECTORS_COUNT; ++i) *pDst++ = *pSrc++; А теперь смотрите внимательно: 1) Вы в комментариях пишете, что копируете 200 байт, а на самом деле копируете 128*sizeof(uint32_t), т.е. 512 байт. 2) Та часть ОЗУ, куда вы пишете, у вас зарезервирована? Т.е. не получается ли так, что вы копируя разрушаете данные или стек загрузчика? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 24 сентября, 2012 Опубликовано 24 сентября, 2012 · Жалоба Работает только если в "рабочей программе" не используются прерывания. Если прерывания используются, то "Рабоча программа" нивкакую не стартует. Какие есть догадки, в чем ошибка? Такая догадка: в рабочей программе происходит очистка памяти, в которой находятся адреса обработчиков прерываний. Проверьте на входе в main рабочей программы что у вас по адресам ОЗУ 0x10000000-0x100000C0? Заполнена эта область нулями или там адреса обработчиков? Эту область нужно как-то выделить в скрипте линкера или указать в скрипте область ОЗУ рабочей программы не 0x10000000-0x100001FF, а от 0x100000C0 до 0x100001FFF. нивкакую не стартует. Какие есть догадки, в чем ошибка? Не стартует - это что значит? А что она делает? В HardFault не попадает? P.S. Выложили бы проекты целиком - программа это не только текст. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Almaz1988 0 28 сентября, 2012 Опубликовано 28 сентября, 2012 · Жалоба Наметился небольшой прогресс)) В "загрузчике" копирую из флеша ячейки 0х0000-0х0200 в ОЗУ по адресам 0х1000 0000 - 0х1000 0200, делаю ремап и затем прыгаю по адресу Reset_handler(0х1000 0004). "Загрузчик" успешно перезапускается. Если же я копирую в ОЗУ из адресов флеша 0х2000-0х2200. То после ремапа и прыжка "Рабочая программа", которая залита по адресу 0х2000 не запускается. В том что у меня залита корректная рабочая программа я могу убедиться если не делая ремапа прыгаю: void (*fptr)(void); fptr = (void (*)(void))0x000002675; fptr(); Тогда рабочая программа запускается. Прикладываю проекты "Загрузчика" и "Рабочей программы". Еще один вопрос: Используемый МК - lpc11c24 с "железным" протоколом CAN. В рабочей программе он используется. В мануале на МК написано: On-chip RAM from address 0x1000 0050 to 0x1000 00B8 is used by the CAN API. This address range should not be used by the application. For applications using the on-chip CAN API, the linker control file should be modified appropriately to prevent usage of this area for application’s variable storage. Выходит, что ремап векторов в ОЗУ будет приводить к затиранию CAN функций? Значит ремап не решение. Какие есть другие способы решения проблемы, если и загрузчик и рабочая программа активно будут пользоваться прерываниями? bootloader.rar Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 1 28 сентября, 2012 Опубликовано 28 сентября, 2012 · Жалоба Еще один вопрос: Используемый МК - lpc11c24 с "железным" протоколом CAN. В рабочей программе он используется. В мануале на МК написано: Выходит, что ремап векторов в ОЗУ будет приводить к затиранию CAN функций? Значит ремап не решение. Какие есть другие способы решения проблемы, если и загрузчик и рабочая программа активно будут пользоваться прерываниями? Если вы используете функции CAN, которые в ПЗУ лежат, то они могут перетереть ваши вектора - т.к. используют эту область памяти под свои данные (сами функции стереть нельзя они в ПЗУ) В любом случае хранить вектора прерываний в ОЗУ для данного контроллера не очень хорошее решение! Я уже привел метод - он прекрасно работает! http://electronix.ru/forum/index.php?s=&am...t&p=1095595 Можно использовать метод еще тупее - в бутлоадере создать обработчик на каждое прерывание (для M0 их не так много) который просто берет указатель из таблицы прерываний приложения и переходит по нему. (собственно говоря приведенный исходник это и делает, но что бы не плодить функции он узнает номер из регистра). При этом приложения с бутлоадером и без бутлоадера отличаются только icf файлом! (началом флеша) и никаких ограничений на использования памяти нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 28 сентября, 2012 Опубликовано 28 сентября, 2012 · Жалоба и затем прыгаю по адресу Reset_handler(0х1000 0004).А вот неверно - вы прыгаете на вектор сброса. А надо прыгать на адрес, которых хранится в этом векторе: void (**fptr)(void); fptr = (void (**)(void))0x10000004; (*fptr)(); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Almaz1988 0 28 сентября, 2012 Опубликовано 28 сентября, 2012 · Жалоба Если вы используете функции CAN, которые в ПЗУ лежат, то они могут перетереть ваши вектора - т.к. используют эту область памяти под свои данные (сами функции стереть нельзя они в ПЗУ) В любом случае хранить вектора прерываний в ОЗУ для данного контроллера не очень хорошее решение! Я уже привел метод - он прекрасно работает! http://electronix.ru/forum/index.php?s=&am...t&p=1095595 Можно использовать метод еще тупее - в бутлоадере создать обработчик на каждое прерывание (для M0 их не так много) который просто берет указатель из таблицы прерываний приложения и переходит по нему. (собственно говоря приведенный исходник это и делает, но что бы не плодить функции он узнает номер из регистра). При этом приложения с бутлоадером и без бутлоадера отличаются только icf файлом! (началом флеша) и никаких ограничений на использования памяти нет. Ваш пример подойдет в случае, если в загрузчике не используются прерывания. В моем же случае, я планирую это делать. Я думаю написать обработчики для каждого прерывания с двумя вариантами выбора: __ASM void CAN_IRQapplication(void) { ldr r0, =0x2074 ldr r0, [r0] mov pc, r0 } __ASM void CAN_IRQbootloader(void) { ldr r0, =0x0074 ldr r0, [r0] mov pc, r0 } void CAN_IRQ(void) { if ( main < 2000 ) { CAN_IRQapplication(); } else { CAN_IRQbootloader(); } } Такое решение приведено в примере NXP secondary bootloader (без варианта выбора). Сейчас пытаюсь вкрутить их стартап-файл (LPCXpresso) в свой Keil-овский проект. Сработает? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 28 сентября, 2012 Опубликовано 28 сентября, 2012 · Жалоба Сработает?Нет. для этой программы main будет константой, она понятия не имеет, что в другой программе есть свой main и никаким образом не может получить его адрес. Можно взводить и анализировать какой-то флаг. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Almaz1988 0 28 сентября, 2012 Опубликовано 28 сентября, 2012 · Жалоба Нет. для этой программы main будет константой, она понятия не имеет, что в другой программе есть свой main и никаким образом не может получить его адрес. Можно взводить и анализировать какой-то флаг. Так нам и не нужен main другой программы. Запускается загрузчик. Начинает работать. При прерываниях прыгает в свою табл векторов ( т.к. адрес его функции main < 0x2000). Закончил работу, передал управление рабочей программе. Та начинает работу и при прерываниях прыгает по своим адресам ( т.к. адрес его функции main > 0x2000). что в keil'e, что в LPCXpresso startup-файлы полны загадочных extern и импорт, например: в Keil: Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main LDR R0, =__main BX R0 ENDP в LPCXpresso: extern unsigned long _etext; extern unsigned long _data; extern unsigned long _edata; extern unsigned long _bss; extern unsigned long _ebss; void ResetISR(void) { unsigned char *pulSrc, *pulDest; pulSrc = (unsigned char *)&_etext; for(pulDest = (unsigned char *)&_data; pulDest < (unsigned char *)&_edata; ) { *pulDest++ = *pulSrc++; } ......... Откуда в Кейловском варианте берется __main, а в LPC-шном _etext, _data, _edata....? Их тупо проэкстернили, но они нигде не инициализируются Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 28 сентября, 2012 Опубликовано 28 сентября, 2012 · Жалоба Та начинает работу и при прерываниях прыгает по своим адресам ( т.к. адрес его функции main > 0x2000).Прыгает в каком месте? В тех функциях, которые принадлежат загрузчику и знают только о существовании своего main. Либо приложению надо переписать эти функции поверх функций загрузчика, тогда зачем в них ветвление? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Almaz1988 0 28 сентября, 2012 Опубликовано 28 сентября, 2012 · Жалоба Прыгает в каком месте? В тех функциях, которые принадлежат загрузчику и знают только о существовании своего main. Либо приложению надо переписать эти функции поверх функций загрузчика, тогда зачем в них ветвление? В каждый проект(загрузчик и рабочая программа) добавляет один и тот же файл (Handlers.h), в котором написаны обработчики прерываний которые отправляют по адресам 0х0000 - 0х00С0, если они вызваны из загрузчика и по адресам 0х2000 - 0х20С), если они вызваны из рабочей программы. По идее нужно просто переделать стартап файл, чтобы из него при всех прерываниях прыгать в мои самописные обработчики прерываний. Но он меня пока вводит в тупик - своими экстернами и импортами нигде не объявленных переменных Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 1 28 сентября, 2012 Опубликовано 28 сентября, 2012 · Жалоба Я думаю написать обработчики для каждого прерывания с двумя вариантами выбора: там функции на асме не нужны! Проще сразу из С вызвать нужную функцию из таблиц указателей! тут весь вопрос в условии - как определить что бутлоадер еще работает! А можно и один код для всех обработчиков оставить - только базовый адрес таблицы вычислять в зависимости от условия void handler(void) { asm ( // вычислить адрес таблицы в R1 "mrs r0,IPSR\n" "add r0, r1\n" "lsls r0,#2\n" "ldr r0,[r0]\n" "mov r15, r0"); while(1); } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 28 сентября, 2012 Опубликовано 28 сентября, 2012 · Жалоба Используемый МК - lpc11c24 с "железным" протоколом CAN. В рабочей программе он используется. В мануале на МК написано: Выходит, что ремап векторов в ОЗУ будет приводить к затиранию CAN функций? Значит ремап не решение. Какие есть другие способы решения проблемы, если и загрузчик и рабочая программа активно будут пользоваться прерываниями? Almaz1988, а в буте CAN используется? Если не используется, то может можно сделать наоборот: бут располагается где нибудь в конце памяти, и при старте ремапит вектора в ОЗУ, а основная программа работает с векторами расположенными во flash. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Almaz1988 0 1 октября, 2012 Опубликовано 1 октября, 2012 · Жалоба Продолжаю штурм)) и в загрузчике и в рабочей программе будут использоваться прерывания: SysTick, SVC, PendSV, CAN. Пишу обработчики для этих прерываний. Если в обработчике для каждого прерывания делаю прыжок, например в SysTick_Handler: __ASM void SysTick_Handler(void) { ldr r0, =0x203C ldr r0, [r0] mov pc, r0 } То Загрузчик передает управление Рабочей программе, в которой все прерывания обрабатываются корректно. Но, стоит написать вот так (через функцию посредник): __ASM void SysTick_Handler_of_application(void) { ldr r0, =0x203C ldr r0, [r0] mov pc, r0 } void SysTick_Handler(void) { SysTick_Handler_of_application( ); } И три из четырех обработчика прерывания работать уже не хотят! Обрабатываются только CAN-прерывания! Функции посредники нужны мне для того, чтобы производить проверку, из какой программы вызвано прерывание: void SysTick_Handler(void) { if ( *(uint32_t *)0x100001F0 == 0x67 ) //сли обработчик прерывания вызван из рабочей программы, то прыгаем в таблицу векторов рабочей программы SysTick_Handler_of_application( ); else SysTick_Handler_of_bootloader();//иначе обработчик прерывания вызван из загрузчика } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться