Files
DCU_APP/GD32E508_DCU_APP/device/canfd.h
T
cbb b171767023 feat(ethercat): 添加EtherCAT从站功能支持并优化同步机制
- 添加CAN反馈和ID快照SPI命令文件
- 移除EXMC组件依赖,精简项目配置
- 添加RAM函数段链接脚本,优化Flash等待周期抖动
- 实现EscExmcBus类,提供16位并行总线访问LAN9252
- 实现EscLan9252驱动,支持寄存器和PDI内存访问
- 实现EthercatSlave类,采用三缓冲机制进行PDO数据交换
- 实现EthercatSync同步管理,支持SYNC0/SYNC1中断和定时器模式
- 添加ISR执行时间统计和诊断功能
- 分离周期路径和事件路径通知机制,避免RMW竞态
2026-06-29 01:51:02 +08:00

203 lines
7.6 KiB
C++

#ifndef DEVICE_CANFD_H
#define DEVICE_CANFD_H
#include <stdint.h>
/** @brief CANFD 状态报文的数据长度,单位字节。 */
#define CANFD_STATUS_DLEN 12U
/** @brief 每通道反馈快照中保存的最近一帧最大数据长度,受 SPI 应答帧总长度约束。 */
#define CANFD_FEEDBACK_LAST_DATA_MAX 32U
/** @brief 每通道不重复 ID 快照表最大条目数。 */
#define CANFD_ID_SNAPSHOT_MAX 16U
/** @brief 快照条目中最大数据字节数(等于 CANFD DLC 上限)。 */
#define CANFD_ID_SNAPSHOT_DATA_MAX 64U
/**
* @brief CANFD 通信模块。
* @note 负责 GPIO/模式控制、波特率配置、异步接收缓存与按需发送能力。
*/
class CanFd {
public:
/**
* @brief CANFD 接收过滤模式枚举。
* @note 默认模式为 kModeAllPass,即三路控制器关闭硬件 ID 过滤,全部接收。
*/
enum class Mode : uint8_t {
kModeAllPass = 0U, /**< 全部接收模式:禁用硬件 ID/掩码匹配,所有 11/29 位帧都进入 FIFO0。 */
kModeFilterId = 1U, /**< 过滤模式:按 CONFIG_CAN_RX_FILTER_ID/MASK 做标准帧掩码匹配。 */
};
/**
* @brief CANFD 运行诊断统计信息。
*/
struct Diag {
uint32_t tx_count;
uint32_t rx_count;
uint32_t error_count;
uint32_t rx_drop_count;
uint32_t rx_fifo_full_count;
uint32_t rx_fifo_overfull_count;
uint32_t tx_drop_count;
uint32_t tx_abort_count;
uint32_t last_rx_id;
uint32_t last_tx_id;
uint8_t last_rx_channel;
uint8_t last_tx_channel;
uint8_t last_payload_length;
uint8_t last_rx_fd_flag;
uint8_t last_rx_brs;
uint8_t last_rx_esi;
};
/**
* @brief 单通道运行计数(每路独立累计)。
*/
struct ChannelStats {
uint32_t rx_count; /**< 该通道累计成功接收帧数。 */
uint32_t tx_count; /**< 该通道累计成功发送帧数。 */
uint32_t rx_drop_count; /**< 该通道累计软件丢帧数。 */
uint32_t error_count; /**< 该通道累计错误计数(与发送邮箱失败合并)。 */
uint32_t last_rx_id; /**< 该通道最近一帧报文标识符。 */
uint8_t last_rx_dlc; /**< 该通道最近一帧报文数据长度。 */
uint8_t last_rx_fd_flag; /**< 该通道最近一帧 FD 帧标志。 */
uint8_t last_rx_brs; /**< 该通道最近一帧 BRS 标志。 */
uint8_t last_rx_esi; /**< 该通道最近一帧 ESI 标志。 */
uint8_t last_rx_data[CANFD_FEEDBACK_LAST_DATA_MAX];
};
/**
* @brief 单通道 1Hz 反馈快照(每秒刷新一次)。
*/
struct ChannelFeedback {
uint32_t snapshot_seq; /**< 第几次刷新(自启动起递增)。 */
ChannelStats stats; /**< 抓拍时刻的该通道统计与最近一帧信息。 */
};
/**
* @brief 单个不重复 ID 的最新帧快照。
*/
struct IdSnapshotEntry {
uint32_t id; /**< CAN 报文标识符。 */
uint32_t seq; /**< 该条目被更新的序号(自启动起递增)。 */
uint32_t rx_count; /**< 该 ID 累计接收帧数。 */
uint8_t dlc; /**< 最新一帧数据长度。 */
uint8_t fd_flag; /**< 最新一帧 FD 标志。 */
uint8_t brs; /**< 最新一帧 BRS 标志。 */
uint8_t esi; /**< 最新一帧 ESI 标志。 */
uint8_t data[CANFD_ID_SNAPSHOT_DATA_MAX]; /**< 最新一帧数据。 */
bool occupied; /**< 条目是否已被占用。 */
};
/**
* @brief 每通道不重复 ID 快照表(1Hz 刷新,SPI 命令分页拉取)。
*/
struct IdSnapshotTable {
IdSnapshotEntry entries[CANFD_ID_SNAPSHOT_MAX];
uint8_t count; /**< 当前占用条目数。 */
uint32_t seq; /**< 全局更新序号(每次 refresh 时递增)。 */
};
/**
* @brief CANFD 状态发送载荷。
*/
struct StatusPayload {
uint16_t temp_raw;
uint16_t vref_raw;
float vdda;
float temperature;
};
static void init();
/**
* @brief 切换 CANFD 接收过滤模式。
*/
static void setMode(Mode mode);
/** @brief 查询当前 CANFD 接收过滤模式。 */
static Mode mode();
static void poll();
static void prepareStatus(const StatusPayload *status);
static bool prepareStatusForChannel(uint8_t channelIndex, const StatusPayload *status);
static void sendPrepared();
static bool hasRxFrame();
static bool consumeRxFrame(uint32_t *id, uint8_t *data, uint8_t *length, uint8_t *channel = nullptr);
static bool transmitFrame(uint8_t channelIndex, uint32_t ext_id,
const uint8_t *data, uint8_t dlc);
static const Diag *diag();
/**
* @brief 刷新三路 1Hz 反馈快照。
* @note 通常由任务调度器在 1 秒节拍调用,将各通道实时计数与最近一帧信息抓拍到 s_feedback。
*/
static void refreshFeedbackSnapshot();
/**
* @brief 拷贝指定通道的最新反馈快照到调用方缓冲。
* @param[in] channelIndex 目标 CAN 通道号(0/1/2)。
* @param[out] out 目标快照缓冲;为空或通道非法时返回 false。
* @retval bool true 表示成功拷贝,false 表示参数非法。
*/
static bool copyFeedbackSnapshot(uint8_t channelIndex, ChannelFeedback *out);
/**
* @brief 拷贝指定通道的不重复 ID 快照表。
* @param[in] channelIndex 目标通道 0/1/2。
* @param[out] out 输出缓冲。
* @retval true 成功。
*/
static bool copyIdSnapshotTable(uint8_t channelIndex, IdSnapshotTable *out);
static void setNormalMode();
static void setSilentMode();
static void onRx0Interrupt();
static void handleRxInterrupt(uint8_t channelIndex);
private:
static constexpr uint8_t kRxQueueDepth = 16U;
struct RxFrame {
uint8_t channel;
uint32_t id;
uint8_t data[64];
uint8_t length;
};
struct RxQueue {
RxFrame frames[kRxQueueDepth];
volatile uint8_t head;
volatile uint8_t tail;
volatile uint8_t count;
};
static void initGpio();
/**
* @brief 根据当前模式为指定控制器配置接收过滤器。
* @param[in] canPeriph 目标 CAN 外设实例。
* @param[in] filterNumber 过滤器编号。
* @param[in] mode 目标接收过滤模式。
*/
static void configureRxFilter(uint32_t canPeriph, uint8_t filterNumber, Mode mode);
static void initNominalTiming(uint32_t canPeriph);
static void initFdMode(uint32_t canPeriph);
static void buildStatusFrame(const StatusPayload *status);
static bool enqueueTxFrame(uint8_t channelIndex, const StatusPayload *status);
static Diag s_diag;
static RxQueue s_rxQueues[3];
static uint8_t s_nextConsumeChannel;
static volatile Mode s_mode;
static ChannelStats s_channelStats[3];
static ChannelFeedback s_feedback[3];
static uint32_t s_feedbackSeq;
static IdSnapshotTable s_idSnapshot[3];
};
using canfd_diag_t = CanFd::Diag;
using canfd_status_payload_t = CanFd::StatusPayload;
#endif /* DEVICE_CANFD_H */