Перейти к содержанию
    

LPC11xx(C-M0) ремап векторов в RAM

Здраствуйте.

Пытаюсь сделать ремап векторов прерываний на ОЗУ.

Последовательность такая.

Создаю секцию в 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:

#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();
//....... код


 

Вроде работает. Но может это только пока, а потом перестанет?

Может есть какие-то способы получше?

Кто как делает подобные действия?

 

Спасибо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да вроде бы все. Обратите внимание на тонкость: после ремапа ваша новая таблица закроет часть флеша и если эта часть случайно в целях экономии используется не как остаток оригинальной таблицы, а для кода исполняемого после ремапа - будет ой. В этом случае надо вручную разместить туда код, выполняющийся только до ремапа.

 

Не ясна лишь цель всего этого. Я использую ремап для запуска приложения из загрузчика, и просто копирую таблицу. У вас же, очевидно, какая-то другая цель. Какая? Подмена на лету каких-то отдельных векторов? Просто любопытно. Ну и, может быть, зная цель придет в голову какое-то альтернативное решение.

 

Для удобства в вашем случае можно вектора периферии оформить в виде массива и заполнять, используя в качестве индекса xxx_IRQn.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не ясна лишь цель всего этого.

Цель простая: стандартная задача. Видимо я что-то не так понял и мне первым на ум пришёл какой-то альтернативный вариант и всё делается проще. Наверное надо ещё разок заглянуть в appn по secondary bootloader.

Так вот цель: в начале флэш от 0 до N - bootloader (сколько это N пока не знаю). От N до конца - приложение. Соответственно вектора находятся по адресам от 0 до 0xC0 и прошиты раз и навсегда (переписывать boot мне как-то не хочется).

Можно конечно располагать в application-области обработчики по фиксированным адресам (кстати ещё не пробовал), а в boot вообще не использовать прерывания (что кстати и напрашивается). Хм.

Получается, что ремап даёт полную отвязку от прошитых векторов, что может и не нужно, если вектора указывают на область приложения.

 

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

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А вы как делали?
Несколько проще. Загрузчик занимает место с 0 до 0x1000. Со своими векторами, прибитыми гвоздями. Приложение линкуется как обычно, но начиная не с 0, а с 0x1000, в остальном это обычная программа:
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 */
}

 

Для загрузчика карта памяти будет, соответственно:

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:

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 только занятой памяти:

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;
};

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо за пример.

Ещё такой вопрос: как отлаживать такую программу? Создавать два ld-файла - Debug (заполняет флеш от 0) и Release (заполняет флеш начиная от 0x1000)? Или есть более другие способы?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ещё такой вопрос: как отлаживать такую программу? Создавать два ld-файла - Debug (заполняет флеш от 0) и Release (заполняет флеш начиная от 0x1000)? Или есть более другие способы?
Смотря чем отлаживать. Для OpenOCD в аналогичном случае с SAM7 писал скрипт, который после загрузки и ресета делает то же, что и загрузчик - копирует вектора, делает remap, передает управление на нулевой вектор. Здесь надо будет сделать то же самое, плюс загрузить указатель стека из начала таблицы и вместо передачи управления грузить PC из вектора. Еще не помешает добавить ORIGIN() в скрипт.

 

А как такое сделать с LPCXpresso - не знаю, не разбирался. Я сначала написал загрузчик, а перед отладкой приложения закомментировал в нем проверку правильности контрольной суммы и он всегда запускал свежепрошитое отладчиком приложение.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Смотря чем отлаживать. Для OpenOCD в аналогичном случае с SAM7 писал скрипт, который после загрузки и ресета делает то же, что и загрузчик - копирует вектора, делает remap, передает управление на нулевой вектор. Здесь надо будет сделать то же самое, плюс загрузить указатель стека из начала таблицы и вместо передачи управления грузить PC из вектора. Еще не помешает добавить ORIGIN() в скрипт.

 

А как такое сделать с LPCXpresso - не знаю, не разбирался. Я сначала написал загрузчик, а перед отладкой приложения закомментировал в нем проверку правильности контрольной суммы и он всегда запускал свежепрошитое отладчиком приложение.

 

Да, не АВР. Буду разбираться.

Спасибо.

 

Еще момент:

Из карты для загрузчика:

REMAPPED (xrw)  : ORIGIN = 0x10000000, LENGTH =  512

 

Почему 512? С чем это связано?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Почему 512? С чем это связано?
С документацией:

3.5.1 System memory remap register

The system memory remap register selects whether the ARM interrupt vectors are read

from the boot ROM, the flash, or the SRAM. By default, the flash memory is mapped to

address 0x0000 0000. When the MAP bits in the SYSMEMREMAP register are set to 0x0

or 0x1, the boot ROM or RAM respectively are mapped to the bottom 512 bytes of the

memory map (addresses 0x0000 0000 to 0x0000 0200).

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

С документацией:

Да, дело было в документации: у меня мануал был версии годовой давности и нём от вашей цитаты только первое предложение, про 512 байт - ничего. Обновил - увидел.

 

Спасибо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...