【发布时间】:2019-03-04 12:18:33
【问题描述】:
我正在研究如何实现一个自定义 C++ HAL,它针对多个微控制器,可能具有不同的架构(ARM、AVR、PIC 等),同时保持正常。
我继承了几个大而杂乱的代码库,这些代码库在当前状态下无法维护,因此需要更结构化的东西。
在挑选了许多优秀的文章和设计指南后,我正在考虑使用PIMPL 实现。
考虑以下 UART/串行端口示例:
// -----------------------------
// High-level HAL
// -----------------------------
// serialport.h
class SerialPortPrivate;
class SerialPort {
public:
SerialPort(uint8_t portNumber);
~SerialPort();
bool open();
void close();
void setBaudRate(uint32_t baudRate = 115200);
private:
SerialPortPrivate *_impl;
};
// serialport_p.h
class SerialPort;
class SerialPortPrivate {
public:
SerialPortPrivate(uint8_t portNumber, SerialPort *parent) {
// Store the parent (q_ptr)
_parent = parent;
// Store the port number, this is used to access UART
// specific registers UART->D[portNumber] = 0x10;
_portNumber = portNumber;
}
~SerialPortPrivate();
bool open() = 0;
void close() = 0;
void setBaudRate(uint32_t baudRate) = 0;
protected:
uint8_t _portNumber;
private:
SerialPort *_parent;
};
// serialport.cpp
#include "serialport.h"
#include "serialport_p.h"
#include "stm32serialport_p.h"
#include "avr32serialport_p.h"
#include "nrf52serialport_p.h"
#include "kinetisserialport_p.h"
SerialPort::SerialPort(uint8_t portNumber) {
#if MCU_STM32
_impl = new Stm32SerialPortPrivate(portNumber, this);
#elif MCU_AVR32
_impl = new Avr32SerialPortPrivate(portNumber, this);
#elif MCU_NRF52
_impl = new Nrf52SerialPortPrivate(portNumber, this);
#elif MCU_KINETIS
_impl = new KinetisSerialPortPrivate(portNumber, this);
#endif
}
void SerialPort::setBaudRate(uint32_t baudRate) {
_impl->setBaudRate(baudRate);
}
// -----------------------------
// Low-level BSP
// Hardware-specific overrides
// -----------------------------
// stm32serialport_p.h
class Stm32SerialPortPrivate : public SerialPortPrivate {
};
// nrf52serialport_p.h
class Nrf52SerialPortPrivate : public SerialPortPrivate {
};
// kinetisserialport_p.h
class KinetisSerialPortPrivate : public SerialPortPrivate {
};
上述代码在高级接口 (SerialPort) 的构造函数中只有一组 #if/#endif 语句,并且特定于硬件的代码(寄存器访问等)在私有实现中完成。
进一步了解上述内容,我可以看到上述实现对于 I2cPort、SpiPort、UsbSerialPort 等类运行良好,但对于时钟、硬件定时器等其他非端口相关的外围设备集。
我确信上述概念中存在一些漏洞,任何人都可以根据经验提出要避免的事情,或者是否有更好的抽象方法?
【问题讨论】:
-
你不是在重新实现 mbed-os 吗?和其他试图做你想做的事情的多个操作系统?
-
@KamilCuk 我完全不知道。我是吗?我没有考虑为这些项目采用 RTOS 路线,但如果我几乎是从头开始,也许我应该...
-
我认为这个问题太宽泛了。前任。 mbed-os 支持 nrf52 stm32 kinetis。我认为 atmel 不见了。并且 PIC(我的天哪!)不见了。但是您可以采用他们提供的抽象并为平台实现它。但是有几个这样的项目可以选择,在github上搜索就可以了。 mbed-os 是用 C++ 编写的,所以我提到了它。集成许多硬件真的非常非常困难,因为每一个都是独一无二的。还有很多(大)项目,都在尝试做和你一样的事情。
-
@Lundin,我必须承认,我用于嵌入式系统的任何 C++ 编译器都没有遇到过问题。我继承的所有代码库都在 C++ 中并且工作正常,它们只是一团糟 - 回到 C 是一大堆其他工作,我什至不会考虑(而且我不明白为什么我真的需要)。我也没有意识到
new关键字仅适用于PC!我正在使用具有 64/128/256kB SRAM 的设备,而不是小型 8k 设备。 -
当然你有确定性的用例。如果有 5 个外部外围设备,那么您有一个程序应该处理的指定最大值。它不应该处理更多,它需要在启用 5 个时起作用,因此处理这个所需的必要 RAM 正好是 5,这是最坏的情况。它不是在 1 到 5 之间,因为您必须始终为 5 保留空间。如果用户请求 1,则只为 1 分配空间是没有意义的,因为您的程序没有任何意义处理其他 4 个的内存。它必须为最坏的情况保留。