Перейти к содержанию
    

LPC11xx не стартует код из своего бутлоадера

Работает только если в "рабочей программе" не используются прерывания. Если прерывания используются, то "Рабоча программа" нивкакую не стартует.

Какие есть догадки, в чем ошибка?

Попробуйте по-другому.

Например так:

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();

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Т.к. у 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 по которому лежит обычная таблица прерываний.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот код бутлоадера:
Для вставки кода в сообщения есть кнопочка rte-code-button.png на форме ввода. Используйте ее, пожалуйста. Здесь так принято.

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) Та часть ОЗУ, куда вы пишете, у вас зарезервирована? Т.е. не получается ли так, что вы копируя разрушаете данные или стек загрузчика?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Работает только если в "рабочей программе" не используются прерывания. Если прерывания используются, то "Рабоча программа" нивкакую не стартует.

Какие есть догадки, в чем ошибка?

Такая догадка: в рабочей программе происходит очистка памяти, в которой находятся адреса обработчиков прерываний.

Проверьте на входе в main рабочей программы что у вас по адресам ОЗУ 0x10000000-0x100000C0? Заполнена эта область нулями или там адреса обработчиков?

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

 

нивкакую не стартует.

Какие есть догадки, в чем ошибка?

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

В HardFault не попадает?

 

P.S. Выложили бы проекты целиком - программа это не только текст.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Наметился небольшой прогресс))

В "загрузчике" копирую из флеша ячейки 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Еще один вопрос:

Используемый МК - lpc11c24 с "железным" протоколом CAN. В рабочей программе он используется.

В мануале на МК написано:

 

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

 

 

 

Значит ремап не решение.

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

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

 

В любом случае хранить вектора прерываний в ОЗУ для данного контроллера не очень хорошее решение!

Я уже привел метод - он прекрасно работает! http://electronix.ru/forum/index.php?s=&am...t&p=1095595

Можно использовать метод еще тупее - в бутлоадере создать обработчик на каждое прерывание (для M0 их не так много) который просто берет указатель из таблицы прерываний приложения и переходит по нему. (собственно говоря приведенный исходник это и делает, но что бы не плодить функции он узнает номер из регистра).

 

При этом приложения с бутлоадером и без бутлоадера отличаются только icf файлом! (началом флеша) и никаких ограничений на использования памяти нет.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

и затем прыгаю по адресу Reset_handler(0х1000 0004).
А вот неверно - вы прыгаете на вектор сброса. А надо прыгать на адрес, которых хранится в этом векторе:

    void (**fptr)(void);
    fptr = (void (**)(void))0x10000004;
    (*fptr)();

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если вы используете функции 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-овский проект.

 

 

Сработает?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сработает?
Нет. для этой программы main будет константой, она понятия не имеет, что в другой программе есть свой main и никаким образом не может получить его адрес. Можно взводить и анализировать какой-то флаг.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нет. для этой программы 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....?

Их тупо проэкстернили, но они нигде не инициализируются

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

В каждый проект(загрузчик и рабочая программа) добавляет один и тот же файл (Handlers.h), в котором написаны обработчики прерываний которые отправляют по адресам 0х0000 - 0х00С0, если они вызваны из загрузчика и по адресам 0х2000 - 0х20С), если они вызваны из рабочей программы. По идее нужно просто переделать стартап файл, чтобы из него при всех прерываниях прыгать в мои самописные обработчики прерываний.

Но он меня пока вводит в тупик - своими экстернами и импортами нигде не объявленных переменных

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я думаю написать обработчики для каждого прерывания с двумя вариантами выбора:

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

 

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

 

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

 

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);
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Используемый МК - lpc11c24 с "железным" протоколом CAN. В рабочей программе он используется.

В мануале на МК написано:

 

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

Значит ремап не решение.

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

Almaz1988, а в буте CAN используется?

Если не используется, то может можно сделать наоборот:

бут располагается где нибудь в конце памяти, и при старте ремапит вектора в ОЗУ, а основная программа работает с векторами расположенными во flash.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Продолжаю штурм))

и в загрузчике и в рабочей программе будут использоваться прерывания: 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();//иначе обработчик прерывания вызван из загрузчика
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...