Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Cамопрограммирование flash, ( Запись flash )
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Jhohn
Здравствуйте!

Разрабатываемое устройство на Atmel 168 (flash = 16k, bootloader = 2048 byte) принимает данные по USB (эта часть уже реализована программно). Среда разработки WinAvr. Программная реализация USB (программа-usb) не маленькая больше чем bootloader. По USB принимаются данные (основная-программа + константы) и перепрошивается flash. Код основной-программы не писался, оочень большая вероятность что это будет > 2 к. У устройства есть два режима программирование (задание конфигурации) и работа самого устройства, для выбора режима имеется вход +5 В на ножку МК при программировании. EEPROM может не хватить поэтому предполагаю запись констант в флеш.

Вопросы:

1) При включении устройства мы переходим в bootload, проверяем вывод и соответственно переходим к jmp(необходимый адрес в flash) ?

2) Можно ли программу-usb расположить в flash принимать данные в ОЗУ потом jmp bootload, писать там код основной программы и обратно в программу в flash? (т.к. программа-usb не помещается в bootload )
т.е. вопрос могу ли я перейти из RWW в загрузчик (NRWW) КАК ? jmp (адрес) ?

3) Ход программирования предполагаю таким:
------( bootload_start см рис память flash ) загрузчик (nrww) [if (port == 1) ] ->
------( Jmp 1 ) к программе-usb ->
------( Jmp 1 ) пишем в озу 128 б принятые данные по usb ->
------( bootload ) оттуда пишем память > Jmp_2 ->
------( Jmp 1 )
reset
Ход выполнения основной программы:
------( bootload ) загрузчик (nrww) [if (port == 0) ] ->
------( Jmp 2 ) к основной-программе

ЕСТЬ ЗАМЕЧАНИЯ?


4) При выполнении основной-программы при считывании констант из flash, как прочесть константы ? (снова в загрузчик читать в озу и обратно?)



Жду замечаний ) Спасибо. smile.gif
GDI
Почему тут http://www.obdev.at/products/avrusb/prjprog.html люди молут разместить бутлоадер а вы нет?
Jhohn
Цитата(GDI @ Nov 13 2008, 17:06) *
Почему тут http://www.obdev.at/products/avrusb/prjprog.html люди молут разместить бутлоадер а вы нет?


спасибо за ссылку.

Вопрос о размещении bootloader не стоял. я так понял вы не сталкивались с этим...

Жду замечаний по существу smile.gif
GDI
Цитата
Программная реализация USB (программа-usb) не маленькая больше чем bootloader.

Я так по этой фразе понял.
Jhohn
Хочется получить грамотный ответ на поставленный вопрос smile.gif
SasaVitebsk
Цитата(Jhohn @ Nov 13 2008, 20:09) *
Хочется получить грамотный ответ на поставленный вопрос smile.gif

Принципиально - ничто не мешает. В своё время я планировал расположить в буте (в неизменяемой области) драйвера устр-в включая RS232 (по нём и обновление). В этом случае гарантировано один протокол обмена и при буте и при работе. Потом отказался от этой идеи.
Несколько непонятно зачем такие сложности.
1) я делаю так при старте бута смотрю ногу принудительного перехода в бут и смотрю DDR порта, который гарантировано не 0 при работе приложения (принудительный переход из приложения в бут) Считаю CRC области приложения (при несовпадении - в бут)
2)Учитывая, что загрузчик занимает > места чем область загрузчика у вас будут следующие ограничения.
a) Старт будет осуществлятся не с начала загрузчика, а с середины
б) область приложения будет кратна размеру страницы и требуется следить за тем, чтобы не запортить загрузчик.
в) вектора будут находится посередине.
Если это не пугает, то вперёд.

насчёт констант - какие вопросы?
Не знаю как это в WinAvR сделать - в IAR весьма всё просто осуществляется.
Jhohn
Цитата(SasaVitebsk @ Nov 13 2008, 19:43) *
Несколько непонятно зачем такие сложности.
....
Если это не пугает, то вперёд.


А у вас есть более "интересное" решение, данной задачи? smile.gif

К сожалению другого решения не вижу.
plombir
Цитата(Jhohn @ Nov 13 2008, 16:38) *
Здравствуйте!

Разрабатываемое устройство на Atmel 168 (flash = 16k, bootloader = 2048 byte) принимает данные по USB
...

2) Да можно.
В IARе я использовал #pragma location=bootadr для 2-х процедур (загрузка в буфер и прошить страницу), которые располагались в буте. Больше там ничего не было. К процедурам обращался как обычно call. Так как грузил я только таблицы, контроллер после не ресетил.
SasaVitebsk
Цитата(Jhohn @ Nov 14 2008, 01:19) *
А у вас есть более "интересное" решение, данной задачи? smile.gif
К сожалению другого решения не вижу.

Это же программирование. Здесь решений - огромное количество. smile.gif

Во первых, при построении таких систем, я бы взял за основу стандартное построение мониторов и биосов. То есть наличие чётко описаных процедур и данных находящихся по фиксированным адресам.
Ну например:
E000: StartBoot
E002: ReadPacket
E004: SendPacket
E006: CRC8
Что там разместить - вам решать (я указал от балды), но надеюсь понятна идея, зачем это сделано?

Во вторых в верхней части разместил бы мааалюсенький boot. Идею на этом форуме кто-то из великих уже подкидывал. Правда назначение другое было Boot для Boot-а. Здесь таже хрень. Сам маленький бут понятия не имеет как данные поступают в МК. Он просто их берёт и записывает.

Размещение данных для бута может быть - озу, EEPROM, FLASH. То есть любое.

Конечно для эфективной работы такой системы предпочтительным является размер буфера превышающий размер апликейшена. Либо апликейшн строится по типу перемещаемого кода. В противном случае требуется несколько итераций для восстановления работоспособности всей системы в целом. Всё прописывается в проге зашивальщике.

Это усложнённо.
Если упростить, то размер приложения должен быть меньше свободного размера флэш в 2 раза.
defunct
Цитата(Jhohn @ Nov 13 2008, 23:19) *
А у вас есть более "интересное" решение, данной задачи? smile.gif

Есть
Берем внешний копеечный eeprom на 16KB. USB программой загоняем туда образ "программы которую надо зашить", и перезагружаем МК. Стартует загрузчик, проверяет нет ли во внешнем eeprom более свежей копии основной программы, если есть то он шьет ее в МК и передает управление по адресу 0.
Плюсы:
1. МК защищен от случайного перетирания флеша, бутлоадер всегда сможет восстановить основную программу из внешнего eeprom.
2. Бутлоадер может стать меньше (не 2K, а 1K) т.к. ему не нужно общаться с внешним компом.
3. Нет никаких манипуляций с программированием не из boot секции.
4. Основная программа совмещена с USB программой, т.е. всего два независимых модуля, а не три.

Минусы:
доп корпус.
Jhohn
В процессе записи в Flash сталкнулся с ошибкой:

Петедаю массив (в озу) - {1,1,1.. (128)...1,1,} в bootload, чтоб там записать во flash, но при записи получаю результат


:1019F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7
:101A000001020102010201020102010201020102BE
:101A100001020102010201020102010201020102AE
:101A2000010201020102010201020102010201029E
:101A3000010201020102010201020102010201028E
:101A4000001A009D7550400702BFC2880001A12204
:101A5000000121230102010201000000000000003A
:101A60000000FFFEFFFEFFFEFFFEFFFEFFFEFFFE8B
:101A7000FFFEFFFEFFFEFFFEFFFEFFFEFFFEFFFE7E
:101A8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66

вместо

:1019F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7
:101A000001010101010101010101010101010101C6
:101A100001010101010101010101010101010101B6
:101A200001010101010101010101010101010101A6
:101A30000101010101010101010101010101010196
:101A40000101010101010101010101010101010186
:101A50000101010101010101010101010101010176
:101A60000101010101010101010101010101010166
:101A70000101010101010101010101010101010156
:101A8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66

Код загрузчика (функция взятая из avr/boot.h )
................................................................................
...................................................................
BOOTLOADER_SECTION
void boot_write_page(unsigned int page, unsigned int *buf)
{
unsigned int i;
unsigned int w;

eeprom_busy_wait ();
boot_page_erase (page);..............................// Стереть страницу
boot_spm_busy_wait ();................................// Ждем пока не сотрем страницу


for (i=0; i<PAGE_SIZE; i+=2)
{
w = *buf++;............................................// Запись w (2 байта) байт_старш + байт_младш
w += (*buf++) << 8;
boot_page_fill (page + i, w);.....................// Заносим в буфер данные [ addrerss, data_16 ]
}

boot_page_write (page);...............................// Запись в Флеш страницы
boot_spm_busy_wait();................................// Ждем пока не запишем страницу
boot_rww_enable ();.................................. // Разрешение адресации в области памяти программ

LED_OFF;

}
................................................................................
...................................................................
Вызов функции
................................................................................
...................................................................
boot_write_page(addr,usb_ram);........ //аргументы 1 - адрес по которуму пишем в флеш
........................................................//2 - массив (в озу) - {1,1,1.. (128)...1,1}

***************************************************************************
***************************************************************************
Вся проблема кроется здесь

w = *buf++;............................................// Запись w (2 байта) байт_старш + байт_младш
w += (*buf++) << 8;

неверно передаются данные из "*buf" в "w"
aesok
Цитата(Jhohn @ Nov 19 2008, 14:50) *
BOOTLOADER_SECTION
void boot_write_page(unsigned int page, unsigned int *buf)
{
...
}

Вся проблема кроется здесь

w = *buf++;............................................// Запись w (2 байта) байт_старш + байт_младш
w += (*buf++) << 8;

неверно передаются данные из "*buf" в "w"


buf - указатель на int, поэтому buf++ инкрементирует buf на 2.

Анатолий.
Jhohn
smile.gif Вы правы. Спасибо.
Jhohn
Мучаю Код help.gif

//////////////////////////////////////////////////////////////////////////////////////////////////////

if (val < PAGE_SIZE - 1)
{
.........usb_in_ram[val] = USBBuffer[5];

.........val += 1;
}
else
{
.........usb_in_ram[val] = USBBuffer[5];

.........boot_program_page(addr_word_flash, usb_in_ram); // запись страницы
..........addr_word_flash += 128;

..........val = 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////

записываемый флай в флеш

:101A000011111111111111111111111111111111C6
:101A100022222222222222222222222222222222A6
:101A20003333333333333333333333333333333386
:101A30004444444444444444444444444444444466
:101A40005555555555555555555555555555555546
:101A50006666666666666666666666666666666626
:101A60007777777777777777777777777777777706
:101A700088888888888888888888888888888888E6
:101A800099999999999999999999999999999999C6
:101A900022222222222222222222222222222222A6
:101AA0003333333333333333333333333333333386
:101AB0004444444444444444444444444444444466
:101AC0005555555555555555555555555555555546
:101AD0006666666666666666666666666666666626
:101AE0007777777777777777777777777777777706
:101AF00011111111111111111111111111111111E6

== 1 байту == 256 значений

РЕЗУЛЬТАТ:

:101A000011111111111111111111111111111111C6
:101A100022222222222222222222222222222222A6
:101A20003333333333333333333333333333333386
:101A30004444444444444444444444444444444466
:101A40005555555555555555555555555555555546
:101A50006666666666666666666666666666666626
:101A60007777777777777777777777777777777706
:101A700088888888888888888888888888888888E6
:101A800088999999999999999999999999999999D7
:101A900099222222222222222222222222222222AF
:101AA0002233333333333333333333333333333317
:101AB00033444444444444444444444444444444F7
:101AC00044555555555555555555555555555555D7
:101AD00055666666666666666666666666666666B7
:101AE0006677777777777777777777777777777797
:101AF0007711111111111111111111111111111170


В записанном файле первые 128 пишутся нормально, А ВТОРЫЕ 128 В НАЧАЛЕ добавляется БАЙТ ???

Где может быть проблема?
help.gif
Jhohn
может в функции проблема boot_program_page() ? хотя она стандартная в AVR ...
Сергей Борщ
Цитата(Jhohn @ Nov 24 2008, 13:21) *
//////////////////////////////////////////////////////////////////////////////////////////////////////
.........usb_in_ram[val] = USBBuffer[5];
И что только люди не делают, только бы не использовать специально заточенные тэги оформления кода (кнопка '#' на форме ввода сообщения).

Подключите UART контроллера к СОМ-порту компьютера и вместо библиотечный функций записи подставьте свои, которые вместо записи будут сливать информацию в UART в текстовом виде. Информации можно послать достаточно для поиска проблемы. Можно печатать адреса, данные, содержимое памяти, все, что угодно.
Цитата(Jhohn @ Nov 24 2008, 13:21) *
Код
if (val < PAGE_SIZE - 1)
Не видя остального кода предполагать трудно, но вы уверены, что тут должно быть PAGE_SIZE - 1?
Jhohn
Цитата(Сергей Борщ @ Nov 24 2008, 16:19) *
Не видя остального кода предполагать трудно, но вы уверены, что тут должно быть PAGE_SIZE - 1?


Да точно. Последний 127 байт пишется в else и там же пишется в память.


Разобрался, при записи мы не успеваем ответить на out-пакет от USB и он его повторяет в следующем байте который мы ловим.

Код
Спасибо, буду знать  :)
SasaVitebsk
Кстати идея Defunct весьма интересна. Можно её даже развивать.
Jhohn
Не могу войти в область загрузчика (bootload section) при старте.

Использовал

1)BOOTLOADER_SECTION void main ()


2) устанавливал флаг BOOTRST = 0


Может что-то нужно еще?
Сергей Борщ
Цитата(Jhohn @ Nov 26 2008, 12:22) *
1)BOOTLOADER_SECTION void main ()
Все остальное (включая вектора) тоже надо разместить в области загрузчика. Правьте скрипт линкера.
Jhohn
Такой дурацкий вопрос: как? вы имеете в виду meikfile ?

Цитата(Сергей Борщ @ Nov 26 2008, 13:41) *
Все остальное (включая вектора)

что имеется в виду?
Могу я загрузится в boot потом сделать проверку и идти в application_1 или application_2 ?
Сергей Борщ
Цитата(Jhohn @ Nov 26 2008, 12:41) *
Такой дурацкий вопрос: как? вы имеете в виду meikfile ?
Нет. Скрипт линкера. Если у вас в makefile скрипт явно не указан через LDFLAGS += -Wl,-T,имя_скрипта, то avr-ld берет подходящий для вашего кристалла из WinAVR/AVR/LIB/LDSCRIPTS. Самый простой способ определить, какой именно - переименуйте всю папку, линкер ругнется на конкретный файл, переименуйте папку обратно. Потом берите этот файл, копируйте в свой проект (можно переименовать, чтобы не путаться), добавляйте LDFLAGS += -Wl,-T,имя_скрипта в нужное место makefile или -Wl,-T,имя_скрипта на вкладку опций линкера в AVRStudio, идите в WinAVR/DOC/binutils/ld, читайте о формате скрипт-файла и правьте его как вам надо.

Результаты хорошо видны в файле дизассемблера. У меня он генерится примерно так (отрывки makefile):
Код
## Build
all: create_dirs $(PROJECT).elf $(PROJECT).hex $(PROJECT).eep $(PROJECT).lss size

%.lss: $(PROJECT).elf
    $(OBJDUMP) -hdSC $< > $@


Цитата(Jhohn @ Nov 26 2008, 12:41) *
Могу я загрузится в boot потом сделать проверку и идти в application_1 или application_2 ?
Конечно.
defunct
Цитата(SasaVitebsk @ Nov 25 2008, 12:29) *
Кстати идея defunct весьма интересна. Можно её даже развивать.

Эта идея возникла после того как однажды слетел флеш на одном из устройств, установленном на объекте в "степях мухосранска". После этого случая комплектую внешней EEPROM'кой с копией прошивки. В рабочем состоянии eeprom'ка защищена от записи (WP).

При обновлении - одной перемычкой разрешается бутлоадеру "шить" и снимается WP с eeprom'а.
При установленной перемычке дальше бутлоадера ничего не идет (основная программа не запускается),. В критической ситуации (сбой CRC основного кода) бутлоадер заливает код из eeprom'a автоматически.
Jhohn
Как всегда о неудачах:

Цитата(Сергей Борщ @ Nov 26 2008, 14:25) *
Нет. Скрипт линкера. Если у вас в makefile скрипт явно не указан через LDFLAGS += -Wl,-T,имя_скрипта, то avr-ld берет подходящий для вашего кристалла из WinAVR/AVR/LIB/LDSCRIPTS. Самый простой способ определить, какой именно - переименуйте всю папку, линкер ругнется на конкретный файл, переименуйте папку обратно. Потом берите этот файл, копируйте в свой проект (можно переименовать, чтобы не путаться), добавляйте LDFLAGS += -Wl,-T,имя_скрипта в нужное место makefile или -Wl,-T,имя_скрипта на вкладку опций линкера в AVRStudio, идите в WinAVR/DOC/binutils/ld, читайте о формате скрипт-файла и правьте его как вам надо.


Нашел файл "avr5.x" почитал указанные скрипты но так и не разобрался с указанным файлом, при разборе много вынес полезного.

Я подумал хорошенько и решил не Рестартиться в boot, а загрузаться в usb_application, соответстенно, проверку того какая программа выполняется делаю в main() ( usb_application )

Код
[code]USB_SECTION                                                            // 0x2800
void main (void)
{

    if(CHECKBIT(PINC,2))                            // usb_section     ->  + 5 V
    {
                                                                                   // инициализация
        for(;;)
        {    

        }
    }    
    else                                            // application_section     ->   0 V
    {
                                                                                   // инициализация
        
        for(;;)
        {
            goto_application();
        }
    }
}



Необходимо загрузится по адресу application_section ( 0x0200), после самопрограммирования, но не получается. Я создал функцию goto_application(); которая начинается с адреса = 0x0200, а пишу я в flash по этому же адресу.
Возможно одна из причин следующая:


Код
APPLICATION_SECTION                             //0x0200
void goto_application(void)
{
    
     LED_ON;
     LED_ON;                  // Три LED_ON
     LED_ON;
}


Если в теле фукцнии goto_application() написалть 3-и оператора, то получаем память программ вида
Код
...
:1001F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0F
:10020000[b]5E9A5E9A5E9A[/b]0895FFFFFFFFFFFFFFFF71
:10021000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEE
...
:1034200090915B01982F882790935B0180935A01BC
:1034300020915A0130915B0180916F0190E0822BC5
:10344000932B90935B0180935A0120916A018091A4
:103450005A0190915B01F999FECF92BD81BD20BDCB
:10346000FA9AF99A74CADF91CF911F910895CF9378                      
:10347000DF93329B16C023E02093690081E08DBB6F
:1034800080E48AB980E58AB980E18BB98CE691E065
:10349000D92FC82F86E2809333012093340178948A
:10[b]34A0[/b]00FFCF80E48AB9[b]5E9A5E9A5E9A[/b]FCCFFFFFF6
:1034B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1C
...


main() 0x0000346e

то есть код повторяется

Если в теле фукцнии goto_application() написалть 5-ть операторов, то получаем память программ с пятью повторяющимися содами в двух секциях


Если в теле фукцнии goto_application() написалть 20-ть операторов, то получаем память программ вида
Код
...
:1001F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0F
:10020000[b]5E9A5E9A5E9A5E9A5E9A5E9A5E9A5E9A2E
:100210005E9A5E9A5E9A5E9A5E9A5E9A5E9A5E9A1E
:100220005E9A5E9A5E9A5E9A[/b]0895FFFFFFFFFFFF57
:10023000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE
...
:10344000932B90935B0180935A0120916A018091A4
:103450005A0190915B01F999FECF92BD81BD20BDCB
:10346000FA9AF99A74CADF91CF911F910895CF9378
:10347000DF93329B16C023E02093690081E08DBB6F
:1034800080E48AB980E58AB980E18BB98CE691E065
:10349000D92FC82F86E2809333012093340178948A
:10[b]34A0[/b]00FFCF80E48AB90E940001FDCFFFFFFFFF3C
:1034B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1C
:1034C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0C
...


повторяющихся 5E9A не видно

НЕ ПОЙМУ почем функция main() изменяется так странно то добавляет, код код другой секции, то нет...
Может я что-то я что-то делаю не так?


память соответственно 3 оператора, 5 и 20 в файлах
Сергей Борщ
Цитата(Jhohn @ Nov 27 2008, 19:28) *
Я подумал хорошенько и решил не Рестартиться в boot, а загрузаться в usb_application, соответстенно, проверку того какая программа выполняется делаю в main() ( usb_application )
Можно и так, но что произойдет, если приложения нет или обновление оборвалось на середине? Обычно в задачу загрузчика входит проверка контрольной суммы приложения и передача ему управления лишь в том случае, если контрольная сумма совпала, т.е. приложение работоспособно.

Цитата(Jhohn @ Nov 27 2008, 19:28) *
НЕ ПОЙМУ почем функция main() изменяется так странно то добавляет, код код другой секции, то нет...
Может я что-то я что-то делаю не так?
поробуйте сделать так: avr-objdump -hdSC file.elf > listing.lss
file.elf - .elf-файл вашей программы. В listing.lss увидите дизассемблированный текст. По этому тексту видно, что "то добавляет" - это компилятор встроил тело вашей функции в точку вызова. Ну и оставил еще одну копию на случай, если вы захотите вызвать ее из другого файла. "То нет"- это когда тело вашей функции такого размера, что вызвать функцию уже выгоднее по размеру, чем встроить ее.
Чтобы не оставалось ненужных копий, почитайте эту ветку. А чтобы компилятор не встраивал функцию goto_application() в main() размещайте их в разных единицах компиляции или примените к ней __attribute__((__noinline__)). Последнее более правильно, ибо компиляторы начали поддерживать многофайловую оптимизацию и начиная с какой-то версии научатся встраивать функции и из других единиц компиляции.
Jhohn
Цитата(Сергей Борщ @ Nov 28 2008, 01:42) *
поробуйте сделать так: avr-objdump -hdSC file.elf > listing.lss
file.elf - .elf-файл вашей программы. В listing.lss увидите дизассемблированный текст.


Да при добавлении

Код
__attribute__((__noinline__))  goto_application(void)


по файлу *.lss видно, что не добавляет. Теперь все работает, программы меняются a14.gif Спасибо.

Цитата(Сергей Борщ @ Nov 28 2008, 01:42) *
Чтобы не оставалось ненужных копий, почитайте эту ветку. А чтобы компилятор не встраивал функцию goto_application() в main() размещайте их в разных единицах компиляции или примените к ней __attribute__((__noinline__)).


А что копия и вставка сода из одной функции в другую это разные вещи?
Jhohn
Начну с хорошего все работает и прошивается на atmga 168. Перенес тот же код на atmega 64, и нифига.
Подробно: 128 байт пишет по заданному адресу, если же прошивается более (128 + 16) то пишется в Flash только 16 ! c правильным адресом (start + 128). В чем проблема не пойму, в итоге получается вид: 128 байт (FF), 128 байт (кода), 128 байт (FF)...
Подскажите в какую сторону капать. 1111493779.gif
rx3apf
Цитата(Jhohn @ Mar 10 2009, 23:59) *
Подскажите в какую сторону капать. 1111493779.gif

Вероятно, в сторону размера страницы, которая у mega64 вдвое больше (256 байтов).
Jhohn
1111493779.gif блин, так и есть, вылетело из головы cranky.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.