Комментарии 9
Вроде бы в cmsis определена функция NVIC_SetVector?
0
А не проще завести указатель на функцию, и в обработчике вызывать функцию по этому указателю? А уже сам указатель менять как вам надо. Или расходы на +1 вызов имеют значение?
+1
Я вот даже использую для этих целей статический член класса. И могу описывать прерывание внутри объекта, и каждый тип «драйвера» имеет свой обработчик. крайне читаемый код получается
0
просьба выложить пример кода с таким стат. обработчиком в классе
0
В целом я делаю так.
Тут описание
Это просто идея, которая мне нравится. Я не делают время-критичных устройств и лишний call-другой мне погоду не делает.
Как мне кажется, каждый такой «драйвер» получается крайне читаемым с точки зрения алгоритма работы. Но это лишь мое мнение
К примеру, у нас есть класс для уарт.
Данный указатель на себя нужен для того, чтобы получить доступ к самому классу изнутри статической функции — нашего обработчика прерываний. Так как хоть привязки к классу нет, но статический метод имеет доступ к другим статическим членам класса.
В инициализации он устанавливается через блок switch, к примеру, так:
Где наш обработчик выглядит так
Это наш базовый placeholder, тут можно выполнять нужные нам действия.
Теперь мы поверх этого класса наследуемся, скажем, в класс GPS
Спокойно пишем свой обработчик внутри GPS класса
Каждый объект — устройство, работающий поверх UART при создании ставят свой обработчик в таблицу прерываний, сохраняя предыдущее значение. В деструкторе восстанавливают предыдущее состояние.
Всё то же самое для SPI, I2C, DMA и прочих SDIO
Как мне кажется, каждый такой «драйвер» получается крайне читаемым с точки зрения алгоритма работы. Но это лишь мое мнение
К примеру, у нас есть класс для уарт.
class Uart
{
public:
Uart (short ch, word bd, bool doinit);
Uart (short ch, word bd, word isrptr = 0);
~Uart(void);
static class Uart *self;
static void isr (void);
//тут какой-то код
protected:
//тут всякое разное
USART_TypeDef* Reg;
};
static class Uart *self;
Данный указатель на себя нужен для того, чтобы получить доступ к самому классу изнутри статической функции — нашего обработчика прерываний. Так как хоть привязки к классу нет, но статический метод имеет доступ к другим статическим членам класса.
USART_TypeDef* Reg
Является указателем на нужный нам регистр нужного порта для автоматизации.В инициализации он устанавливается через блок switch, к примеру, так:
__disable_irq();
self = this;
....
switch (channel)
.....
Reg = (USART_TypeDef*) USART1_BASE;
IRQ_VECTOR_TABLE[USART1_IRQn + IRQ0_EX] = isrptr;
....
init();
__enable_irq();
Где наш обработчик выглядит так
class Uart *Uart::self = nullptr;
...
void Uart::isr(void)
{
if (self->Reg->SR & USART_SR_RXNE) //receive
{
self->Reg->SR &= ~USART_SR_RXNE;
}
else if (self->Reg->SR & USART_SR_TC) //transfer
{
self->Reg->SR &= ~USART_SR_TC;
}
}
Это наш базовый placeholder, тут можно выполнять нужные нам действия.
Теперь мы поверх этого класса наследуемся, скажем, в класс GPS
class Gps: public Uart
{
public:
Gps(short ch, word bd) :
Uart::Uart(ch, bd, (word) &gpsisr)
{
Gps::self = this;
}
static void gpsisr(void);
static class Gps *self;
};
Спокойно пишем свой обработчик внутри GPS класса
void Gps::gpsisr(void)
{
if (self->Reg->SR & USART_SR_RXNE)
{
short a = self->Reg->DR;
self->Reg->SR &= ~USART_SR_RXNE;
if (self->ready)
{
return;
}
if (0 == self->nmeastr_len && '$' != a)
{
return;
}
.....................И.Т.Д.
}
}
Каждый объект — устройство, работающий поверх UART при создании ставят свой обработчик в таблицу прерываний, сохраняя предыдущее значение. В деструкторе восстанавливают предыдущее состояние.
Всё то же самое для SPI, I2C, DMA и прочих SDIO
+1
Я писал для ARM7, там все было проще — есть регистры в которых хранятся указатели на обработчики прерываний, просто записывал в такой регистр новое значение и все. Понадобилось такое, когда нужно было обрабатывать четные и нечетные прерывания от таймера или периферии немного по-разному… Оказалось быстрее написать два обработчика и переключаться между ними в конце обработки очередного прерывания, чем писать «if» внутри единого обработчика.
0
одно не понял, а зачем так мудрено копировать ?!!! или это компилятор Си так поизвращался?
<source lang=«XML»
CopyVectorTable:
ldr r0, =_sivector //Записываем в регистр R0 начальный адрес таблицы прерываний во flash-памяти
ldr r1, =_svector //Записываем в регистр R1 начальный адрес таблицы прерываний в оперативной памяти
MOV R4, R1
ldr r2, =_evector //Записываем в регистр R2 конечный адрес таблицы прерываний в оперативной памяти
loop:
LDR R3, [R0]+4!
STR R3, [R1]+4!
CMP R2, R3
BNE LOOP
ldr r2, =VTOR //Записываем адрес регистра VTOR в регистр r2
str r4, [r2] //Записываем по адреcу, содержащемся в r2 значение r0
<source lang=«XML»
CopyVectorTable:
ldr r0, =_sivector //Записываем в регистр R0 начальный адрес таблицы прерываний во flash-памяти
ldr r1, =_svector //Записываем в регистр R1 начальный адрес таблицы прерываний в оперативной памяти
MOV R4, R1
ldr r2, =_evector //Записываем в регистр R2 конечный адрес таблицы прерываний в оперативной памяти
loop:
LDR R3, [R0]+4!
STR R3, [R1]+4!
CMP R2, R3
BNE LOOP
ldr r2, =VTOR //Записываем адрес регистра VTOR в регистр r2
str r4, [r2] //Записываем по адреcу, содержащемся в r2 значение r0
+1
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Динамическое управление прерываниями в ARM