Sto codificando per Cortex M0 / M4 al momento e l'approccio che stiamo usando in C ++ (non esiste un tag C ++, quindi questa risposta potrebbe essere off-topic) è il seguente:
Usiamo una classe CInterruptVectorTableche contiene tutte le routine di servizio di interrupt che sono memorizzate nel vettore di interrupt effettivo del controller:
#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 classe CInterruptVectorTableimplementa un'astrazione dei vettori di interruzione, quindi è possibile associare diverse funzioni ai vettori di interruzione durante il runtime.
L'interfaccia di quella classe si presenta così:
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;
};
È necessario creare le funzioni memorizzate nella tabella vettoriale staticpoiché il controller non può fornire un thispuntatore poiché la tabella vettoriale non è un oggetto. Quindi per pThisovviare a questo problema abbiamo il puntatore statico all'interno di CInterruptVectorTable. Entrando in una delle funzioni di interruzione statica, può accedere al pThis-pointer per accedere ai membri dell'uno oggetto di CInterruptVectorTable.
Ora nel programma, è possibile utilizzare il SetIsrCallbackfunctionper fornire un puntatore a una staticfunzione che deve essere chiamata quando si verifica un interrupt. I puntatori sono memorizzati nel file InterruptVectorTable_t virtualVectorTable.
E l'implementazione di una funzione di interruzione è simile alla seguente:
void CInterruptVectorTable::IsrNMI(void) {
pThis->virtualVectorTable.IsrNMI();
}
In questo modo verrà chiamato un staticmetodo di un'altra classe (che può essere private), che quindi può contenere un altro static thispuntatore per ottenere l'accesso alle variabili membro di quell'oggetto (solo uno).
Suppongo che potresti costruire e interfacciare come IInterruptHandlere memorizzare puntatori agli oggetti, quindi non hai bisogno del static thispuntatore in tutte quelle classi. (forse lo proveremo nella prossima iterazione della nostra architettura)
L'altro approccio funziona bene per noi, poiché gli unici oggetti autorizzati a implementare un gestore di interrupt sono quelli all'interno del livello di astrazione hardware e di solito abbiamo solo un oggetto per ogni blocco hardware, quindi funziona bene con static this-pointers. E il livello di astrazione hardware fornisce ancora un'altra astrazione agli interrupt, chiamato ICallbackche viene quindi implementato nel livello del dispositivo sopra l'hardware.
Accedete ai dati globali? Sicuro, ma puoi rendere privati la maggior parte dei dati globali necessari come i thispuntatori e le funzioni di interruzione.
Non è a prova di proiettile e aggiunge sovraccarico. Farai fatica a implementare uno stack IO-Link usando questo approccio. Ma se non si è estremamente stretti con i tempi, questo funziona abbastanza bene per ottenere un'astrazione flessibile di interrupt e comunicazione nei moduli senza usare variabili globali accessibili da ogni parte.