Я кодую 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
-показник, оскільки векторна таблиця не є об'єктом. Тож для подолання цієї проблеми у нас є статичний pThis
-показник всередині CInterruptVectorTable
. Після введення однієї зі статичних функцій переривання, він може отримати доступ до pThis
-показника, щоб отримати доступ до членів одного об'єкта CInterruptVectorTable
.
Тепер у програмі ви можете використовувати SetIsrCallbackfunction
для надання вказівника на static
функцію, яку потрібно викликати, коли відбувається переривання. Покажчики зберігаються в InterruptVectorTable_t virtualVectorTable
.
А реалізація функції переривання виглядає приблизно так:
void CInterruptVectorTable::IsrNMI(void) {
pThis->virtualVectorTable.IsrNMI();
}
Отже, викликме static
метод іншого класу (який може бути private
), який потім може містити інший static
this
-показник для отримання доступу до змінних членів цього об'єкта (лише однієї).
Я думаю, ви могли б створити та інтерфейсувати, як IInterruptHandler
і зберігати покажчики на об’єкти, тож вам не потрібен static
this
-показник у всіх цих класах. (можливо, ми спробуємо це в наступній ітерації нашої архітектури)
Інший підхід для нас працює чудово, оскільки єдиними об'єктами, дозволеним реалізувати обробник переривань, є ті, що знаходяться в шарі апаратної абстракції, і ми зазвичай маємо лише один об'єкт для кожного апаратного блоку, тому добре працювати з static
this
-інструментами. А апаратний рівень абстракції забезпечує ще одну абстракцію переривань, називається ICallback
яка потім реалізується в шарі пристрою над апаратним забезпеченням.
Ви маєте доступ до глобальних даних? Зрозуміло, що ви робите, але ви можете зробити більшість необхідних глобальних даних приватними, як this
-показчики та функції переривання.
Це не куленепробивна, і це додає накладні витрати. Ви будете намагатися реалізувати стек IO-Link, використовуючи такий підхід. Але якщо ви не дуже тісні з часом, це добре працює, щоб отримати гнучку абстракцію переривань і зв’язок в модулях без використання глобальних змінних, доступних звідусіль.