|
|
  |
LPC11xx не стартует код из своего бутлоадера |
|
|
|
Oct 1 2012, 11:36
|
Частый гость
 
Группа: Участник
Сообщений: 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();//иначе обработчик прерывания вызван из загрузчика }
|
|
|
|
|
Oct 1 2012, 11:36
|
Частый гость
 
Группа: Участник
Сообщений: 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();//иначе обработчик прерывания вызван из загрузчика }
|
|
|
|
|
Oct 1 2012, 11:36
|
Частый гость
 
Группа: Участник
Сообщений: 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();//иначе обработчик прерывания вызван из загрузчика }
|
|
|
|
|
Oct 1 2012, 11:38
|
Частый гость
 
Группа: Участник
Сообщений: 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();//иначе обработчик прерывания вызван из загрузчика }
|
|
|
|
|
Oct 2 2012, 06:09
|
Частый гость
 
Группа: Участник
Сообщений: 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; Как оказалось ничего сложного, если разобраться)))
|
|
|
|
|
Oct 2 2012, 06:31
|

Гуру
     
Группа: Модераторы
Сообщений: 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 все же не получилось?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 2 2012, 10:16
|

Местный
  
Группа: Участник
Сообщений: 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
|
|
|
|
|
Oct 5 2012, 10:07
|
Частый гость
 
Группа: Участник
Сообщений: 100
Регистрация: 19-09-12
Пользователь №: 73 602

|
Дело близится к завершению))
"Программный загрузчик" при запуске слушает сеть, определяет есть ли устройства которые требуют обновления прошивки. Если таких нет передает управление "Рабочей программе". Если есть, то переводит это устройство в режим аппаратного загрузчика (заводской бутлоадер) и прошивает его. Дальше по идее нужно перезапустить прошитое устройство. Для этого у аппаратного загрузчика предусмотрена команда "GO". Но, она позволяет прыгать только по адресам кратным 0х10! А Reset_handler у меня находится по адресу, не кратному 0х10. Т.е. сейчас он у меня по адресу 0x01ad. Прыгнуть в него командой аппаратного загрузчика "GO" я смогу, только если он будет по адресу, например, 0x1b0.
Keil позволяет использовать атрибут __attribute__((at(0x10000))) расположения переменных по конкретному адресу, но, к сожалению на функции этот атрибут не распростаняется. Откусывать память в линкере могу только кусками кратными 4 байтам, что не выручает.
Есть ли другой способ "подвинуть" Reset_handler в памяти МК?
|
|
|
|
|
Oct 5 2012, 13:23
|
Гуру
     
Группа: Свой
Сообщений: 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 байтам откусывуть.
|
|
|
|
|
Oct 6 2012, 19:07
|
Группа: Новичок
Сообщений: 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);
Что нужно добавить?
|
|
|
|
|
Oct 7 2012, 07:29
|
Группа: Новичок
Сообщений: 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); } } стало посылать с некой периодичностью. не понял почему но повторная посылка заработала
|
|
|
|
|
Oct 8 2012, 04:11
|
Частый гость
 
Группа: Участник
Сообщений: 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); Если подтверждение не требуется
|
|
|
|
|
Oct 8 2012, 06:34
|

Гуру
     
Группа: Модераторы
Сообщений: 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)
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|