|
bootloader для Atmega48 |
|
|
|
Jun 27 2009, 21:47
|
Участник

Группа: Участник
Сообщений: 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
|
|
|
|
|
Jun 28 2009, 06:24
|
Участник

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

|
Ещё вот такой вопрос. У нас нет фуза для перехода при сбросе в секцию бутлоадера. И может возникнуть ситуация, я начал менять память, не успел поменять до конца и тут выключили свет. Прошивка основной программы не корректная. Теперь она не пройдет по пустой памяти выполняя опкод 0xFFFF. Есть хоть какие-то решения какие обезопасивают хоть минимально от этого случая?
|
|
|
|
|
Jun 28 2009, 13:29
|
Частый гость
 
Группа: Участник
Сообщений: 149
Регистрация: 2-06-08
Из: Москва
Пользователь №: 38 003

|
Цитата(piz2383 @ Jun 28 2009, 10:24)  Ещё вот такой вопрос ... Есть хоть какие-то решения какие обезопасивают хоть минимально от этого случая? Наверное, лучше будет в нулевом адресе ПЗУ сразу поместить переход на бутлоадер, который по каким-либо признакам будет определять правильность прошивки, и затем либо передавать управление ей, либо сигнализировать о неправильной прошивке и ждать загрузки новой программы. Однако, размещение подобного перехода нельзя считать абсолютной панацеей, плюс нужно будет сделать так, чтобы при загрузке новой программы бутлоадер не перезаписывал вектор сброса, т. е. не заменял переход на бутлоадер.
|
|
|
|
|
Jun 29 2009, 00:02
|
Участник

Группа: Участник
Сообщений: 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 не попадали?
|
|
|
|
|
Jun 29 2009, 08:14
|

Чайник, 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
|
|
|
|
|
Jun 29 2009, 09:35
|
Участник

Группа: Участник
Сообщений: 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 просто причина в чем-то есть. Конечно так догадаться тяжело, но возможные предположения есть?
|
|
|
|
|
Jun 29 2009, 10:32
|

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 просто причина в чем-то есть. Конечно так догадаться тяжело, но возможные предположения есть? А симулятором проверяли куда переходит основная программа ?
--------------------
Все может быть и быть все может, и лишь того не может быть-чего уж точно быть не может, хотя..и это может быть.
|
|
|
|
|
Jun 29 2009, 10:55
|
Участник

Группа: Участник
Сообщений: 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-сячный адрес.
|
|
|
|
|
Jun 29 2009, 10:57
|

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

|
Цитата(piz2383 @ Jun 29 2009, 13:35)  ...и так и так есть пустое пространство между основной программой и бутом, но естевственно при D00 её чуть больше. Не пустое пространство ищите, а проверьте что по нужному адресу оно. -- UPD: Цитата(piz2383 @ Jun 29 2009, 14:55)  Но вот если прошиваю для прошивки размером 2,5 килобайт, все работать начинает некорректно... А вот это уже другой вопрос.. перед вызовом загрузчика запретите прерывания хотя бы.
|
|
|
|
|
Jun 30 2009, 04:55
|

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. Вот в этом и ошибка.
--------------------
Все может быть и быть все может, и лишь того не может быть-чего уж точно быть не может, хотя..и это может быть.
|
|
|
|
|
Jul 6 2009, 05:43
|
Частый гость
 
Группа: Участник
Сообщений: 80
Регистрация: 3-07-09
Пользователь №: 50 897

|
Цитата(smac @ Jun 28 2009, 16:29)  Наверное, лучше будет в нулевом адресе ПЗУ сразу поместить переход на бутлоадер, который по каким-либо признакам будет определять правильность прошивки, и затем либо передавать управление ей, либо сигнализировать о неправильной прошивке и ждать загрузки новой программы. Однако, размещение подобного перехода нельзя считать абсолютной панацеей, плюс нужно будет сделать так, чтобы при загрузке новой программы бутлоадер не перезаписывал вектор сброса, т. е. не заменял переход на бутлоадер. Мне вот кажеться что проще было бы сделать, что бы бутлоадер разместить по нулевому адрессу, а уже рабочую программу по какому-то другому. Не нужно будет заботиться ни о каких векторах сброса, программа будет стартовать всегда с бутлоадера. Ну и тогда настройки линкера "BOOTLOADER_ADDRESS = 0x00С00 и LDFLAGS += -Wl,--section-start=.text=$(BOOTLOADER_ADDRESS)" нужно будет применить именно к своей рабочей программе, это будет наверное единственное ограничение. Ну или же код написать так, что бы все переходы были относителными
|
|
|
|
|
Jul 6 2009, 07:19
|

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