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 CInterruptVectorTable
che 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 CInterruptVectorTable
implementa 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 static
poiché il controller non può fornire un this
puntatore poiché la tabella vettoriale non è un oggetto. Quindi per pThis
ovviare 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 SetIsrCallbackfunction
per fornire un puntatore a una static
funzione 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 static
metodo di un'altra classe (che può essere private
), che quindi può contenere un altro static
this
puntatore per ottenere l'accesso alle variabili membro di quell'oggetto (solo uno).
Suppongo che potresti costruire e interfacciare come IInterruptHandler
e memorizzare puntatori agli oggetti, quindi non hai bisogno del static
this
puntatore 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 ICallback
che 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 this
puntatori 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.