Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Никак не пойму как работае IAP
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Metallist64
Добрый день уважаемый ALL!
Использую LPC2367 + Keil+RL. Встал вопрос обновления прошивки.
Планирую записывать ее во внешнюю флэшку. Затем читать и программировать механизмом IAP.
Проблема в следующем: не въеду как работает этот IAP.
Понял, что есть область адресов для программы, есть кокой-то загрузчик. Но не понимаю как осуществляется переход между ними.
Кто сталкивался, прошу помощи.
kovigor
Цитата(Metallist64 @ Jun 14 2011, 11:36) *
Добрый день уважаемый ALL!
Использую LPC2367 + Keil+RL. Встал вопрос обновления прошивки.
Планирую записывать ее во внешнюю флэшку. Затем читать и программировать механизмом IAP.
Проблема в следующем: не въеду как работает этот IAP.
Понял, что есть область адресов для программы, есть кокой-то загрузчик. Но не понимаю как осуществляется переход между ними.
Кто сталкивался, прошу помощи.


Вызываются функции загрузчика через указатели на них. У NXP все расписано в аппнотах. Например:

http://www.nxp.com/documents/application_note/AN10256.pdf

Если надо, могу прислать проект для LPC214x
Metallist64
Цитата
Вызываются функции загрузчика через указатели на них. У NXP все расписано в аппнотах.

Вот вот здесь собственно и начинаются непонятки:
1. После перехода к загрузчику(и его выполнения?), насколько я понимаю, должен следовать мой код?
2. Насколько я понял максимальный разъмер кода - 8кб ? Т.к. он будет расположен в области загрузчика?
3. Слышал, что нужно переписывать таблицу векторов прерывай, так ли это?

PS Апноут прочел. Но к сожалению не понимаю последовательности процесса.
kovigor
Цитата(Metallist64 @ Jun 14 2011, 13:13) *
Вот вот здесь собственно и начинаются непонятки:
1. После перехода к загрузчику(и его выполнения?), насколько я понимаю, должен следовать мой код?
2. Насколько я понял максимальный разъмер кода - 8кб ? Т.к. он будет расположен в области загрузчика?
3. Слышал, что нужно переписывать таблицу векторов прерывай, так ли это?


1. И до, и после. Вызовы функций загрузчика вставляются в требуемые места вашей программы.
2. См. описание функций загрузчика. В функцию записи передаются адреса источника и приемника, а никак не сами записываемые данные.
3. Не совсем. Вы просто можете запретить прерывания на время модификации Flash. Альтернатива - скопировать таблицу векторов в ОЗУ, указать на эту копию процессору и разместить обработчики прерываний и все требуемое для их работы в ОЗУ. тогда прерывания смогут обрабатываться даже во время записи во Flash ...
Metallist64
Цитата(kovigor @ Jun 14 2011, 14:26) *
1. И до, и после. Вызовы функций загрузчика вставляются в требуемые места вашей программы.
2. См. описание функций загрузчика. В функцию записи передаются адреса источника и приемника, а никак не сами записываемые данные.
3. Не совсем. Вы просто можете запретить прерывания на время модификации Flash. Альтернатива - скопировать таблицу векторов в ОЗУ, указать на эту копию процессору и разместить обработчики прерываний и все требуемое для их работы в ОЗУ. тогда прерывания смогут обрабатываться даже во время записи во Flash ...


Т.е. насколько я понял, я должен записываться код со следующего свободного сектора и затем как-то переходить именно в эту область ?
kovigor
Цитата(Metallist64 @ Jun 14 2011, 14:29) *
Т.е. насколько я понял, я должен записываться код со следующего свободного сектора и затем как-то переходить именно в эту область ?


А зачем туда переходить ? Стираете сектор и записываете в него новые данные (блоками размером не более 4096 байт). В User Manual'е все это подробно расписано. После обновления всех запланированных секторов можете просто использовать их новое содержимое по своему усмотрению (например, если обновлялись данные пользователя). А если речь идет об обновлении прошивки, по проще всего будет после успешного обновления перегрузиться, используя WatchDog. Так вы "перейдете именно в эту область". Функции, модифицирующие Flash, следует расположить в ОЗУ, чтобы не было конфликтов и зависаний при одновременной модификации Flash и выборки из нее кодов команд или данных ...
Metallist64
Цитата
Функции, модифицирующие Flash, следует расположить в ОЗУ, чтобы не было конфликтов и зависаний при одновременной модификации Flash и выборки из нее кодов команд или данных ..


На сколько я понимаю физически флэш память одна. Она просто логически разделена(судя по карте памяти) на разелы BOOT и скажем так пользовательский код?

Сам код, который будет обновлять флэш будет находиться в области зарузчика ? И писать пользовательский код туда нельзя. Судя по карте памяти в нем есть как ROM так FLASH области?

Таким образом общий объем памяти складывается из = BOOT ROM + BOOT FLASH + USER CODE FLASH ?

Опять таки, насколько я понял, что для LPC2367 объем BOOT области = 8кб. И писать тудо ничего ненадо? Там лежат именно те самые функции IAP, я должен только использовать их, вызывая и передавая аргументы?
mempfis_
Цитата(Metallist64 @ Jun 16 2011, 13:32) *
На сколько я понимаю физически флэш память одна. Она просто логически разделена(судя по карте памяти) на разелы BOOT и скажем так пользовательский код?

Сам код, который будет обновлять флэш будет находиться в области зарузчика ? И писать пользовательский код туда нельзя. Судя по карте памяти в нем есть как ROM так FLASH области?

Таким образом общий объем памяти складывается из = BOOT ROM + BOOT FLASH + USER CODE FLASH ?

Опять таки, насколько я понял, что для LPC2367 объем BOOT области = 8кб. И писать тудо ничего ненадо? Там лежат именно те самые функции IAP, я должен только использовать их, вызывая и передавая аргументы?


FLASH одна и имеет линейное адресное пространство от и до.
Вы можете выделить под Ваш загрузчик скажем первые 8к (2 первых сектора по 4к, если их будет мало добавите сколько нужно - для lpc23хх нет разграничений flash на boot не boot области как у атмег). В этой области разместите код загрузчика который будет каким-либо образом принимать прошивку (по uart или как сделано у меня 122к зашифрованной прошивки хранятся во внешней flash-памяти). Код загрузчика анализирует наличие прошивки, закидывает в буффер скажем 4к блок прошивки приложения, из IAP вызывает процедуру подготовки соотв. сектора, процедуру стирания и потом процедуру записи. Там по сути всё настолько просто что работает с первого раза (скажем у меня за полдня получилось полностью освоить код работы с IAP и написать загрузчик для lpc2368).

CODE
//-----------------------------------------
//стирание выбранного сектора
unsigned int eraseSector(unsigned int SECTOR)
{
unsigned int status=0;

//---------------------------------------
//подготовка сектора
status = iapSelectSector(SECTOR, SECTOR);
if(status != IAP_CMD_SUCCESS)
{
return 0; //сбой подготовки
}
//---------------------------------------


//---------------------------------------
//стирание сектора
__disable_interrupt();
status = iapEraseSector(SECTOR, SECTOR);
__enable_interrupt();

if(status != IAP_CMD_SUCCESS)
{
return 0; //сбой стирания
}
else
{
return 1; //стирание OK
}
//---------------------------------------
}
//-----------------------------------------

//-----------------------------------------
//запись вектора
unsigned int writeSector(unsigned int* pData, unsigned int SECTOR, unsigned int addr, unsigned int size)
{
unsigned int status=0;

//---------------------------------------
//подготовка сектора
status = iapSelectSector(SECTOR, SECTOR);
if(status != IAP_CMD_SUCCESS)
{
return 0; //сбой подготовки
}
//---------------------------------------

//---------------------------------------
//запись сектора
__disable_interrupt();
status = iapRamToFlash( addr, (unsigned int) pData, size);
__enable_interrupt();
if(status != IAP_CMD_SUCCESS)
{
return 0; //сбой записи
}
else
{
return 1; //запись OK
}
//---------------------------------------

}
//-----------------------
Metallist64
Большое спасибо за пример и пояснение.
С функциями более или менее разобрался.
Но есть еще пара вопросиков:
А на уровне проекта это как осуществляется?
Создаются 2 проекта с разными рабочими областями? или в одном проекте указывается где какой код должен лежать?

Заранее спасибо.

mempfis_
Цитата(Metallist64 @ Jun 20 2011, 09:29) *
Большое спасибо за пример и пояснение.
С функциями более или менее разобрался.
Но есть еще пара вопросиков:
А на уровне проекта это как осуществляется?
Создаются 2 проекта с разными рабочими областями? или в одном проекте указывается где какой код должен лежать?

Заранее спасибо.


У меня это 2 отдельных проекта. Связаны они между собой только начальным адресом приложения во flash.
В бутлоадере в файле линкера flash ограничена 8к. Выделен сегмент под CRP.
В коде бутлоадера гдето прописывается уровень защиты
Код
//-------------------------------------------
//устанавливаем защиту
#define CRP1 0x12345678ul
#define CRP2 0x87654321ul
#define CRP3 0x43218765ul //этот уровень защиты убъёт процессор!!!

#pragma location = "CRP_section"
__root const unsigned long crp = 0x87654321ul;
//-------------------------------------------


вызов приложения из бутлоадера осуществляется так:

Код
void (*app) (); //указатель на приложение

#define APPL_START_ADDR 0x00002000 //стартовый адрес расположения приложения во flash

app = (void(*)()) APPL_START_ADDR;
app();


В icf-файле приложения необходимо указать линкеру что вектора прерываний находятся не по нулевому адресу. Ну и ограничить flash.

Пишу в IAR. Прмер icf-файла для бутлоадера.

CODE
/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x00000000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x00000200;
define symbol __ICFEDIT_region_ROM_end__ = 0x00002000;
define symbol __ICFEDIT_region_RAM_start__ = 0x40000040;
define symbol __ICFEDIT_region_RAM_end__ = 0x40007FDF;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__ = 0x400;
define symbol __ICFEDIT_size_svcstack__ = 0x100;
define symbol __ICFEDIT_size_irqstack__ = 0x100;
define symbol __ICFEDIT_size_fiqstack__ = 0x40;
define symbol __ICFEDIT_size_undstack__ = 0x10;
define symbol __ICFEDIT_size_abtstack__ = 0x10;
define symbol __ICFEDIT_size_heap__ = 0x2000;
/**** End of ICF editor section. ###ICF###*/


define memory mem with size = 4G;
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];

define symbol __region_USB_DMA_RAM_start__ = 0x7FD00000;
define symbol __region_USB_DMA_RAM_end__ = 0x7FD01FFF;
define region USB_DMA_RAM_region= mem:[from __region_USB_DMA_RAM_start__ to __region_USB_DMA_RAM_end__];

define symbol __region_EMAC_DMA_RAM_start__ = 0x7FE00000;
define symbol __region_EMAC_DMA_RAM_end__ = 0x7FE03FFF;
define region EMAC_DMA_RAM_region= mem:[from __region_EMAC_DMA_RAM_start__ to __region_EMAC_DMA_RAM_end__];

define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
define block FIQ_STACK with alignment = 8, size = __ICFEDIT_size_fiqstack__ { };
define block UND_STACK with alignment = 8, size = __ICFEDIT_size_undstack__ { };
define block ABT_STACK with alignment = 8, size = __ICFEDIT_size_abtstack__ { };
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };

initialize by copy { readwrite };
do not initialize { section .noinit };
do not initialize { section USB_DMA_RAM };
do not initialize { section EMAC_DMA_RAM };

place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };

place in ROM_region { readonly };
place in RAM_region { readwrite,
block CSTACK, block SVC_STACK, block IRQ_STACK, block FIQ_STACK,
block UND_STACK, block ABT_STACK, block HEAP };
place in USB_DMA_RAM_region
{ section USB_DMA_RAM };
place in EMAC_DMA_RAM_region
{ section EMAC_DMA_RAM };


place at address mem: 0x000001FC { readonly section CRP_section };


Пример icf-файла приложения:

CODE
/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x00002000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x00002044;
define symbol __ICFEDIT_region_ROM_end__ = 0x0001FFFF;
define symbol __ICFEDIT_region_RAM_start__ = 0x40000040;
define symbol __ICFEDIT_region_RAM_end__ = 0x40007FFF;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__ = 0x400;
define symbol __ICFEDIT_size_svcstack__ = 0x100;
define symbol __ICFEDIT_size_irqstack__ = 0x100;
define symbol __ICFEDIT_size_fiqstack__ = 0x40;
define symbol __ICFEDIT_size_undstack__ = 0x10;
define symbol __ICFEDIT_size_abtstack__ = 0x10;
define symbol __ICFEDIT_size_heap__ = 0x2000;
/**** End of ICF editor section. ###ICF###*/


define memory mem with size = 4G;
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];

define symbol __region_USB_DMA_RAM_start__ = 0x7FD00000;
define symbol __region_USB_DMA_RAM_end__ = 0x7FD01FFF;
define region USB_DMA_RAM_region= mem:[from __region_USB_DMA_RAM_start__ to __region_USB_DMA_RAM_end__];

define symbol __region_EMAC_DMA_RAM_start__ = 0x7FE00000;
define symbol __region_EMAC_DMA_RAM_end__ = 0x7FE03FFF;
define region EMAC_DMA_RAM_region= mem:[from __region_EMAC_DMA_RAM_start__ to __region_EMAC_DMA_RAM_end__];

define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
define block FIQ_STACK with alignment = 8, size = __ICFEDIT_size_fiqstack__ { };
define block UND_STACK with alignment = 8, size = __ICFEDIT_size_undstack__ { };
define block ABT_STACK with alignment = 8, size = __ICFEDIT_size_abtstack__ { };
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };

initialize by copy { readwrite };
do not initialize { section .noinit };
do not initialize { section USB_DMA_RAM };
do not initialize { section EMAC_DMA_RAM };

place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };

place in ROM_region { readonly };
place in RAM_region { readwrite,
block CSTACK, block SVC_STACK, block IRQ_STACK, block FIQ_STACK,
block UND_STACK, block ABT_STACK, block HEAP };
place in USB_DMA_RAM_region
{ section USB_DMA_RAM };
place in EMAC_DMA_RAM_region
{ section EMAC_DMA_RAM };

Metallist64
Большое спасибо!
Пойду разбираться!
Lexy_one
Здраствуйте я прочитал топик... вроде большынство доводов понятно..
есть один вопросик:
Так все таки нужно ремап далать или нет? Или можно коду загрузчика работать из флеш?
kovigor
Цитата(Lexy_one @ Jul 11 2011, 14:34) *
Здраствуйте я прочитал топик... вроде большынство доводов понятно..
есть один вопросик:
Так все таки нужно ремап далать или нет? Или можно коду загрузчика работать из флеш?

Ремап таблицы векторов нужен, если вы не запрещаете прерывания на время выполнения IAP. Иначе не нужен.
skripach
Цитата
Или можно коду загрузчика работать из флеш?

Нужно.
Lexy_one
И еще пара вопросиков sm.gif
1) допустим у меня приложение начинается с адреса 0х020000. достаточно ли просто для старта приложения перейти по указанному адресу? или нет?
2) в НЕХ файле приложения есть запись с типом 05 (линейный адрес старта) что с ней делать? можно ли ее проигнорировать или нет? в описании стандарта Intel-HEX указанно что эта запись указывает на адрес с которого начинается исполнение объектного файла - значит ее надо кудато запихнуть, а куда...?

Подскажите кто знает!
Lexy_one
И еще подскажите как корректно перейти из основного приложание в загрузчик?
Достаточно ли просто по ссылке или через WatcDog?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.