Сейчас я пишу для Cortex M0 / M4, и подход, который мы используем в C ++ (тега C ++ нет, поэтому этот ответ может быть не по теме), заключается в следующем:
Мы используем класс, CInterruptVectorTable
который содержит все подпрограммы обработки прерываний, которые хранятся в фактическом векторе прерываний контроллера:
#pragma location = ".intvec"
extern "C" const intvec_elem __vector_table[] =
{
{ .__ptr = __sfe( "CSTACK" ) }, // 0x00
__iar_program_start, // 0x04
CInterruptVectorTable::IsrNMI, // 0x08
CInterruptVectorTable::IsrHardFault, // 0x0C
//[...]
}
Класс CInterruptVectorTable
реализует абстракцию векторов прерываний, поэтому вы можете связывать различные функции с векторами прерываний во время выполнения.
Интерфейс этого класса выглядит следующим образом:
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;
};
Вам необходимо создать функции, которые хранятся в таблице векторов, static
потому что контроллер не может предоставить this
-pointer, поскольку таблица векторов не является объектом. Таким образом, чтобы обойти эту проблему, у нас есть статический pThis
указатель внутри CInterruptVectorTable
. После входа в одну из статических функций прерывания он может получить доступ к pThis
-pointer, чтобы получить доступ к членам одного объекта CInterruptVectorTable
.
Теперь в программе вы можете использовать SetIsrCallbackfunction
указатель функции для static
функции, которая должна вызываться при возникновении прерывания. Указатели хранятся в InterruptVectorTable_t virtualVectorTable
.
И реализация функции прерывания выглядит так:
void CInterruptVectorTable::IsrNMI(void) {
pThis->virtualVectorTable.IsrNMI();
}
Так что это вызовет static
метод другого класса (который может бытьprivate
), который затем может содержать другой static
this
-pointer, чтобы получить доступ к переменным-членам этого объекта (только один).
Я думаю, вы могли бы построить и интерфейс, как IInterruptHandler
и хранить указатели на объекты, поэтому вам не нужен static
this
-pointer во всех этих классах. (возможно, мы попробуем это на следующей итерации нашей архитектуры)
Другой подход хорошо работает для нас, так как единственные объекты, которым разрешено реализовывать обработчик прерываний, это те, которые находятся на уровне аппаратной абстракции, и у нас обычно есть только один объект для каждого аппаратного блока, так что это нормально работает с static
this
-pointers. И уровень аппаратной абстракции предоставляет еще одну абстракцию для прерываний, ICallback
которая называется, которая затем реализуется на уровне устройств над аппаратными средствами.
У вас есть доступ к глобальным данным? Конечно, но вы можете сделать большую часть необходимых глобальных данных частными, как, например,this
-pointers и функции прерывания.
Это не пуленепробиваемый, и это добавляет накладные расходы. Вы будете бороться за реализацию стека IO-Link, используя этот подход. Но если вы не очень сильно привязаны к временным интервалам, это работает очень хорошо, чтобы получить гибкую абстракцию прерываний и связи в модулях без использования глобальных переменных, которые доступны везде.