|
LPC11xx(C-M0) ремап векторов в RAM |
|
|
|
Mar 26 2012, 21:36
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Здраствуйте. Пытаюсь сделать ремап векторов прерываний на ОЗУ. Последовательность такая. Создаю секцию в ld-файле: Код MEMORY { TEXT (rx) : ORIGIN = 0x00000000, LENGTH = 32K RAMVectorTable (rwx) : ORIGIN = 0x10000000, LENGTH = 256 RAM (xrw) : ORIGIN = 0x10000100, LENGTH = 0x1F00 }
.IntVecTable : { *(.IntVecTable) } > RAMVectorTable структура таблицы векторов(vector_table.h): Код #define LPC11XX_VECTOR_QTY 47 typedef void (*ISRPtr) (void); struct TLPC11xxVectorTable { ISRPtr StackPtr;// уже не нужен ISRPtr ResetISR;// уже не нужен ISRPtr Reserved0[9]; ISRPtr SvcISR; ISRPtr Reserved1[2]; ISRPtr PendSvcISR; ISRPtr SysTickISR; /* Device interrupt vectors */ ISRPtr WakeUpISR[13]; ISRPtr Reserved2; ISRPtr Ssp1ISR; ISRPtr I2cISR; ISRPtr Timer16_0_ISR; ISRPtr Timer16_1_ISR; ISRPtr Timer32_0_ISR; ISRPtr Timer32_1_ISR; ISRPtr Ssp0ISR; ISRPtr UART_ISR; ISRPtr Reserved3[2]; ISRPtr ADC_ISR; ISRPtr Wdt_ISR; ISRPtr Bod_ISR; ISRPtr Reserved4; ISRPtr EINT3_ISR; ISRPtr EINT2_ISR; ISRPtr EINT1_ISR; ISRPtr EINT0_ISR; void SetDefault(ISRPtr default_handler); }; main.cpp: CODE #include "vector_table.h" __attribute__ ((__section__(".IntVecTable"))) struct TLPC11xxVectorTable IntVecTable;
extern "C" void SVC_Handler(void); extern "C" void PendSVC_ISR(void); extern "C" void Default_Handler(void);
void InitVectorTable() { IntVecTable.SvcISR=&SVC_Handler; IntVecTable.PendSvcISR=&PendSVC_ISR; IntVecTable.SysTickISR=&OS::SystemTimer_ISR; IntVecTable.Timer16_0_ISR=&Timer16_0_IRQ_Handler; IntVecTable.UART_ISR=&UART_IRQ_Handler; LPC_SYSCON->SYSMEMREMAP=1; }
void TLPC11xxVectorTable::SetDefault(ISRPtr default_handler) { ISRPtr *isr_ptr=&ResetISR; for (uint8_t i=0; i<LPC11XX_VECTOR_QTY; i++) *isr_ptr++=default_handler; for (uint8_t i=0; i<9; i++) Reserved0[i]=0; Reserved4= Reserved3[0]=Reserved3[1]= Reserved2= Reserved1[0]=Reserved1[1]=0; }
int main() { IntVecTable.SetDefault(&Default_Handler); InitVectorTable(); //....... код
Вроде работает. Но может это только пока, а потом перестанет? Может есть какие-то способы получше? Кто как делает подобные действия? Спасибо.
|
|
|
|
|
 |
Ответов
|
Mar 26 2012, 21:58
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Да вроде бы все. Обратите внимание на тонкость: после ремапа ваша новая таблица закроет часть флеша и если эта часть случайно в целях экономии используется не как остаток оригинальной таблицы, а для кода исполняемого после ремапа - будет ой. В этом случае надо вручную разместить туда код, выполняющийся только до ремапа.
Не ясна лишь цель всего этого. Я использую ремап для запуска приложения из загрузчика, и просто копирую таблицу. У вас же, очевидно, какая-то другая цель. Какая? Подмена на лету каких-то отдельных векторов? Просто любопытно. Ну и, может быть, зная цель придет в голову какое-то альтернативное решение.
Для удобства в вашем случае можно вектора периферии оформить в виде массива и заполнять, используя в качестве индекса xxx_IRQn.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Mar 26 2012, 22:28
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(Сергей Борщ @ Mar 27 2012, 00:58)  Не ясна лишь цель всего этого. Цель простая: стандартная задача. Видимо я что-то не так понял и мне первым на ум пришёл какой-то альтернативный вариант и всё делается проще. Наверное надо ещё разок заглянуть в appn по secondary bootloader. Так вот цель: в начале флэш от 0 до N - bootloader (сколько это N пока не знаю). От N до конца - приложение. Соответственно вектора находятся по адресам от 0 до 0xC0 и прошиты раз и навсегда (переписывать boot мне как-то не хочется). Можно конечно располагать в application-области обработчики по фиксированным адресам (кстати ещё не пробовал), а в boot вообще не использовать прерывания (что кстати и напрашивается). Хм. Получается, что ремап даёт полную отвязку от прошитых векторов, что может и не нужно, если вектора указывают на область приложения. А вы как делали?
|
|
|
|
|
Mar 27 2012, 06:16
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (_Артём_ @ Mar 27 2012, 01:28)  А вы как делали? Несколько проще. Загрузчик занимает место с 0 до 0x1000. Со своими векторами, прибитыми гвоздями. Приложение линкуется как обычно, но начиная не с 0, а с 0x1000, в остальном это обычная программа: CODE MEMORY { REMAPED(r) : ORIGIN = 0x00000000, LENGTH = 192 /* 192 = vectors table size */ TEXT (rx) : ORIGIN = 0x00001000, LENGTH = 32K - 4K - 4K /* 4K - boot, 4K - config */ CONFIG(r) : ORIGIN = 32K - 4K, LENGTH = 4K
RAM (rw) : ORIGIN = 0x10000000 + 192, LENGTH = 8K - 192 - 32 /* 192 - remaped vectors, 32 - iap working area */ } Для загрузчика карта памяти будет, соответственно: CODE MEMORY { TEXT (rx) : ORIGIN = 0x00000000, LENGTH = 4K
APPLICATION(rx) : ORIGIN = 4K, LENGTH = 32K - 4K - 4K /* 4K - boot, 4K - config */ CONFIG(r) : ORIGIN = 32K - 4K, LENGTH = 4K
RAM (rw) : ORIGIN = 0x10000000 + 512, LENGTH = 8K - 512 - 32 /* 32 - IAP reserved space */ REMAPPED (xrw) : ORIGIN = 0x10000000, LENGTH = 512 /* 512 = remappable area size */ } SECTIONS { .remapped (NOLOAD) : { _remap_area = .; } > REMAPPED ....... .application (NOLOAD): { Application = .; } > APPLICATION } И загрузчик просто копирует всю таблицу векторов приложения начиная с метки Application в _remap_area: CODE struct application { struct vectors { typedef void( *handler )( void ); uint32_t MSP_init; handler Reset_vector; handler Core_handler[14]; handler MCU_handler[32]; } Vectors; };
extern const application Application; extern application::vectors _remap_area;
.... if (CRC.ok()) // Application Section OK { // copy application vectors table to remap area // memcpy(&_remap_area, &Application.Vectors, sizeof(Application.Vectors)); uint32_t const * pSrc = (uint32_t const *)&Application.Vectors; uint32_t * pDst = (uint32_t *)&_remap_area; do { *pDst++ = *pSrc++; } while(pSrc < (uint32_t const *)(&Application.Vectors + 1));
asm volatile ( " MSR MSP, %0\n" // store App stack init value to MSP : : "r" (Application.Vectors.MSP_init) ); LPC_SYSCON->SYSMEMREMAP = LPC_MAP_RAM; // remap to ram Application.Vectors.Reset_vector(); } } Вообще-то у меня еще в начале приложения хранится его размер, чтобы считать CRC только занятой памяти: CODE struct application { uint32_t Size;
struct vectors { typedef void( *handler )( void ); uint32_t MSP_init; handler Reset_vector; handler Core_handler[14]; handler MCU_handler[32]; } Vectors; };
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Mar 27 2012, 18:59
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (_Артём_ @ Mar 27 2012, 18:30)  Ещё такой вопрос: как отлаживать такую программу? Создавать два ld-файла - Debug (заполняет флеш от 0) и Release (заполняет флеш начиная от 0x1000)? Или есть более другие способы? Смотря чем отлаживать. Для OpenOCD в аналогичном случае с SAM7 писал скрипт, который после загрузки и ресета делает то же, что и загрузчик - копирует вектора, делает remap, передает управление на нулевой вектор. Здесь надо будет сделать то же самое, плюс загрузить указатель стека из начала таблицы и вместо передачи управления грузить PC из вектора. Еще не помешает добавить ORIGIN() в скрипт. А как такое сделать с LPCXpresso - не знаю, не разбирался. Я сначала написал загрузчик, а перед отладкой приложения закомментировал в нем проверку правильности контрольной суммы и он всегда запускал свежепрошитое отладчиком приложение.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Mar 28 2012, 21:54
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(Сергей Борщ @ Mar 27 2012, 21:59)  Смотря чем отлаживать. Для OpenOCD в аналогичном случае с SAM7 писал скрипт, который после загрузки и ресета делает то же, что и загрузчик - копирует вектора, делает remap, передает управление на нулевой вектор. Здесь надо будет сделать то же самое, плюс загрузить указатель стека из начала таблицы и вместо передачи управления грузить PC из вектора. Еще не помешает добавить ORIGIN() в скрипт.
А как такое сделать с LPCXpresso - не знаю, не разбирался. Я сначала написал загрузчик, а перед отладкой приложения закомментировал в нем проверку правильности контрольной суммы и он всегда запускал свежепрошитое отладчиком приложение. Да, не АВР. Буду разбираться. Спасибо. Еще момент: Из карты для загрузчика: Код REMAPPED (xrw) : ORIGIN = 0x10000000, LENGTH = 512 Почему 512? С чем это связано?
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|