Описывается, как сделать безусловный переход по нужному фиксированному адресу (например 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: как поменять абсолютный начальный адрес выполнения программы. |
Комментарии
В частности здесь: http://electronix.ru/forum/index.php?s=&showtopic=62107&view=findpost&p=612474 описывается как использовать SWI_Handler для перехода и почему его надо использовать.
RSS лента комментариев этой записи