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

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> bootloader для Atmega48
piz2383
сообщение Jun 27 2009, 21:47
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 43
Регистрация: 26-06-09
Пользователь №: 50 675



Есть плата с Atmega48. Необходимо по приходу соответствующей команды из вне, в моем случае по SPI произвести обновление кода.
В Atmega48 нет секции бутлоадера и нет фуза для перехода при сбросе в эту секцию, поэтому как я понимаю секцию в этом контроллере необходимо создавать искусственно программным путем.
С этим я сталкиваюсь впервые. Я только, что перечитал апноуты, темы на нашем форуме и в голове у меня обрисовался общий алгоритм решения моей проблемы. Сейчас я озвучу его, а вы если вам не трудно укажите где я говорю не правильно, ну в целом выскажите любые замечания.

В общем "загрузчик" создаю отдельным проектом. В мейк-файле к этому проекту дописываю две строчки: BOOTLOADER_ADDRESS = 0x00С00 и LDFLAGS += -Wl,--section-start=.text=$(BOOTLOADER_ADDRESS)

Я правильно выбрал адрес? 0x00С00? Как я понял в атмеге48 4 килобайта памяти, поэтому под бутлоадер можно отнести килобайт в конце этой памяти.

Итак далее. Моя основная программа работает, и по интерфейсу SPI получает ту самую команду перепрошивки. Я в коде своей программы пишу следующее:
void (*funboot)( void ) = 0x0C00;
funboot();

так я попадаю в бутлоадер. В теле программы бутлоадера я принимаю данные по SPI и с помощью команд SPM перепрошиваю программу, параллельно проверяя чексум, если все хорошо, то допустим бутяю с помощью собаки или просто перехожу по нулевому адрес.

Тоесть первый раз, я проект бутлоадера прошиваю по адрессу 0xC00. Далее я прошиваю программатором первую версию моей программы по нулевому адресу, в которой заложен механизм перехода по адрессу бутлоадера. Затем новые прошивки которые будут поступать тоже будут с этим механизмом.

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

Заранее благодарен за помощь.

Сообщение отредактировал piz2383 - Jun 27 2009, 21:51
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jun 27 2009, 23:32
Сообщение #2


Гуру
******

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



Да, все совершенно правильно. Первую рабочую программу необязательно зашивать программатором. После прошивки загрузчика контроллер стартанет, пройдет по пустой памяти выполняя опкод 0xFFFF (это что-то безобидное наподобие nop) и сам добежит до адреса 0xC00.


--------------------
На любой вопрос даю любой ответ
"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
piz2383
сообщение Jun 28 2009, 06:24
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 43
Регистрация: 26-06-09
Пользователь №: 50 675



Ещё вот такой вопрос. У нас нет фуза для перехода при сбросе в секцию бутлоадера. И может возникнуть ситуация, я начал менять память, не успел поменять до конца и тут выключили свет. Прошивка основной программы не корректная. Теперь она не пройдет по пустой памяти выполняя опкод 0xFFFF. Есть хоть какие-то решения какие обезопасивают хоть минимально от этого случая?
Go to the top of the page
 
+Quote Post
smac
сообщение Jun 28 2009, 13:29
Сообщение #4


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

Группа: Участник
Сообщений: 149
Регистрация: 2-06-08
Из: Москва
Пользователь №: 38 003



Цитата(piz2383 @ Jun 28 2009, 10:24) *
Ещё вот такой вопрос ... Есть хоть какие-то решения какие обезопасивают хоть минимально от этого случая?

Наверное, лучше будет в нулевом адресе ПЗУ сразу поместить переход на бутлоадер, который по каким-либо признакам будет определять правильность прошивки, и затем либо передавать управление ей, либо сигнализировать о неправильной прошивке и ждать загрузки новой программы. Однако, размещение подобного перехода нельзя считать абсолютной панацеей, плюс нужно будет сделать так, чтобы при загрузке новой программы бутлоадер не перезаписывал вектор сброса, т. е. не заменял переход на бутлоадер.
Go to the top of the page
 
+Quote Post
piz2383
сообщение Jun 29 2009, 00:02
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 43
Регистрация: 26-06-09
Пользователь №: 50 675



В общем начал реализовывать все выше сказанное... Начал с простого.
Написал программу которая инициализирует UART, и просто отправляет пять байт. далее:
void (*funcptr)( void ) = 0x0000;
funcptr();

Разместил код по адрессу 0xC00. Прошил.
В основной программе размер, которой 2,5 килобайт, в определенном месте сделал аналогичное.
void (*funcptr)( void ) = 0x0C00;
funcptr();

Прошил, запустил не работает. Танцевал, танцевал с бубном. Выяснил что если заменить C00 на D00. То резко все начинает работать. В полтергейсты я не верю, на это должна быть какая-то причина. Не подскажите в чем может быть данная причина?

И ещё хочу задать вопрос по поводу WINAVR. В общем я реализовал к примеру библиотеку UART. Там много функций, и некоторые из них в проекте не используются. Но все равно они компиляться, линкуються и попадают в проект, при этом занимают место. Никак не мог найти ключ, который бы это отключал. Не подскажите что нужно прописать в makefile что бы не используемые функции в выходной hex не попадали?
Go to the top of the page
 
+Quote Post
SysRq
сообщение Jun 29 2009, 08:14
Сообщение #6


Чайник, 1 литр
****

Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168



Цитата(piz2383 @ Jun 29 2009, 04:02) *
В полтергейсты я не верю, на это должна быть какая-то причина.
Считайте программатором целиком прошивку из МК, переведите из *.hex или почего в бинарный дамп (*.bin), посмотрите любым hex-редактром правильно ли расположены куски кода в памяти МК. Если с этим все в порядке, показывайте код, так проще будет.

Цитата(piz2383 @ Jun 29 2009, 04:02) *
...WINAVR. ...много функций, и некоторые из них в проекте не используются. Но все равно они компиляться, линкуються и попадают в проект, при этом занимают место. ...что нужно прописать в makefile что бы не используемые функции в выходной hex не попадали?
Здесь: http://electronix.ru/forum/index.php?showtopic=64145
Go to the top of the page
 
+Quote Post
piz2383
сообщение Jun 29 2009, 09:35
Сообщение #7


Участник
*

Группа: Участник
Сообщений: 43
Регистрация: 26-06-09
Пользователь №: 50 675



Цитата(SysRq @ Jun 29 2009, 11:14) *
Считайте программатором целиком прошивку из МК, переведите из *.hex или почего в бинарный дамп (*.bin), посмотрите любым hex-редактром правильно ли расположены куски кода в памяти МК. Если с этим все в порядке, показывайте код, так проще будет.

Дамп проверял, и так и так есть пустое пространство между основной программой и бутом, но естевственно при D00 её чуть больше. Вот код для бута.
Код
int main(void)
{
    UARTinit();
    UARTByte('B');
    UARTByte('O');
    UARTByte('O');
    UARTByte('T');    

    void (*funcptr)( void ) = 0x0000;
    funcptr();
    
    return 0;
}

Код для основной программы большой, в целом 2,5 килобайт прошивки, вот то место где происходит вызов
Код
// команда о перепрошивке
else if(SIGNAL == REPROGRAM)
{
   void (*funcptr)( void ) = 0x0D00; // или 0x0С00
   funcptr();
}

В общем при D00 как я и говори все отлично работает, в терминале появляется надпись "BOOT" и прошивка начинает работать со старта (я в начале вывожу надпись "START" этим и проверяю). Ну а ежели C00, то на экране ничего не появляется и прошивка далее уже работает некорректно.

Мне в принципе все-равно с C00 или D00 просто причина в чем-то есть. Конечно так догадаться тяжело, но возможные предположения есть?
Go to the top of the page
 
+Quote Post
dimka76
сообщение Jun 29 2009, 10:32
Сообщение #8


developer
****

Группа: Свой
Сообщений: 902
Регистрация: 12-04-06
Из: Казань
Пользователь №: 16 032



Цитата(piz2383 @ Jun 29 2009, 13:35) *
Код для основной программы большой, в целом 2,5 килобайт прошивки, вот то место где происходит вызов
Код
// команда о перепрошивке
else if(SIGNAL == REPROGRAM)
{
   void (*funcptr)( void ) = 0x0D00; // или 0x0С00
   funcptr();
}


Мне в принципе все-равно с C00 или D00 просто причина в чем-то есть. Конечно так догадаться тяжело, но возможные предположения есть?


А симулятором проверяли куда переходит основная программа ?


--------------------
Все может быть и быть все может, и лишь того не может быть-чего уж точно быть не может, хотя..и это может быть.
Go to the top of the page
 
+Quote Post
piz2383
сообщение Jun 29 2009, 10:55
Сообщение #9


Участник
*

Группа: Участник
Сообщений: 43
Регистрация: 26-06-09
Пользователь №: 50 675



В симуляторе все отлично. И главное если прошить две программы
Код
Первую вот такую
int main(void)
{
    UARTinit();
    UARTByte('S');
    UARTByte('T');
    UARTByte('A');
    UARTByte('R');    
    UARTByte('T');

    void (*funcptr)( void ) = 0x0С00;
    funcptr();
    
    return 0;
}

а вторую вот такую

int main(void)
{
    UARTinit();
    UARTByte('B');
    UARTByte('O');
    UARTByte('O');
    UARTByte('T');    

    void (*funcptr)( void ) = 0x0000;
    funcptr();
    
    return 0;
}

То все хорошо работает и для С00.
Но вот если прошиваю для прошивки размером 2,5 килобайт, все работать начинает некорректно и не пойму ведь почему, ведь C00 это 3000-сячный адрес.
Go to the top of the page
 
+Quote Post
SysRq
сообщение Jun 29 2009, 10:57
Сообщение #10


Чайник, 1 литр
****

Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168



Цитата(piz2383 @ Jun 29 2009, 13:35) *
...и так и так есть пустое пространство между основной программой и бутом, но естевственно при D00 её чуть больше.
Не пустое пространство ищите, а проверьте что по нужному адресу оно.

--
UPD:

Цитата(piz2383 @ Jun 29 2009, 14:55) *
Но вот если прошиваю для прошивки размером 2,5 килобайт, все работать начинает некорректно...
А вот это уже другой вопрос.. перед вызовом загрузчика запретите прерывания хотя бы.
Go to the top of the page
 
+Quote Post
dimka76
сообщение Jun 30 2009, 04:55
Сообщение #11


developer
****

Группа: Свой
Сообщений: 902
Регистрация: 12-04-06
Из: Казань
Пользователь №: 16 032



Цитата(piz2383 @ Jun 29 2009, 14:55) *
То все хорошо работает и для С00.
Но вот если прошиваю для прошивки размером 2,5 килобайт, все работать начинает некорректно и не пойму ведь почему, ведь C00 это 3000-сячный адрес.


Дело в том, что ширина шины данных памяти программ составляет 16 бит.
В hex файле все данные восьмибитные. Размер памяти mega48 2048 слов, что в байтах равно 4096 байт.
Линкеру вы правильно указываете адрес 0хС00. Но когда присваиваете значение
Код
void (*funcptr)( void ) = 0x0С00;

то должны указать адрес слова, а не байта. Т.е. 0x0C00 / 2 = 0x0600.
Вот в этом и ошибка.


--------------------
Все может быть и быть все может, и лишь того не может быть-чего уж точно быть не может, хотя..и это может быть.
Go to the top of the page
 
+Quote Post
head_sk
сообщение Jul 6 2009, 05:43
Сообщение #12


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

Группа: Участник
Сообщений: 80
Регистрация: 3-07-09
Пользователь №: 50 897



Цитата(smac @ Jun 28 2009, 16:29) *
Наверное, лучше будет в нулевом адресе ПЗУ сразу поместить переход на бутлоадер, который по каким-либо признакам будет определять правильность прошивки, и затем либо передавать управление ей, либо сигнализировать о неправильной прошивке и ждать загрузки новой программы. Однако, размещение подобного перехода нельзя считать абсолютной панацеей, плюс нужно будет сделать так, чтобы при загрузке новой программы бутлоадер не перезаписывал вектор сброса, т. е. не заменял переход на бутлоадер.


Мне вот кажеться что проще было бы сделать, что бы бутлоадер разместить по нулевому адрессу, а уже рабочую программу по какому-то другому. Не нужно будет заботиться ни о каких векторах сброса, программа будет стартовать всегда с бутлоадера. Ну и тогда настройки линкера "BOOTLOADER_ADDRESS = 0x00С00 и LDFLAGS += -Wl,--section-start=.text=$(BOOTLOADER_ADDRESS)" нужно будет применить именно к своей рабочей программе, это будет наверное единственное ограничение. Ну или же код написать так, что бы все переходы были относителными smile.gif
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jul 6 2009, 07:19
Сообщение #13


Гуру
******

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



Цитата(head_sk @ Jul 6 2009, 08:43) *
Мне вот кажеться что проще было бы сделать, что бы бутлоадер разместить по нулевому адрессу, а уже рабочую программу по какому-то другому
К сожалению, в нулевых адресах располагаются вектора прерываний, которые нужны скорее приложению. Можно, конечно, поставить туда таблицу RJMP...


--------------------
На любой вопрос даю любой ответ
"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
head_sk
сообщение Jul 6 2009, 16:48
Сообщение #14


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

Группа: Участник
Сообщений: 80
Регистрация: 3-07-09
Пользователь №: 50 897



А почему нельзя просто таблицу векторов прерывания приложения скопировать в начальные адреса? Конечно кроме нулевого вектора smile.gif
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jul 6 2009, 18:25
Сообщение #15


Гуру
******

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



Цитата(head_sk @ Jul 6 2009, 19:48) *
А почему нельзя просто таблицу векторов прерывания приложения скопировать в начальные адреса? Конечно кроме нулевого вектора smile.gif
Что значит "скопировать"? На этапе компиляции загрузчика? Но приложение будет меняться и вектора будут указывать не туда. На этапе заливки приложения? Но это переписывание части загрузчика, а значит велика вероятность получить из-за сбоя полностью неработоспособное устройство. В ОЗУ таблицу держать нельзя - это не ARM.


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

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

 


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


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