Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: LPC11xx не стартует код из своего бутлоадера
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2
Сергей Борщ
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
alx2
Кажется, без ответа остался этот вопрос:
Цитата(Almaz1988 @ Sep 28 2012, 14:06) *
Откуда в Кейловском варианте берется __main, а в LPC-шном _etext, _data, _edata....?
Их тупо проэкстернили, но они нигде не инициализируются

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

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

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

Есть ли другой способ "подвинуть" Reset_handler в памяти МК?
_Артём_
Цитата(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 байтам откусывуть.
igor_mmm
Добрый День!
Использую 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);

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

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

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

Если реально надо выдавать разные фреймы (хотя принимать их все равно не кому) Надо сделать Disable Automatic Retransmission, тогда попытка отправки будет тольо одна! Или надо отменять посылку потом.
igor_mmm
Цитата(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);
   }
}

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

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

Так и сделал, тем более и Keil рекомендует такое решение.

Цитата
Поэтому я делаю так: в первую же ячейку сразу за векторами линкер записывает размер приложения. CRC кладется сразу же следом за приложением.

Как вы это проделываете? Скаттер файл изменяете?

Получается у вас контрольная сумма записывается не в последнюю очередь? Для максимальной надежности механизма логично писать ее в последнюю очередь.
Сергей Борщ
QUOTE (Almaz1988 @ Oct 8 2012, 12:28) *
Как вы это проделываете? Скаттер файл изменяете?
Я использую gcc и делаю это через его скрипт линкера. В Кейле, насколько мне известно, такую функцию выполняет скаттер-файл. Значит менять надо его, да.
QUOTE (Almaz1988 @ Oct 8 2012, 12:28) *
Получается у вас контрольная сумма записывается не в последнюю очередь?
Почему вы так решили? В скрипте линкера под контрольную сумму выделается место после кода и данных, после линковки контрольная сумма вписывается в это зарезервированное место сторонней утилитой.
Almaz1988
В общем осталась последняя проблема.
Есть функция Х( ). В МАР-файле она расположена по адресам 0х00000175 - 0х00000189.
Когда я прыгаю в ячейку 0х00000175, вызывается эта функция:
Код
    void (*fptr)(void);
    fptr = (void (*)(void))0x00000175;
    fptr();



Копирую эти адреса в оперативку по адресу начиная с 0х10000300. Эта область "откушена" в настройках проекта и она не затирается при работе. Дебагером смотрю - скопирована точь-в-точь и не затирается.
Но когда прыгаю по адресу 0х10000300. Эта функция не вызывается.
Что я не учел?
Сергей Борщ
QUOTE (Almaz1988 @ Oct 8 2012, 14:45) *
Что я не учел?
Надо пошагать в отладчике. Версии есть, но излагать их довольно долго (предполагаю, дело в способах адресации внутри функции). Попробуйте поискать в документации ключевое слово ramfunc или похожее на него - оно как раз для этих целей.
igor_mmm
Цитата(Almaz1988 @ Oct 8 2012, 08:11) *
Вот как выглядит моя функция отправки 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);

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


а где взять переменную "flagMessageTransmitte" и кто ее выставляет
я так понимаю кто то в прерывании эту переменную выставляет 1
покажите весь пример пожалуйста
Almaz1988
Цитата(igor_mmm @ Oct 9 2012, 06:21) *
а где взять переменную "flagMessageTransmitte" и кто ее выставляет
я так понимаю кто то в прерывании эту переменную выставляет 1
покажите весь пример пожалуйста


В прерывании CAN_TX, которое вызывается автоматически всякий раз при успешной отправке сообщения.
В примере устройство каждые 0.5 сек шлет хартбит.
Отправь SDO-запрос: 0х601 40 00 10 00 00 00 00 00, оно откликнется сообщением с ид-ром 0х581.
Отправь любое сообщение с ид-ром меньше - 0х600 загорится светодиод на выводе 2.1
igor_mmm
Цитата(Almaz1988 @ Oct 9 2012, 08:24) *
В прерывании CAN_TX, которое вызывается автоматически всякий раз при успешной отправке сообщения.
В примере устройство каждые 0.5 сек шлет хартбит.
Отправь SDO-запрос: 0х601 40 00 10 00 00 00 00 00, оно откликнется сообщением с ид-ром 0х581.
Отправь любое сообщение с ид-ром меньше - 0х600 загорится светодиод на выводе 2.1

добрый день!
я смотрю пример и вижу , что вы отправляете сообщение через промежутки времени. при "удачной" передаче заходите в прерывание и выставляете флаг - понятно.
Но как быть если передача тыла так сказать неудачная (датчик отвалился) (ведущим так сказать в моем случае будет контроллер lpc ). Он (контроллер) будет пытаться отослать посылку повторно.
Я сделал так перед передачей выставил флаг "DAR" - отключение повторной передачи и выдаю раз в секунду. контроллер зараза первый 16 секунд не выдает (либо выдает но прерывается но пол посылки потому что не видит датчика ) а потом начинает успешно выдавать раз в секунду.
бит DAR - это как я понял отключение повторной передачи. а мне нужно что бы при отсутствии датчика посылка отправилась и только один раз.
== как это сделать я не знаю ===.
в принципе прерывание может возникнуть и при неправильной передаче это можно распознать но как потом отключить передачу (те есть очистить буфер)
Almaz1988
Цитата(Сергей Борщ @ Oct 8 2012, 14:57) *
Надо пошагать в отладчике. Версии есть, но излагать их довольно долго (предполагаю, дело в способах адресации внутри функции). Попробуйте поискать в документации ключевое слово ramfunc или похожее на него - оно как раз для этих целей.

Разобрался в чем дело: Если копирую функцию из флеша в ОЗУ, она не запускается. Если изначально "говорю" линкеру расположить функцию в ОЗУ она старутет нормально. Видимо дело в использовании абсолютной адресации в ассемблерном коде функций
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.