Estou codificando para o Cortex M0 / M4 no momento e a abordagem que estamos usando no C ++ (não há tag C ++, portanto, essa resposta pode estar fora do tópico) é a seguinte:
Usamos uma classe CInterruptVectorTable
que contém todas as rotinas de serviço de interrupção que são armazenadas no vetor de interrupção real do controlador:
#pragma location = ".intvec"
extern "C" const intvec_elem __vector_table[] =
{
{ .__ptr = __sfe( "CSTACK" ) }, // 0x00
__iar_program_start, // 0x04
CInterruptVectorTable::IsrNMI, // 0x08
CInterruptVectorTable::IsrHardFault, // 0x0C
//[...]
}
A classe CInterruptVectorTable
implementa uma abstração dos vetores de interrupção, para que você possa vincular diferentes funções aos vetores de interrupção durante o tempo de execução.
A interface dessa classe fica assim:
class CInterruptVectorTable {
public :
typedef void (*IsrCallbackfunction_t)(void);
enum InterruptId_t {
INTERRUPT_ID_NMI,
INTERRUPT_ID_HARDFAULT,
//[...]
};
typedef struct InterruptVectorTable_t {
IsrCallbackfunction_t IsrNMI;
IsrCallbackfunction_t IsrHardFault;
//[...]
} InterruptVectorTable_t;
typedef InterruptVectorTable_t* PinterruptVectorTable_t;
public :
CInterruptVectorTable(void);
void SetIsrCallbackfunction(const InterruptId_t& interruptID, const IsrCallbackfunction_t& isrCallbackFunction);
private :
static void IsrStandard(void);
public :
static void IsrNMI(void);
static void IsrHardFault(void);
//[...]
private :
volatile InterruptVectorTable_t virtualVectorTable;
static volatile CInterruptVectorTable* pThis;
};
Você precisa criar as funções que são armazenadas na tabela de vetores, static
porque o controlador não pode fornecer um this
ponteiro, pois a tabela de vetores não é um objeto. Então, para contornar esse problema, temos o pThis
ponteiro estático dentro do CInterruptVectorTable
. Ao inserir uma das funções de interrupção estática, ele pode acessar o pThis
ponteiro para obter acesso aos membros do único objeto de CInterruptVectorTable
.
Agora no programa, você pode usar o SetIsrCallbackfunction
para fornecer um ponteiro de função para uma static
função que deve ser chamada quando ocorrer uma interrupção. Os ponteiros são armazenados no InterruptVectorTable_t virtualVectorTable
.
E a implementação de uma função de interrupção é assim:
void CInterruptVectorTable::IsrNMI(void) {
pThis->virtualVectorTable.IsrNMI();
}
Portanto, isso chamará um static
método de outra classe (que pode ser private
), que poderá conter outro static
this
-pointer para obter acesso às variáveis-membro desse objeto (apenas uma).
Eu acho que você pode criar e interagir como IInterruptHandler
e armazenar ponteiros para objetos, para não precisar do static
this
ponteiro em todas essas classes. (talvez tentemos isso na próxima iteração da nossa arquitetura)
A outra abordagem funciona bem para nós, já que os únicos objetos permitidos para implementar um manipulador de interrupções são aqueles dentro da camada de abstração de hardware, e geralmente temos apenas um objeto para cada bloco de hardware, portanto, é bom trabalhar com static
this
-pointers. E a camada de abstração de hardware fornece outra abstração para interrupções, chamada ICallback
que é então implementada na camada de dispositivo acima do hardware.
Você acessa dados globais? Claro que sim, mas você pode this
privar a maioria dos dados globais necessários, como as funções -pointers e as interrupções.
Não é à prova de balas, e acrescenta sobrecarga. Você lutará para implementar uma pilha IO-Link usando essa abordagem. Mas se você não é extremamente rigoroso com os tempos, isso funciona muito bem para obter uma abstração flexível de interrupções e comunicação em módulos sem usar variáveis globais acessíveis em qualquer lugar.