реклама на сайте
подробности

 
 
5 страниц V  < 1 2 3 4 5 >  
Reply to this topicStart new topic
> LPC11xx не стартует код из своего бутлоадера
_Артём_
сообщение Sep 24 2012, 11:18
Сообщение #31


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(Almaz1988 @ Sep 24 2012, 11:46) *
Работает только если в "рабочей программе" не используются прерывания. Если прерывания используются, то "Рабоча программа" нивкакую не стартует.
Какие есть догадки, в чем ошибка?

Попробуйте по-другому.
Например так:
Код
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();
Go to the top of the page
 
+Quote Post
KRS
сообщение Sep 24 2012, 11:41
Сообщение #32


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Т.к. у 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 по которому лежит обычная таблица прерываний.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 24 2012, 12:45
Сообщение #33


Гуру
******

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



QUOTE (Almaz1988 @ Sep 24 2012, 11:46) *
Вот код бутлоадера:
Для вставки кода в сообщения есть кнопочка на форме ввода. Используйте ее, пожалуйста. Здесь так принято.
QUOTE (Almaz1988 @ Sep 24 2012, 11:46) *
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) Та часть ОЗУ, куда вы пишете, у вас зарезервирована? Т.е. не получается ли так, что вы копируя разрушаете данные или стек загрузчика?


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Sep 24 2012, 15:09
Сообщение #34


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(Almaz1988 @ Sep 24 2012, 11:46) *
Работает только если в "рабочей программе" не используются прерывания. Если прерывания используются, то "Рабоча программа" нивкакую не стартует.
Какие есть догадки, в чем ошибка?

Такая догадка: в рабочей программе происходит очистка памяти, в которой находятся адреса обработчиков прерываний.
Проверьте на входе в main рабочей программы что у вас по адресам ОЗУ 0x10000000-0x100000C0? Заполнена эта область нулями или там адреса обработчиков?
Эту область нужно как-то выделить в скрипте линкера или указать в скрипте область ОЗУ рабочей программы не 0x10000000-0x100001FF, а от 0x100000C0 до 0x100001FFF.

Цитата(Almaz1988 @ Sep 24 2012, 11:46) *
нивкакую не стартует.
Какие есть догадки, в чем ошибка?

Не стартует - это что значит? А что она делает?
В HardFault не попадает?

P.S. Выложили бы проекты целиком - программа это не только текст.
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Sep 28 2012, 06:22
Сообщение #35


Частый гость
**

Группа: Участник
Сообщений: 100
Регистрация: 19-09-12
Пользователь №: 73 602



Наметился небольшой прогресс))
В "загрузчике" копирую из флеша ячейки 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 ( 197.97 килобайт ) Кол-во скачиваний: 17
 
Go to the top of the page
 
+Quote Post
KRS
сообщение Sep 28 2012, 07:15
Сообщение #36


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(Almaz1988 @ Sep 28 2012, 10:22) *
Еще один вопрос:
Используемый МК - lpc11c24 с "железным" протоколом CAN. В рабочей программе он используется.
В мануале на МК написано:

Выходит, что ремап векторов в ОЗУ будет приводить к затиранию CAN функций?



Значит ремап не решение.
Какие есть другие способы решения проблемы, если и загрузчик и рабочая программа активно будут пользоваться прерываниями?

Если вы используете функции CAN, которые в ПЗУ лежат, то они могут перетереть ваши вектора - т.к. используют эту область памяти под свои данные (сами функции стереть нельзя они в ПЗУ)

В любом случае хранить вектора прерываний в ОЗУ для данного контроллера не очень хорошее решение!
Я уже привел метод - он прекрасно работает! http://electronix.ru/forum/index.php?s=&am...t&p=1095595
Можно использовать метод еще тупее - в бутлоадере создать обработчик на каждое прерывание (для M0 их не так много) который просто берет указатель из таблицы прерываний приложения и переходит по нему. (собственно говоря приведенный исходник это и делает, но что бы не плодить функции он узнает номер из регистра).

При этом приложения с бутлоадером и без бутлоадера отличаются только icf файлом! (началом флеша) и никаких ограничений на использования памяти нет.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 28 2012, 07:56
Сообщение #37


Гуру
******

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



QUOTE (Almaz1988 @ Sep 28 2012, 09:22) *
и затем прыгаю по адресу Reset_handler(0х1000 0004).
А вот неверно - вы прыгаете на вектор сброса. А надо прыгать на адрес, которых хранится в этом векторе:
CODE
    void (**fptr)(void);
    fptr = (void (**)(void))0x10000004;
    (*fptr)();


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Sep 28 2012, 08:10
Сообщение #38


Частый гость
**

Группа: Участник
Сообщений: 100
Регистрация: 19-09-12
Пользователь №: 73 602



Цитата(KRS @ Sep 28 2012, 11:15) *
Если вы используете функции 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-овский проект.


Сработает?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 28 2012, 08:44
Сообщение #39


Гуру
******

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



QUOTE (Almaz1988 @ Sep 28 2012, 11:10) *
Сработает?
Нет. для этой программы main будет константой, она понятия не имеет, что в другой программе есть свой main и никаким образом не может получить его адрес. Можно взводить и анализировать какой-то флаг.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Sep 28 2012, 09:06
Сообщение #40


Частый гость
**

Группа: Участник
Сообщений: 100
Регистрация: 19-09-12
Пользователь №: 73 602



Цитата(Сергей Борщ @ Sep 28 2012, 12:44) *
Нет. для этой программы 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....?
Их тупо проэкстернили, но они нигде не инициализируются


Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 28 2012, 09:26
Сообщение #41


Гуру
******

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



QUOTE (Almaz1988 @ Sep 28 2012, 12:06) *
Та начинает работу и при прерываниях прыгает по своим адресам ( т.к. адрес его функции main > 0x2000).
Прыгает в каком месте? В тех функциях, которые принадлежат загрузчику и знают только о существовании своего main. Либо приложению надо переписать эти функции поверх функций загрузчика, тогда зачем в них ветвление?


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Sep 28 2012, 09:43
Сообщение #42


Частый гость
**

Группа: Участник
Сообщений: 100
Регистрация: 19-09-12
Пользователь №: 73 602



Цитата(Сергей Борщ @ Sep 28 2012, 13:26) *
Прыгает в каком месте? В тех функциях, которые принадлежат загрузчику и знают только о существовании своего main. Либо приложению надо переписать эти функции поверх функций загрузчика, тогда зачем в них ветвление?

В каждый проект(загрузчик и рабочая программа) добавляет один и тот же файл (Handlers.h), в котором написаны обработчики прерываний которые отправляют по адресам 0х0000 - 0х00С0, если они вызваны из загрузчика и по адресам 0х2000 - 0х20С), если они вызваны из рабочей программы. По идее нужно просто переделать стартап файл, чтобы из него при всех прерываниях прыгать в мои самописные обработчики прерываний.
Но он меня пока вводит в тупик - своими экстернами и импортами нигде не объявленных переменных
Go to the top of the page
 
+Quote Post
KRS
сообщение Sep 28 2012, 10:45
Сообщение #43


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(Almaz1988 @ Sep 28 2012, 12:10) *
Я думаю написать обработчики для каждого прерывания с двумя вариантами выбора:

там функции на асме не нужны! Проще сразу из С вызвать нужную функцию из таблиц указателей!

тут весь вопрос в условии - как определить что бутлоадер еще работает!

А можно и один код для всех обработчиков оставить - только базовый адрес таблицы вычислять в зависимости от условия

Код
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);
}

Go to the top of the page
 
+Quote Post
_Артём_
сообщение Sep 28 2012, 18:55
Сообщение #44


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(Almaz1988 @ Sep 28 2012, 09:22) *
Используемый МК - lpc11c24 с "железным" протоколом CAN. В рабочей программе он используется.
В мануале на МК написано:

Выходит, что ремап векторов в ОЗУ будет приводить к затиранию CAN функций?
Значит ремап не решение.
Какие есть другие способы решения проблемы, если и загрузчик и рабочая программа активно будут пользоваться прерываниями?

Almaz1988, а в буте CAN используется?
Если не используется, то может можно сделать наоборот:
бут располагается где нибудь в конце памяти, и при старте ремапит вектора в ОЗУ, а основная программа работает с векторами расположенными во flash.
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Oct 1 2012, 11:34
Сообщение #45


Частый гость
**

Группа: Участник
Сообщений: 100
Регистрация: 19-09-12
Пользователь №: 73 602



Продолжаю штурм))
и в загрузчике и в рабочей программе будут использоваться прерывания: 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();//иначе обработчик прерывания вызван из загрузчика
}
Go to the top of the page
 
+Quote Post

5 страниц V  < 1 2 3 4 5 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 23rd July 2025 - 15:23
Рейтинг@Mail.ru


Страница сгенерированна за 0.01517 секунд с 7
ELECTRONIX ©2004-2016