реклама на сайте
подробности

 
 
> LPC11xx(C-M0) ремап векторов в RAM
_Артём_
сообщение Mar 26 2012, 21:36
Сообщение #1


Гуру
******

Группа: Свой
Сообщений: 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();
//....... код




Вроде работает. Но может это только пока, а потом перестанет?
Может есть какие-то способы получше?
Кто как делает подобные действия?

Спасибо.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Сергей Борщ
сообщение Mar 26 2012, 21:58
Сообщение #2


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Mar 26 2012, 22:28
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 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 вообще не использовать прерывания (что кстати и напрашивается). Хм.
Получается, что ремап даёт полную отвязку от прошитых векторов, что может и не нужно, если вектора указывают на область приложения.

А вы как делали?

Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 27 2012, 06:16
Сообщение #4


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Mar 27 2012, 15:30
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Спасибо за пример.
Ещё такой вопрос: как отлаживать такую программу? Создавать два ld-файла - Debug (заполняет флеш от 0) и Release (заполняет флеш начиная от 0x1000)? Или есть более другие способы?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 27 2012, 18:59
Сообщение #6


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Mar 28 2012, 21:54
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 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? С чем это связано?
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 02:41
Рейтинг@Mail.ru


Страница сгенерированна за 0.0146 секунд с 7
ELECTRONIX ©2004-2016