Возможность это всегда хорошо. Но вот как это сделать максимально удобно и прозрачно? Рассмотрим на примере компилятора от IAR.
Решение в лоб: создать массив в ОЗУ по фиксированному адресу (не в любом месте может быть новая таблица, а только в строго определённом - Top of RAM, как утверждает руководство) и заполнять его ручками:
__interrupt void YYY_handler (void)
{ /* ... */ }
__root __no_init uint16_t int_table[] @ TOP_OF_RAM;
int_vector_table[yyy] = YYY_handler;
Это замечательно, но хотелось бы сделать максимально "похоже" на обычную таблицу:#pragma vector=YYY
__interrupt void YYY_handler (void)
{
}
Таблица векторов, заданных через #pragma vector, размещается в секции INTVEC, которая располагается по адресам FF80-FFFF. Нам надо создать новую секцию такого же размера, но только в ОЗУ (я назвал новую секцию INTRAMVEC). Для это подправим linker-script, а именно ту часть, которая описывает распределение ОЗУ*:
Было:
// -----------------------------------------------
// Read/write memory
//
-Z(DATA)DATA16_I,DATA16_Z,DATA16_N,TLS16_I,DATA16_HEAP+_DATA16_HEAP_SIZE=2400-63FF
-Z(DATA)CODE_I
-Z(DATA)DATA20_I,DATA20_Z,DATA20_N,DATA20_HEAP+_DATA20_HEAP_SIZE
-Z(DATA)CSTACK+_STACK_SIZE#
Стало:
// -----------------------------------------------
// Read/write memory
//
-Z(DATA)DATA16_I,DATA16_Z,DATA16_N,TLS16_I,DATA16_HEAP+_DATA16_HEAP_SIZE=2400-637F
-Z(DATA)CODE_I
-Z(DATA)DATA20_I,DATA20_Z,DATA20_N,DATA20_HEAP+_DATA20_HEAP_SIZE
-Z(DATA)CSTACK+_STACK_SIZE#
-Z(DATA)INTRAMVEC=6380-63FF
* в данном примере адреса указаны для MSP430F6638. Для других МК адреса могут отличаться, но общий принцип тот же: секция INTRAMVEC располагается по самым старшим адресам ОЗУ и равна по размеру INTVEC.Место выделили, осталось его заполнить (скопировать INTVEC в INTRAMVEC):
#pragma segment="INTVEC"
#pragma segment="INTRAMVEC"
int __low_level_init (void)
{
WDTCTL = WDTPW | WDTHOLD;
/* Copy interrupt vector table content
from INTVEC to INTRAMVEC */
void * intramvec_begin = __segment_begin("INTRAMVEC");
void * intvec_begin = __segment_begin("INTVEC");
size_t intvec_size = __segment_size("INTVEC");
memcpy(intramvec_begin, intvec_begin, intvec_size);
/* Switch to interrupt vector table in RAM */
SYSCTL |= SYSRIVECT;
return 1;
}
Одно из возможных применений: можно хранить в МК несколько версий прошивки и запускать именно ту, что нужна. Это возможно т.к. каждая версия прошивки будет копировать свою таблицу векторов прерываний.
Комментариев нет:
Отправить комментарий