Estoy codificando para Cortex M0 / M4 en este momento y el enfoque que estamos usando en C ++ (no hay una etiqueta de C ++, por lo que esta respuesta podría estar fuera de tema) es la siguiente:
Utilizamos una clase CInterruptVectorTable
que contiene todas las rutinas de servicio de interrupción que se almacenan en el vector de interrupción real del 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
//[...]
}
La clase CInterruptVectorTable
implementa una abstracción de los vectores de interrupción, por lo que puede vincular diferentes funciones a los vectores de interrupción durante el tiempo de ejecución.
La interfaz de esa clase se ve así:
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;
};
Debe realizar las funciones que están almacenadas en la tabla de vectores static
porque el controlador no puede proporcionar un puntero this
ya que la tabla de vectores no es un objeto. Entonces, para solucionar ese problema, tenemos el punto estático pThis
dentro del CInterruptVectorTable
. Al ingresar a una de las funciones de interrupción estática, puede acceder al puntero pThis
para obtener acceso a los miembros del único objeto de CInterruptVectorTable
.
Ahora en el programa, puede usar SetIsrCallbackfunction
para proporcionar un puntero a una función static
que se llamará cuando ocurra una interrupción. Los punteros se almacenan en el InterruptVectorTable_t virtualVectorTable
.
Y la implementación de una función de interrupción se ve así:
void CInterruptVectorTable::IsrNMI(void) {
pThis->virtualVectorTable.IsrNMI();
}
Entonces, se llamará al método static
de otra clase (que puede ser private
), que luego puede contener otro static
this
-pointer para obtener acceso a las variables miembro de ese objeto (solo una ).
Supongo que podría crear e interactuar como IInterruptHandler
y almacenar punteros a objetos, por lo que no necesita el puntero static
this
en todas esas clases. (tal vez lo intentemos en la próxima iteración de nuestra arquitectura)
El otro enfoque funciona bien para nosotros, ya que los únicos objetos que pueden implementar un controlador de interrupciones son aquellos que se encuentran dentro de la capa de abstracción de hardware, y generalmente solo tenemos un objeto para cada bloque de hardware, por lo que está bien trabajar con static
this
-puntos. Y la capa de abstracción del hardware proporciona otra abstracción a las interrupciones, denominada ICallback
, que luego se implementa en la capa del dispositivo sobre el hardware.
¿Accedes a los datos globales? Claro que sí, pero puede hacer que la mayoría de los datos globales necesarios sean privados, como los puntos this
y las funciones de interrupción.
No es a prueba de balas, y agrega gastos generales. Tendrá dificultades para implementar una pila IO-Link utilizando este enfoque. Pero si no estás muy ajustado a los tiempos, esto funciona bastante bien para obtener una abstracción flexible de interrupciones y comunicación en módulos sin utilizar variables globales a las que se pueda acceder desde cualquier lugar.