C++ 在中断处理程序中访问类成员
我有一个UART类,它有C++ 在中断处理程序中访问类成员,c++,embedded,interrupt-handling,C++,Embedded,Interrupt Handling,我有一个UART类,它有Fifo类的实例(目前只是一个粗略的想法),但是如果我这样做,并且在源文件中有一个中断处理程序,我就没有办法访问Fifo实例或任何其他UART成员 //uart.hpp 类Uart{ 先进先出; // ... }; //uart.cpp 无效UART\U IRQ\U处理程序(无效) { //无法访问Uart类 } 在C中,我在头中有一个 UART< /Cux.Stutt,也许在源文件中定义 FIFO < /Cuff>实例,作为源代码文件中的代码>静态< /代码>,在IR
Fifo
类的实例(目前只是一个粗略的想法),但是如果我这样做,并且在源文件中有一个中断处理程序,我就没有办法访问Fifo
实例或任何其他UART
成员
//uart.hpp
类Uart{
先进先出;
// ...
};
//uart.cpp
无效UART\U IRQ\U处理程序(无效)
{
//无法访问Uart类
}
<>在C中,我在头中有一个<代码> UART< /Cux.Stutt,也许在源文件中定义<代码> FIFO < /Cuff>实例,作为源代码文件中的代码>静态< /代码>,在IRQ处理程序内部访问它,但不十分确信C++中的这一点,同时保持封装。
//uart.c
静态Fifo fifoRx;
无效UART\U IRQ\U处理程序(无效)
{
//可访问fifoRx
}
如果您想访问Uart
类本身,一种方法可能是将static
指针设置为uartini(Uart*pUart)
函数中的实例
//uart.c
静态Uart*psUart;
无效UART\U IRQ\U处理程序(无效){
//通过psUart访问UART
}
无效UartInit(Uart*pUart){
psUart=pUart;
// ...
}
<>但是,在保持封装完好的情况下,你将怎样做类似于现代C++的事情? < p>你可以尝试以下机制之一:
//uart.h
类Uart{
公众:
静态Fifo fifoRx;
// ...
};
//初始化Uart类的静态成员
Fifo Uart::fifoRx={0};
//uart.cpp
无效UART\U IRQ\U处理程序(无效)
{
//直接访问静态成员
Uart::fifoRx。
}
我也遇到过同样的问题,我用了一种有点肮脏和复杂的设计来解决它。我的解决方案依赖于某些硬件支持,因此它可能不适用于您的平台。我的解决方案是在STM32F1和STM32F4 uCs上开发的,它们分别使用Cortex M3和M4内核。它可能也适用于M0。此外,我的解决方案使用了一些C++17特性,但只需稍加修改即可将其转换为C++11及更高版本 很明显,一些与硬件相关的类,如您提到的UART类,与中断处理程序紧密耦合。uC可以有这些类的多个实例。这还要求您需要多个ISR实例。因为它们不能有参数,如果必须确定中断源,那么将多个中断向量映射到同一个函数可能会导致问题 ISR的另一个问题是,它们的名称是由供应商提供的向量表代码预先确定的,有时是用汇编编写的。由于每个向量都有一个硬编码的名称,因此如果没有一些宏暗术,就不可能编写通用代码 首先,需要解决ISR命名问题。这是依赖于硬件支持的部分。Cortex M3和M4内核使您能够指向位于不同地址上的不同向量表。如果将向量表从闪存复制到RAM,则可以在运行时将带有
void ISR\u func(void)
签名的任何函数注册为ISR。M0内核具有有限的向量表重定位功能,但它们仍然提供了一种将其移动到RAM开始的方法
我认为将ISR向量表从闪存移动到RAM的细节与这个问题的主题有点脱节,但让我们假设以下函数可用,它阻止将函数作为给定向量的ISR:
void registerISR(IRQn_Type IRQn, void (*isr)());
我们可以假设已知类实例的最大数量,因为UART硬件模块的数量已知。我们需要以下组件:
Uart指针的静态成员数组,每个指针指向Uart的一个实例
static constexpr unsigned MaxUarts {3};
inline static Uart* uartList[MaxUarts] {nullptr};
ISR的功能模板。这些将是静态成员函数,但最终每个实例将有自己的专用ISR:
template <unsigned uartIndex>
void Uart::uartIsr()
{
auto instance = uartList[uartIndex];
instance->doSometing();
}
因此Uart类头应该如下所示:
class Uart {
public:
Uart(/* Arguments */);
private:
inline static uint8_t instanceNoAssigner {0};
void doSomething(); // Just a place holder
IRQn_Type getIrqNo(); // Implementation depends on HW
template <unsigned uartIndex>
static void uartIsr();
static constexpr unsigned MaxUarts {3};
inline static Uart* uartList[MaxUarts] {nullptr};
using isrPointer = void (*)();
inline static const isrPointer uartHandlers[MaxUarts] {
&uartIsr<0>,
&uartIsr<1>,
&uartIsr<2>
}
}
template <unsigned uartIndex>
Uart::uartIsr()
{
auto instance = uartList[uartIndex];
instance->doSometing();
}
我还在RAM的开头创建了一个新的部分。对于Cortex M3和M4,向量表可以是任意位置(有一些对齐要求)。但对于Cortex M0,RAM的起始位置是唯一的替代位置,因为它们缺少VTOR寄存器
/* Relocated ISR Vector Table */
.isr_vector_ram 0x20000000 :
{
. = ALIGN(4);
KEEP(*(.isr_vector_ram))
. = ALIGN(4);
} >RAM
最后,这是我用于重新定位(初始化时调用一次)和注册的两个函数:
extern uint32_t _svector;
static constexpr size_t VectorTableSize {106}; // words
uint32_t __attribute__((section(".isr_vector_ram"))) vectorTable[VectorTableSize];
void relocateVectorTable()
{
// Copy IRQ vector table to RAM @ 0x20'000'000
uint32_t *ptr = &_svector;
for (size_t i = 0; i < VectorTableSize; ++i) {
vectorTable[i] = ptr[i];
}
// Switch to new table
__disable_irq();
SCB->VTOR = 0x20'000'000ULL;
__DSB();
__enable_irq();
}
void registerISR(IRQn_Type IRQn, void (*isr)())
{
uint32_t absAdr = reinterpret_cast<uint32_t>(isr);
__disable_irq();
vectorTable[IRQn + 16] = absAdr;
__DSB();
__enable_irq();
}
extern uint32\u t\u svector;
静态constexpr size\u t VectorTableSize{106};//话
uint32可向量化[向量化大小];
void relocateVectorTable()
{
//将IRQ矢量表复制到内存@0x20'000'000
uint32_t*ptr=&u svector;
对于(大小i=0;iVTOR=0x20'000'000ULL;
__DSB();
__启用_irq();
}
无效登记簿isr(IRQn类型IRQn,无效(*isr)()
{
uint32\u t absAdr=重新解释铸件(isr);
__禁用_irq();
可矢量化[IRQn+16]=absAdr;
__DSB();
__启用_irq();
}
<> P>不知何故,GCC足够聪明,自动生成最低位的原始函数地址1,以指示拇指指令。 < P>您的C版本和C++版本不重新使用。
Uart::Uart(/* Arguments, possibly the instance no */) {
instanceNo = instanceNoAssigner++; // One can use a static counter
uartList[instanceNo] = this;
registerISR(this->getIrqNo(), uartHandlers[instanceNo])
}
class Uart {
public:
Uart(/* Arguments */);
private:
inline static uint8_t instanceNoAssigner {0};
void doSomething(); // Just a place holder
IRQn_Type getIrqNo(); // Implementation depends on HW
template <unsigned uartIndex>
static void uartIsr();
static constexpr unsigned MaxUarts {3};
inline static Uart* uartList[MaxUarts] {nullptr};
using isrPointer = void (*)();
inline static const isrPointer uartHandlers[MaxUarts] {
&uartIsr<0>,
&uartIsr<1>,
&uartIsr<2>
}
}
template <unsigned uartIndex>
Uart::uartIsr()
{
auto instance = uartList[uartIndex];
instance->doSometing();
}
/* The startup code into "ROM" Rom type memory */
.isr_vector :
{
. = ALIGN(4);
_svector = .;
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
_evector = .;
} >ROM
/* Relocated ISR Vector Table */
.isr_vector_ram 0x20000000 :
{
. = ALIGN(4);
KEEP(*(.isr_vector_ram))
. = ALIGN(4);
} >RAM
extern uint32_t _svector;
static constexpr size_t VectorTableSize {106}; // words
uint32_t __attribute__((section(".isr_vector_ram"))) vectorTable[VectorTableSize];
void relocateVectorTable()
{
// Copy IRQ vector table to RAM @ 0x20'000'000
uint32_t *ptr = &_svector;
for (size_t i = 0; i < VectorTableSize; ++i) {
vectorTable[i] = ptr[i];
}
// Switch to new table
__disable_irq();
SCB->VTOR = 0x20'000'000ULL;
__DSB();
__enable_irq();
}
void registerISR(IRQn_Type IRQn, void (*isr)())
{
uint32_t absAdr = reinterpret_cast<uint32_t>(isr);
__disable_irq();
vectorTable[IRQn + 16] = absAdr;
__DSB();
__enable_irq();
}
static Uart uart1 ;
void UART1_IRQ_Handler(void)
{
...
uart1.fifoRx.put( UART1_DR ) ;
...
}
class Uart
{
public:
Uart( UART uart ) : m_uart(uart) { ... } ;
void isr()
{
...
m_fifoRx.put( m_uart.DR ) ;
...
}
private:
Fifo m_fifoRx;
UART m_uart ;
};
static Uart uart1( UART1 ) ;
static Uart uart2( UART2 ) ;
void UART1_IRQ_Handler(void)
{
uart1.isr() ;
}
void UART2_IRQ_Handler(void)
{
uart2.isr() ;
}
// uart.h
class Uart {
Fifo fifoRx;
friend void UART_IRQ_Handler(void)
// ...
};
// uart.cpp
void UART_IRQ_Handler(void)
{
// have no way to access the Uart class
}