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

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

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

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

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


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

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

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

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


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

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

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

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


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

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

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

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


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

Добил бутлоадер)))

В бутлоадере использую только 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;

 

Как оказалось ничего сложного, если разобраться)))

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


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

Как оказалось ничего сложного, если разобраться)))

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

 

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 все же не получилось? ;)

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


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

Кажется, без ответа остался этот вопрос:

Откуда в Кейловском варианте берется __main, а в LPC-шном _etext, _data, _edata....?

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

Судя по названиям, символы _etext, _data, _edata и т.п. определены в скрипте линкера и обозначают:

_etext - конец секции .text;

_data - начало секции .data;

_edata - конец секции .data;

_bss - начало секции .bss;

_ebss - конец секции .bss.

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


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

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

 

"Программный загрузчик" при запуске слушает сеть, определяет есть ли устройства которые требуют обновления прошивки. Если таких нет передает управление "Рабочей программе". Если есть, то переводит это устройство в режим аппаратного загрузчика (заводской бутлоадер) и прошивает его.

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

 

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

 

Есть ли другой способ "подвинуть" Reset_handler в памяти МК?

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


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

"Программный загрузчик" при запуске слушает сеть, определяет есть ли устройства которые требуют обновления прошивки. Если таких нет передает управление "Рабочей программе". Если есть, то переводит это устройство в режим аппаратного загрузчика (заводской бутлоадер) и прошивает его.

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

 

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

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

 

А Reset_handler у меня находится по адресу, не кратному 0х10. Т.е. сейчас он у меня по адресу 0x01ad.

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

 

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

Раз можно кратными по 4 байта, то можно и кратно 16 байтам откусывуть.

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


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

Добрый День!

Использую 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);

 

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

 

 

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


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

Необходимо организовать выдачу без подтверждения приема. То есть на приемной стороне может отсутствовать приемник.

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

 

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

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


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

Если в сети только одно устройство (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);
   }
}

стало посылать с некой периодичностью.

не понял почему но повторная посылка заработала

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


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

Добрый День!

Использую 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);

Если подтверждение не требуется

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


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

Вопрос по примеру "NXP secondary bootloader" (документ AN10995).

Программный бутлоадер под конец загрузки новой прошивки во флеш в последнюю ячейку флеша записывает контрольную сумму.

В последующем при всяком запуске микронотроллера он вычисляет действительную контрольную сумму флеш-памяти и значение, которое записано в последней ячейке флеша. Если они совпадают, то рабочая программа корректна и программный загрузчик передает управление рабочей программе.

А как быть если рабочая программа заливается не с помощью программного бутлоадера, а программатором с компа. В этом случае контрольная сумма не записывается и программный бутлоадер посчитает, что рабочая программа битая. Как быть?

 

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


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

Как быть?
Посчитать ее при помощи какой-либо внешней утилиты и добавить той же или другой утилитой в прошиваемый программатором файл. Но не совсем красиво хранить контрольную сумму в последней ячейке флеша. По двум причинам:

1) Вне зависимости от реального размера приложения загрузчик вынужден обсчитывать всю флеш, а это время.

2) При очередном обновлении может захотеться добавить эмуляцию eeprom в последнюю страницу флеша, а эта область уже защищена CRC.

Поэтому я делаю так: в первую же ячейку сразу за векторами линкер записывает размер приложения. CRC кладется сразу же следом за приложением. Загрузчик знает, в какой ячейке лежит размер и считает CRC только реально занятой области флеша.

Поскольку у LPC11 перед ремапом вектора копируются и им не обязательно начинаться с адреса, кратного 256 - можно размер хранить перед векторами.

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


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

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

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

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

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

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

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

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

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

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