Описывается, как сделать безусловный переход по нужному фиксированному адресу (например 0x108000) для ARM AT91SAM7X256 на языке C в среде IAR Embedded Workbench for ARM (версия 5.20).
Такое понадобилось сделать, когда я хотел поместить во flash две независимые программы - bootloader по адресу 0x100000 (по этому адресу всегда будет старт при включении питания или сбросе) и основная программа по адресу 0x108000. Идея была такая - bootloader может загрузить новую прошивку основной программы по адресу 0x108000 и потом запустить её на выполнение с адреса 0x108000.
Сначала я хотел сделать тупой выход из функции main - в надежде, что попаду в код модуля board_cstartup_iar.s после вызова функции main (там тупое зацикливание loop4: B loop4). Зацикливание я думал переправить на B 0x108000. Но, увы, из этого ничего не получилось - почему-то компилятор генерировал такой код, что выполнение после завершения функции main крутилось на обработке SWI_Handler, и обратно в код board_cstartup_iar.s я не попадал (пробовал вызывать функции exit(), _exit(), __exit(), abort(), пробовал просто прерывать основной цикл main - все без толку). Разбираться, как писать обработчик SWI_Handler (чтобы оттуда передать управление по адресу SWI_Handler), мне не хотелось. Поэтому я поступил проще - вызвал подпрограмму по адресу 0x108000. Сделать это можно двумя способами - применив inline ассемблер (директива asm) или указатель на функцию. Теперь примеры реализации этих двух способов. Переход с помощью команды ассемблера (первый пример) более экономен по использованию памяти, а переход с помощью указателя (второй пример) более удобен в плане документирования - адрес перехода определяется константой PGM_START_ADDRESS.
[Переход в коде директивы asm]
void main()
{
// ... тут настроечный код
while (true)
{
// ... тут основной цикл main, который я прерываю,
// когда нужно закончить работу bootloader
// и сделать переход по адресу 0x108000
}
// ... код завершения, если он нужен
//запрет всех прерываний
AT91C_BASE_AIC->AIC_IDCR = 0xFFFFFFFF;
//безусловный переход по адресу 0x108000
asm("B 0x108000");
}
[Переход с помощью указателя на функцию]
#define PGM_START_ADDRESS 0x108000
void (*pgm_start_address)(void);
void main()
{
// ... тут настроечный код
while (true)
{
// ... тут основной цикл main, который я прерываю,
// когда нужно закончить работу bootloader
// и сделать переход по адресу 0x108000
}
// ... код завершения, если он нужен
//запрет всех прерываний
AT91C_BASE_AIC->AIC_IDCR = 0xFFFFFFFF;
//безусловный переход по адресу 0x108000
pgm_start_address = (void(*)(void))PGM_START_ADDRESS;
pgm_start_address();
}
[Ссылки]
1. IAR EWB for ARM: как
поменять абсолютный начальный адрес выполнения программы.
|
Комментарии
2010-06-3019:52:18 Обсуждение этой темы на electronix: http://electronix.ru/forum/index.php?showtopic=62107
В частности здесь: http://electronix.ru/forum/index.php?s=&showtopic=62107&view=findpost&p=612474 описывается как использовать SWI_Handler для перехода и почему его надо использовать.