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

 
 
5 страниц V  « < 2 3 4 5 >  
Reply to this topicStart new topic
> LPC11xx не стартует код из своего бутлоадера
Almaz1988
сообщение Oct 1 2012, 11:36
Сообщение #46


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

Группа: Участник
Сообщений: 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
Almaz1988
сообщение Oct 1 2012, 11:36
Сообщение #47


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

Группа: Участник
Сообщений: 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
Almaz1988
сообщение Oct 1 2012, 11:36
Сообщение #48


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

Группа: Участник
Сообщений: 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
Almaz1988
сообщение Oct 1 2012, 11:38
Сообщение #49


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

Группа: Участник
Сообщений: 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
Almaz1988
сообщение Oct 2 2012, 06:09
Сообщение #50


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

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



Добил бутлоадер)))
В бутлоадере использую только CAN-прерывания:
Код
__ASM void CAN_IRQHandler_of_application(void)
{
    ldr r0, =0x2074
    ldr r0, [r0]
    bx r0
}

void CAN_IRQHandler(void)
{
    if ( *(uint32_t *)0x100001F0 == 0x67 )
    {
        CAN_IRQHandler_of_application( );
    }
    else
    {
        (*rom)->pCAND->isr();
    }
}


Значение 0х67 в ячейку 0x100001F0 записывает рабочая программа при запуске (в своем main()):
Код
    uint32_t *ram_vector_table;
    ram_vector_table=(uint32_t *)0x100001F0;
    *ram_vector_table = 0x67;


Как оказалось ничего сложного, если разобраться)))
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 2 2012, 06:31
Сообщение #51


Гуру
******

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



QUOTE (Almaz1988 @ Oct 2 2012, 09:09) *
Как оказалось ничего сложного, если разобраться)))

Еще чуть-чуть и можно избавиться от тяжелого наследия (ассемблера) совсем:

CODE
void CAN_IRQHandler(void)
{
    if ( *(uint32_t *)0x100001F0 == 0x67 )
    {
        void(**CAN_IRQHandler_of_application)() = (void(**)())0x2074;
        (*CAN_IRQHandler_of_application)( );
    }
    else
    {
        (*rom)->pCAND->isr();
    }
}


P.S. c меткой main все же не получилось? wink.gif


--------------------
На любой вопрос даю любой ответ
"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
alx2
сообщение Oct 2 2012, 10:16
Сообщение #52


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Кажется, без ответа остался этот вопрос:
Цитата(Almaz1988 @ Sep 28 2012, 14:06) *
Откуда в Кейловском варианте берется __main, а в LPC-шном _etext, _data, _edata....?
Их тупо проэкстернили, но они нигде не инициализируются

Судя по названиям, символы _etext, _data, _edata и т.п. определены в скрипте линкера и обозначают:
_etext - конец секции .text;
_data - начало секции .data;
_edata - конец секции .data;
_bss - начало секции .bss;
_ebss - конец секции .bss.


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Oct 5 2012, 10:07
Сообщение #53


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

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



Дело близится к завершению))

"Программный загрузчик" при запуске слушает сеть, определяет есть ли устройства которые требуют обновления прошивки. Если таких нет передает управление "Рабочей программе". Если есть, то переводит это устройство в режим аппаратного загрузчика (заводской бутлоадер) и прошивает его.
Дальше по идее нужно перезапустить прошитое устройство. Для этого у аппаратного загрузчика предусмотрена команда "GO". Но, она позволяет прыгать только по адресам кратным 0х10! А Reset_handler у меня находится по адресу, не кратному 0х10. Т.е. сейчас он у меня по адресу 0x01ad. Прыгнуть в него командой аппаратного загрузчика "GO" я смогу, только если он будет по адресу, например, 0x1b0.

Keil позволяет использовать атрибут __attribute__((at(0x10000))) расположения переменных по конкретному адресу, но, к сожалению на функции этот атрибут не распростаняется. Откусывать память в линкере могу только кусками кратными 4 байтам, что не выручает.

Есть ли другой способ "подвинуть" Reset_handler в памяти МК?
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Oct 5 2012, 13:23
Сообщение #54


Гуру
******

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



Цитата(Almaz1988 @ Oct 5 2012, 13:07) *
"Программный загрузчик" при запуске слушает сеть, определяет есть ли устройства которые требуют обновления прошивки. Если таких нет передает управление "Рабочей программе". Если есть, то переводит это устройство в режим аппаратного загрузчика (заводской бутлоадер) и прошивает его.

Не понимаю, зачем переводить устройство в режим заводского загрузчика, если есть свой?

Цитата(Almaz1988 @ Oct 5 2012, 13:07) *
Дальше по идее нужно перезапустить прошитое устройство. Для этого у аппаратного загрузчика предусмотрена команда "GO". Но, она позволяет прыгать только по адресам кратным 0х10! А Reset_handler у меня находится по адресу, не кратному 0х10. Т.е. сейчас он у меня по адресу 0x01ad. Прыгнуть в него командой аппаратного загрузчика "GO" я смогу, только если он будет по адресу, например, 0x1b0.

Опять же зачем использовать Go и тп. Не проще ли подать буту команду reset и он запустит Reset_Handler по какому надо адресу, не глядя на выравнивание.

Цитата(Almaz1988 @ Oct 5 2012, 13:07) *
А Reset_handler у меня находится по адресу, не кратному 0х10. Т.е. сейчас он у меня по адресу 0x01ad.

Это Reset_Handler бута или приложения?

Цитата(Almaz1988 @ Oct 5 2012, 13:07) *
Keil позволяет использовать атрибут __attribute__((at(0x10000))) расположения переменных по конкретному адресу, но, к сожалению на функции этот атрибут не распростаняется. Откусывать память в линкере могу только кусками кратными 4 байтам, что не выручает.

Раз можно кратными по 4 байта, то можно и кратно 16 байтам откусывуть.
Go to the top of the page
 
+Quote Post
igor_mmm
сообщение Oct 6 2012, 19:07
Сообщение #55





Группа: Новичок
Сообщений: 7
Регистрация: 3-10-12
Пользователь №: 73 792



Добрый День!
Использую 11с24 и работаю с CAN.
Необходимо организовать выдачу без подтверждения приема. То есть на приемной стороне может отсутствовать приемник.
Смотрю пример "CAN on_chip" из примеров KEIL.

msg_obj.msgobj = 1;
msg_obj.mode_id = 0x123 ;
msg_obj.mask = 0xff;
msg_obj.dlc = 5;
msg_obj.data[0] = 'T';
msg_obj.data[1] = 'E';
msg_obj.data[2] = 'S'; //0x53
msg_obj.data[3] = 'T'; //0x54
(*rom)->pCAND->can_transmit(&msg_obj);

Что нужно добавить?

Go to the top of the page
 
+Quote Post
KRS
сообщение Oct 6 2012, 20:13
Сообщение #56


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

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



Цитата(igor_mmm @ Oct 6 2012, 23:07) *
Необходимо организовать выдачу без подтверждения приема. То есть на приемной стороне может отсутствовать приемник.

Если в сети только одно устройство (ACK выставить некому) то передатчик будет отправлять сообщение заново и увеличивать счетчик ошибок (пока не дойдет до ERROR PASSIVE), потом просто будет передавать пока не остановишь принудительно или не появится второе устройство.

Если реально надо выдавать разные фреймы (хотя принимать их все равно не кому) Надо сделать Disable Automatic Retransmission, тогда попытка отправки будет тольо одна! Или надо отменять посылку потом.
Go to the top of the page
 
+Quote Post
igor_mmm
сообщение Oct 7 2012, 07:29
Сообщение #57





Группа: Новичок
Сообщений: 7
Регистрация: 3-10-12
Пользователь №: 73 792



Цитата(KRS @ Oct 7 2012, 00:13) *
Если в сети только одно устройство (ACK выставить некому) то передатчик будет отправлять сообщение заново и увеличивать счетчик ошибок (пока не дойдет до ERROR PASSIVE), потом просто будет передавать пока не остановишь принудительно или не появится второе устройство.

Если реально надо выдавать разные фреймы (хотя принимать их все равно не кому) Надо сделать Disable Automatic Retransmission, тогда попытка отправки будет тольо одна! Или надо отменять посылку потом.


Сделал DAR. Сначала долго не работало, я засылал посылку один раз и после инициализации
типа так
Код
(*rom)->pCAND->can_transmit(&msg_obj); //послать один раз
while (1);   // бесконечный цикл.

а теперь сделал
Код
while(1)
{
     i++;
     if(i>1000000)
     {
      i=0;
      /* Send a simple CAN message */
      msg_obj.msgobj  = 0;
      msg_obj.mode_id = 0x500;
      msg_obj.mask    = 0x0;
      msg_obj.dlc     = 5;
      msg_obj.data[0] = 'T';    //0x54
      msg_obj.data[1] = 'E';    //0x45
      msg_obj.data[2] = 'S';    //0x53
      msg_obj.data[3] = 'T';    //0x54
      msg_obj.data[4] = 1;
      (*rom)->pCAND->can_transmit(&msg_obj);
   }
}

стало посылать с некой периодичностью.
не понял почему но повторная посылка заработала
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Oct 8 2012, 04:11
Сообщение #58


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

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



Цитата(igor_mmm @ Oct 6 2012, 22:07) *
Добрый День!
Использую 11с24 и работаю с CAN.
Необходимо организовать выдачу без подтверждения приема. То есть на приемной стороне может отсутствовать приемник.
Смотрю пример "CAN on_chip" из примеров KEIL.

msg_obj.msgobj = 1;
msg_obj.mode_id = 0x123 ;
msg_obj.mask = 0xff;
msg_obj.dlc = 5;
msg_obj.data[0] = 'T';
msg_obj.data[1] = 'E';
msg_obj.data[2] = 'S'; //0x53
msg_obj.data[3] = 'T'; //0x54
(*rom)->pCAND->can_transmit(&msg_obj);

Что нужно добавить?


Вот как выглядит моя функция отправки 4-ехбайтового сообщения:

Код
void CANsend4byte(uint32_t ID, uint32_t DATA )                
{
    CAN_MSG_OBJ msg_obj_transmit;
    msg_obj_transmit.msgobj  = 0;        
    msg_obj_transmit.mode_id = ID;
    msg_obj_transmit.mask    = 0x0;
    msg_obj_transmit.dlc     = 4;                            
    msg_obj_transmit.data[0] = DATA;                        
    msg_obj_transmit.data[1] = DATA>>8;
    msg_obj_transmit.data[2] = DATA>>16;
    msg_obj_transmit.data[3] = DATA>>24;
    while (flagMessageTransmitted != 1);    
    (*rom)->pCAND->can_transmit(&msg_obj_transmit);
    flagMessageTransmitted = 0;
}

Она рабочая

Убираешь строчку
Код
while (flagMessageTransmitted != 1);

Если подтверждение не требуется
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Oct 8 2012, 06:05
Сообщение #59


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

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



Вопрос по примеру "NXP secondary bootloader" (документ AN10995).
Программный бутлоадер под конец загрузки новой прошивки во флеш в последнюю ячейку флеша записывает контрольную сумму.
В последующем при всяком запуске микронотроллера он вычисляет действительную контрольную сумму флеш-памяти и значение, которое записано в последней ячейке флеша. Если они совпадают, то рабочая программа корректна и программный загрузчик передает управление рабочей программе.
А как быть если рабочая программа заливается не с помощью программного бутлоадера, а программатором с компа. В этом случае контрольная сумма не записывается и программный бутлоадер посчитает, что рабочая программа битая. Как быть?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 8 2012, 06:34
Сообщение #60


Гуру
******

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



QUOTE (Almaz1988 @ Oct 8 2012, 09:05) *
Как быть?
Посчитать ее при помощи какой-либо внешней утилиты и добавить той же или другой утилитой в прошиваемый программатором файл. Но не совсем красиво хранить контрольную сумму в последней ячейке флеша. По двум причинам:
1) Вне зависимости от реального размера приложения загрузчик вынужден обсчитывать всю флеш, а это время.
2) При очередном обновлении может захотеться добавить эмуляцию eeprom в последнюю страницу флеша, а эта область уже защищена CRC.
Поэтому я делаю так: в первую же ячейку сразу за векторами линкер записывает размер приложения. CRC кладется сразу же следом за приложением. Загрузчик знает, в какой ячейке лежит размер и считает CRC только реально занятой области флеша.
Поскольку у LPC11 перед ремапом вектора копируются и им не обязательно начинаться с адреса, кратного 256 - можно размер хранить перед векторами.


--------------------
На любой вопрос даю любой ответ
"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

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

 


RSS Текстовая версия Сейчас: 26th July 2025 - 00:10
Рейтинг@Mail.ru


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