Obecnie koduję dla Cortex M0 / M4, a podejście, którego używamy w C ++ (nie ma znacznika C ++, więc ta odpowiedź może być nie na temat) jest następujące:
Używamy klasy, CInterruptVectorTable
która zawiera wszystkie procedury obsługi przerwań zapisane w rzeczywistym wektorze przerwań kontrolera:
#pragma location = ".intvec"
extern "C" const intvec_elem __vector_table[] =
{
{ .__ptr = __sfe( "CSTACK" ) }, // 0x00
__iar_program_start, // 0x04
CInterruptVectorTable::IsrNMI, // 0x08
CInterruptVectorTable::IsrHardFault, // 0x0C
//[...]
}
Klasa CInterruptVectorTable
implementuje abstrakcję wektorów przerwań, dzięki czemu można powiązać różne funkcje z wektorami przerwań podczas działania.
Interfejs tej klasy wygląda następująco:
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;
};
Musisz wykonać funkcje, które są przechowywane w tablicy wektorów, static
ponieważ kontroler nie może dostarczyć wskaźnika this
-po, ponieważ tablica wektorów nie jest obiektem. Aby obejść ten problem, mamy wskaźnik statyczny w pThis
środku CInterruptVectorTable
. Po wejściu w jedną z funkcji statycznego przerywania, może uzyskać dostęp do pThis
wskaźnika -po, aby uzyskać dostęp do członków jednego obiektu CInterruptVectorTable
.
Teraz w programie możesz użyć wskaźnika, SetIsrCallbackfunction
aby dostarczyć wskaźnik funkcji do static
funkcji, która ma być wywoływana, gdy nastąpi przerwanie. Wskaźniki są przechowywane w InterruptVectorTable_t virtualVectorTable
.
Implementacja funkcji przerwania wygląda następująco:
void CInterruptVectorTable::IsrNMI(void) {
pThis->virtualVectorTable.IsrNMI();
}
To wywoła static
metodę innej klasy (która może być private
), która następnie może zawierać inną static
this
-pointer, aby uzyskać dostęp do zmiennych składowych tego obiektu (tylko jednej).
Sądzę, że możesz budować i interfejsować jak IInterruptHandler
i przechowywać wskaźniki do obiektów, więc nie potrzebujesz wskaźnika static
this
-po wszystkich tych klasach. (może spróbujemy tego w następnej iteracji naszej architektury)
Drugie podejście działa dla nas dobrze, ponieważ jedynymi obiektami, które mogą zaimplementować moduł obsługi przerwań, są te znajdujące się w warstwie abstrakcji sprzętu, i zwykle mamy tylko jeden obiekt dla każdego bloku sprzętowego, więc dobrze działa z static
this
-pointerami. Warstwa abstrakcji sprzętowej zapewnia jeszcze jedną abstrakcję przerwań, nazywaną ICallback
następnie implementowaną w warstwie urządzeń nad sprzętem.
Czy uzyskujesz dostęp do danych globalnych? Jasne, że tak, ale większość prywatnych danych globalnych można this
ustawić jako prywatne, takie jak wskaźniki i funkcje przerwania.
Nie jest kuloodporny i dodaje napowietrznych. Będziesz miał trudności z wdrożeniem stosu IO-Link przy użyciu tego podejścia. Ale jeśli nie jesteś bardzo napięty z taktowaniem, działa to całkiem dobrze, aby uzyskać elastyczną abstrakcję przerwań i komunikacji w modułach bez użycia zmiennych globalnych, które są dostępne zewsząd.