|
|
  |
самописный бутлоадер для m128, самописный бутлоадер для m128 |
|
|
|
Dec 25 2013, 21:32
|
Участник

Группа: Участник
Сообщений: 27
Регистрация: 12-08-13
Пользователь №: 77 889

|
Доброго времени суток! После написания простенького бутлоадера на ассемблере для m8515 начал писать бутлоадер на си++ в atmel studio 6 для m128. До этого использовал stk500, теперь работаю с jtag ice. С си++ дела раньше не имел. Возник ряд вопросов. Не понимаю как перейти в область бутлоадера, для написания его части кода, пробовал "jmp адрес"" или объявлял "bootloader section;" но при пошаговой отладке по jtag просматривал память и не видел чтобы дальнейший код шел в области лоадера. Подскажите пожалуйста что может быть не так и как лучше осуществить этот переход. Или он произошел но не отображается? И еще подойдет ли boot_page_fill(address, data); для ввода данных в память а boot_page_erase ( address ) чтобы стирать страницы? Если можно бросьте какой нить образец или ссылку на ресурс где это обсуждается!
Заранее спасибо!
|
|
|
|
|
Dec 26 2013, 11:04
|

Профессионал
    
Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409

|
Простой поиск по форуму уже много чего даёт. Например: http://electronix.ru/forum/index.php?showt...=avr+bootloaderПоиск в яндексе (ну или в гугле - кому как удобно) тоже приносит свои результаты http://www.scienceprog.com/testing-avr-uni...r-on-atmega128/Для старта из секции загрузчика необходимо настроить фус-биты. Про это написано в документации. Atmega128 отличается от остальных тем, что у неё 128кБайт памяти, поэтому есть свои особенности в адресации страниц памяти, но об этом также можно узнать из примеров исходником или из документации.
|
|
|
|
|
Jan 9 2014, 21:12
|
Участник

Группа: Участник
Сообщений: 27
Регистрация: 12-08-13
Пользователь №: 77 889

|
Цитата(mempfis_ @ Dec 26 2013, 14:04)  Простой поиск по форуму уже много чего даёт. Например: http://electronix.ru/forum/index.php?showt...=avr+bootloaderПоиск в яндексе (ну или в гугле - кому как удобно) тоже приносит свои результаты http://www.scienceprog.com/testing-avr-uni...r-on-atmega128/Для старта из секции загрузчика необходимо настроить фус-биты. Про это написано в документации. Atmega128 отличается от остальных тем, что у неё 128кБайт памяти, поэтому есть свои особенности в адресации страниц памяти, но об этом также можно узнать из примеров исходником или из документации. Большое спасибо за ответ! Понемногу начинаю разбираться. То что размер загрузчика задается во фьюзах, это я понял. Но не понимаю как указать то, что конкретный код должен быть размещен в памяти загрузчика или в основной памяти(application sector). Нашел по ссылке http://avr-libc.nongnu.org/user-manual/gro...c42bb18f0f5789e следующую информацию: #define BOOTLOADER_SECTION __attribute__ ((section (".bootloader"))) Used to declare a function or variable to be placed into a new section called .bootloader. This section and its contents can then be relocated to any address (such as the bootloader NRWW area) at link-time. Т.е. как я понял - можно указать местоположение в области бутлоадера каждой функции, но только как? Все мои попытки отнести конкретную часть кода в область лоадера не увенчались успехом, когда при отладке на паузе просматривал состояние памяти лоадера - оно отсавалось пустое все равно. А насколько понимаю то производить манипуляции с flash памятью(стирать страницы и записывать) можно только из области бутлоадера. И еще хочу спросить на примере кода: Код #include <inttypes.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> void boot_program_page (uint32_t page, uint8_t *buf) { uint16_t i; uint8_t sreg;
// Disable interrupts.
sreg = SREG; cli(); eeprom_busy_wait ();
boot_page_erase (page); boot_spm_busy_wait (); // Wait until the memory is erased.
for (i=0; i<SPM_PAGESIZE; i+=2) { // Set up little-endian word.
uint16_t w = *buf++; w += (*buf++) << 8; boot_page_fill (page + i, w); }
boot_page_write (page); // Store buffer in flash page. boot_spm_busy_wait(); // Wait until the memory is written.
// Reenable RWW-section again. We need this if we want to jump back // to the application after bootloading.
boot_rww_enable ();
// Re-enable interrupts (if they were ever enabled).
SREG = sreg;
int main(void) { uint8_t data_buf[SPM_PAGESIZE]; здесь получаем data_buf по USART boot_program_page(0, data_buf); } Т.е. имеем две функции : void boot_program_page (uint32_t page, uint8_t *buf) и int main(void), как отметить то что они должны размещаться в секторе загрузчика? и делается это по отдельности для каждой функции? И как поступать с #define и #include в начале программы - их тоже в бутлоадер?
Сообщение отредактировал IVN2013 - Jan 9 2014, 21:16
|
|
|
|
|
Jan 9 2014, 22:14
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(IVN2013 @ Jan 9 2014, 23:12)  Большое спасибо за ответ! Понемногу начинаю разбираться. То что размер загрузчика задается во фьюзах, это я понял. Если весь не влазит, то можно часть функций и в application section расположить. Цитата(IVN2013 @ Jan 9 2014, 23:12)  Но не понимаю как указать то, что конкретный код должен быть размещен в памяти загрузчика или в основной памяти(application sector). В опциях линкера сместить text в область boot-а(может и не лучший способ...наверняка): Код -Wl,--section-start=.text=0x30000 Да и как-то у AVRGCC плохо с бут-проектами... Цитата(IVN2013 @ Jan 9 2014, 23:12)  Т.е. как я понял - можно указать местоположение в области бутлоадера каждой функции, но только как? Не замучаетесь? Цитата(IVN2013 @ Jan 9 2014, 23:12)  А насколько понимаю то производить манипуляции с flash памятью(стирать страницы и записывать) можно только из области бутлоадера. Верно понимаете. Цитата(IVN2013 @ Jan 9 2014, 23:12)  и делается это по отдельности для каждой функции? Цитата(IVN2013 @ Jan 9 2014, 23:12)  И как поступать с #define и #include в начале программы - их тоже в бутлоадер? Сами поняли что спросили? Тогда другим объясните.
|
|
|
|
|
Jan 12 2014, 15:23
|
Участник

Группа: Участник
Сообщений: 27
Регистрация: 12-08-13
Пользователь №: 77 889

|
Цитата(_Артём_ @ Jan 10 2014, 11:33)  А, кстати, где скрипт лежит? Как-то искал его - не нашёл...понятно, что плохо искал, но всё же, где он лежит по умолчанию? Для AVRGCC... Я не так давно имею дело с AVR GCC и С++ вообще, до этого работал с ассемблером. Насколько понял опции линкера доступны в проект > свойства...>toolchain >AVR/GNU linker> miscellaneous или > memory settigs . Не понял правда как все это настраивать. И что будет давать -Wl,--section-start=.text=0x30000? - адрес с которого будет заливаться весь код?, это ведь не определяет принадлежность кода к области загрузчика? или я что-то не так понимаю? Смысл того что я хочу сделать это: исполняемая бесконечно программа application части, которая стартует сразу, и после прихода по USART определенной команды - переход в бутлоадер, после чего можно либо вернуться обратно, либо залить другую прошивку application части, после чего - сразу переход к ее выполнению. Пример записи во flash память из оперативки вроде есть в свободном доступе и я его как раз выше и привел, но вот как разместить код в области лоадера - не могу понять. В ассемблере с этим было проще: .org 0x0F00 и весь следующий код - уже в бутлоадере (к примеру для m8515). Только как быть здесь, с С++? Может быть следующая инфа из boot.h описывает именно как разместить код в лоадер?: #define BOOTLOADER_SECTION __attribute__ ((section (".bootloader"))) Used to declare a function or variable to be placed into a new section called .bootloader. This section and its contents can then be relocated to any address (such as the bootloader NRWW area) at link-time. Не понял правда как это применить, т.к. си++ пока только знакомлюсь. Если у кого есть какие мысли по этому поводу, пишите. Заранее спасибо!
|
|
|
|
|
Jan 12 2014, 16:02
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(IVN2013 @ Jan 12 2014, 17:23)  Я не так давно имею дело с AVR GCC и С++ вообще, до этого работал с ассемблером. Насколько понял опции линкера доступны в проект > свойства...>toolchain >AVR/GNU linker> miscellaneous или > memory settigs . Можно и через эти опции. Цитата(IVN2013 @ Jan 12 2014, 17:23)  И что будет давать -Wl,--section-start=.text=0x30000? - адрес с которого будет заливаться весь код?, Да, код загрузчика будет расположен по адресам начиная с 0x30000. Цитата(IVN2013 @ Jan 12 2014, 17:23)  это ведь не определяет принадлежность кода к области загрузчика? Принадлежность кода к области загрузчика определяется двумя вещами: 1) размер бута и стартовый адрес определяется фузами. 2) программа бута должна быть расположена по адресам в соответствии с фузами Цитата(IVN2013 @ Jan 12 2014, 17:23)  Смысл того что я хочу сделать это: исполняемая бесконечно программа application части, которая стартует сразу, и после прихода по USART определенной команды - переход в бутлоадер, после чего можно либо вернуться обратно, либо залить другую прошивку application части, после чего - сразу переход к ее выполнению. Можно и так конечно, но лучше, чтобы загрузчик стартовал первым (для чего есть соответствующий фуз). В остальном - нормально. Цитата(IVN2013 @ Jan 12 2014, 17:23)  Может быть следующая инфа из boot.h описывает именно как разместить код в лоадер?: #define BOOTLOADER_SECTION __attribute__ ((section (".bootloader"))) Как-то так наверное: Код BOOTLOADER_SECTION void BootFunc() { /// } или так(не проверял) : Код void BootFunc() BOOTLOADER_SECTION { /// } Цитата(IVN2013 @ Jan 12 2014, 17:23)  Если у кого есть какие мысли по этому поводу, пишите. Заранее спасибо! Только зачем макрос BOOTLOADER_SECTION? Не лучше ли всю программу сместить с помощью опций линкера?
|
|
|
|
|
Jan 12 2014, 22:08
|
Участник

Группа: Участник
Сообщений: 27
Регистрация: 12-08-13
Пользователь №: 77 889

|
Большое спасибо за ответ! С утра буду опять мучать контроллер. В данной ситуации меня попросили сделать именно так, чтобы грузилась основная программа, поэтому тут мне выбирать не приходится. По поводу опций линкера не совсем понял что значит параметр ".text" в примере -Wl,--section-start=.text=0x30000 ?, нашел относительно этого пример на http://www.nongnu.org/avr-libc/user-manual...#faq_reloc_code , там приводится пример: -Wl,--section-start=.bootloader=0x1E000, т.е. указывается ".bootloader". Относительно отдельного определения положения функций, по той же ссылке, приводится следующее: First, the code should be put into a new named section. This is done with a section attribute: __attribute__ ((section (".bootloader"))) In this example, .bootloader is the name of the new section. This attribute needs to be placed after the prototype of any function to force the function into the new section. void boot(void) __attribute__ ((section (".bootloader"))); и далее To relocate the section to a fixed address the linker flag --section-start is used. This option can be passed to the linker using the -Wl compiler option: -Wl,--section-start=.bootloader=0x1E000 Не пойму - что здесь такое - "атрибут" ? , и здесь ".bootloader" это произвольное название секции которое указываем в опции линкера: -Wl,--section-start=.bootloader=0x1E000 ? Т.е. в любом случае нужно указывать название и адрес области в линкере? Что - то начинаю совсем запутываться ) Цитата(_Артём_ @ Jan 12 2014, 19:02)  Только зачем макрос BOOTLOADER_SECTION? Не лучше ли всю программу сместить с помощью опций линкера? Даже не знаю, может быть и лучше. Дело в том, что попросили сделать так чтобы старт был именно из application части. Возможно при этом будет удобнее залить тестовую программу в application часть, для отладки и отдельно часть бутлоадера. А для этого нужно раскидывать код по отдельности.
|
|
|
|
|
Jan 13 2014, 08:39
|

Профессионал
    
Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409

|
Цитата(IVN2013 @ Jan 13 2014, 02:08)  Даже не знаю, может быть и лучше. Дело в том, что попросили сделать так чтобы старт был именно из application части. Возможно при этом будет удобнее залить тестовую программу в application часть, для отладки и отдельно часть бутлоадера. А для этого нужно раскидывать код по отдельности. Это очень нестандартное решение, которое потом приведёт к сбоям. Изначально у Вас есть и приложение и загрузчик. Процессор стартует из секции приложения, потом переходит на загрузчик, после чего начинается обновление секции приложения. Тут происходит сбой, секция приложения работает некорректно, переход на загрузчик не осуществляется, у Вас в руках кирпич. Сделайте так как делают все. По фуз-битам определите запуск из секции загрузчика, расположите там минимальный загрузчик, способный выполнить функции обновления приложения, проверки секции приложения и запуск приложения на исполнение. Тут главная задача - написать загрузчик максимально безбаговый, но при этом выполняющий возложенные на него функции. Обновить загрузчик в мегах без перепрошивки процессора врятли получится (с некоторой степенью риска такая задача возможна на ARM).
|
|
|
|
|
Jan 13 2014, 08:54
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(mempfis_ @ Jan 13 2014, 10:39)  Это очень нестандартное решение, которое потом приведёт к сбоям. Изначально у Вас есть и приложение и загрузчик. Процессор стартует из секции приложения, потом переходит на загрузчик, после чего начинается обновление секции приложения. Тут происходит сбой, секция приложения работает некорректно, переход на загрузчик не осуществляется, у Вас в руках кирпич. Кстати, да, вы соверщенно правильно акцентировали на этом моменте внимание. Полностью согласен. Сначала должен стартовать загрузчик, потом приложение. И никак иначе. Цитата(mempfis_ @ Jan 13 2014, 10:39)  Обновить загрузчик в мегах без перепрошивки процессора врятли получится (с некоторой степенью риска такая задача возможна на ARM). Обновить можно, но проще написать без глюков.
|
|
|
|
|
Jan 13 2014, 11:53
|
Гуру
     
Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847

|
Цитата По поводу опций линкера не совсем понял что значит параметр ".text" в примере -Wl,--section-start=.text=0x30000 ?, Это имя секции. В GCC (точнее в ELF, но не суть) все данные (включая код и переменные) располагаются в каких то именованных секциях, и никак иначе. Линкер, в процессе генерации исполняемого образа, собирает вместе именованные секции, и располагает их по заданным адресам, как именно - описывается в скрипте линкера. Если вы не подаете скрипт - линкер все равно берет скрипт по умолчанию. Секция .text содержит код программы (имя секции выбрано по историческим причинам). Цитата Не пойму - что здесь такое - "атрибут" ? Это атрибут функции (в понимании GCC). В GCC есть масса разных атрибутов, в вашем случае это атрибут 'section'. Он задает имя секции (в выходном объектном файле), куда будет помещен код функции. Цитата и здесь ".bootloader" это произвольное название секции которое указываем в опции линкера: -Wl,--section-start=.bootloader=0x1E000 ? Т.е. в любом случае нужно указывать название и адрес области в линкере? Именно так. Цитата А, кстати, где скрипт лежит? Увы, установленного AVRGCC у меня нет. Но можно выковырять из исходников binutils, там есть (шаблон в ld/scripttempl/avr.sc)
|
|
|
|
|
Jan 22 2014, 21:02
|
Участник

Группа: Участник
Сообщений: 27
Регистрация: 12-08-13
Пользователь №: 77 889

|
Всем большое спасибо за ответы! Вроде получилось сделать распределение кода по флэш памяти следующим образом: добавляю __attribute__((section(".text"))) перед int main() в главной части, а для области бутлоадера добавил перед каждой функцией __attribute__((section(".bootloader"))) , причем там у меня может быть несколько функций, например : __attribute__((section(".bootloader"))) static inline void eraseFlash() и __attribute__((section(".bootloader"))) void test() , если правильно понял, то одним и тем же названием секции можно помечать несколько разных функций. Затем: проект > свойства...>toolchain >AVR/GNU linker> miscellaneous >other linker flags указал : -Wl,-section-start=.text=0x000000 -Wl,-section-start=.bootloader=0x01fc00 Относительно выбора загрузки с application части поговорил еще раз на работе. В данном случае перепрошиваться application часть через бутлоадер будет скорее всего не часто, главная часть должна будет начинать работать без лишних задержек на бутлоадер( пусть и малых), а в случае сбоя можно будет перепрошить полностью через jtag. Поэтому пока что буду продолжать делать именно этот вариант)). Сейчас подзастрял: почему - то не получается стереть всю флэш память. Использую следующую функцию в области бутлоадера. Код __attribute__((section(".bootloader"))) static inline void eraseFlash() //стирание application сектора из flash памяти { uint32_t addr = 0; while (0x01fc00 > addr) // 0x01fc00 - это начало бутлоадера { boot_page_erase(addr); // стирание страницы boot_spm_busy_wait(); // задержка на время стирания addr += SPM_PAGESIZE; } boot_rww_enable();
} Почему-то при отладке по jtag не вижу вообще никаких изменений содержимого флэш. При этом старт флаг Bootrst не ставлю и старт с application части, а переход в функцию в буте после. Если ставлю этот флаг, то старт с бутака и тогда флэш заполняется ff (кстати, забыл - так и должно при стирании на ff все меняться а не на 00 ? ) В общем, пишите, если есть какие идеи как стереть всю флэш при старте с application части и не отмеченном Bootrst или может в функции у меня что не так? Спасибо!
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|