Je suis en train de coder pour Cortex M0 / M4 en ce moment et l'approche que nous utilisons en C ++ (il n'y a pas de balise C ++, donc cette réponse pourrait être hors sujet) est la suivante:
Nous utilisons une classe CInterruptVectorTable
qui contient toutes les routines de service d'interruption qui sont stockées dans le vecteur d'interruption réel du contrôleur:
#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
implémente une abstraction des vecteurs d'interruption, vous pouvez donc lier différentes fonctions aux vecteurs d'interruption pendant l'exécution.
L'interface de cette classe ressemble à ceci:
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;
};
Vous devez créer les fonctions qui sont stockées dans la table vectorielle static
car le contrôleur ne peut pas fournir de this
pointeur car la table vectorielle n'est pas un objet. Donc, pour contourner ce problème, nous avons le pThis
pointeur statique à l'intérieur du CInterruptVectorTable
. En entrant dans l'une des fonctions d'interruption statiques, il peut accéder au pThis
pointeur pour accéder aux membres du même objet CInterruptVectorTable
.
Maintenant, dans le programme, vous pouvez utiliser le SetIsrCallbackfunction
pour fournir un pointeur de fonction à une static
fonction qui doit être appelée lorsqu'une interruption se produit. Les pointeurs sont stockés dans le InterruptVectorTable_t virtualVectorTable
.
Et l'implémentation d'une fonction d'interruption ressemble à ceci:
void CInterruptVectorTable::IsrNMI(void) {
pThis->virtualVectorTable.IsrNMI();
}
Donc, cela appellera une static
méthode d'une autre classe (qui peut être private
), qui peut alors contenir un autre static
this
pointeur pour accéder aux variables membres de cet objet (un seul).
Je suppose que vous pourriez construire et interfacer comme IInterruptHandler
et stocker des pointeurs vers des objets, donc vous n'avez pas besoin du static
this
pointeur dans toutes ces classes. (peut-être essayons-nous cela dans la prochaine itération de notre architecture)
L'autre approche fonctionne bien pour nous, car les seuls objets autorisés à implémenter un gestionnaire d'interruption sont ceux à l'intérieur de la couche d'abstraction matérielle, et nous n'avons généralement qu'un seul objet pour chaque bloc matériel, donc cela fonctionne bien avec les static
this
pointeurs. Et la couche d'abstraction matérielle fournit une autre abstraction aux interruptions, appelée ICallback
qui est ensuite implémentée dans la couche de périphérique au-dessus du matériel.
Accédez-vous aux données globales? Bien sûr, mais vous pouvez rendre privées la plupart des données globales nécessaires, comme les this
pointeurs et les fonctions d'interruption.
Ce n'est pas à l'épreuve des balles, et cela ajoute des frais généraux. Vous aurez du mal à implémenter une pile IO-Link en utilisant cette approche. Mais si vous n'êtes pas extrêmement serré avec les timings, cela fonctionne très bien pour obtenir une abstraction flexible des interruptions et de la communication dans les modules sans utiliser de variables globales accessibles de partout.