feat(ethercat): 添加EtherCAT从站功能支持并优化同步机制
- 添加CAN反馈和ID快照SPI命令文件 - 移除EXMC组件依赖,精简项目配置 - 添加RAM函数段链接脚本,优化Flash等待周期抖动 - 实现EscExmcBus类,提供16位并行总线访问LAN9252 - 实现EscLan9252驱动,支持寄存器和PDI内存访问 - 实现EthercatSlave类,采用三缓冲机制进行PDO数据交换 - 实现EthercatSync同步管理,支持SYNC0/SYNC1中断和定时器模式 - 添加ISR执行时间统计和诊断功能 - 分离周期路径和事件路径通知机制,避免RMW竞态
This commit is contained in:
+129
-134
@@ -1,4 +1,4 @@
|
||||
#ifndef DEVICE_CANFD_H
|
||||
#ifndef DEVICE_CANFD_H
|
||||
#define DEVICE_CANFD_H
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -6,165 +6,155 @@
|
||||
/** @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 运行诊断统计信息。
|
||||
* @note 记录发送、接收、错误计数以及最近一次收发报文的关键信息。
|
||||
*/
|
||||
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; /**< 硬件 FIFO0 进入满状态的次数。 */
|
||||
uint32_t rx_fifo_overfull_count; /**< 硬件 FIFO0 发生 overfull 的次数。 */
|
||||
uint32_t tx_drop_count; /**< 发送 FIFO 满导致丢弃的报文计数。 */
|
||||
uint32_t tx_abort_count; /**< 因邮箱全占主动中止占用邮箱的次数(典型:总线无 ACK 导致自动重传卡死)。 */
|
||||
uint32_t last_rx_id; /**< 最近一次接收报文的标识符。 */
|
||||
uint32_t last_tx_id; /**< 最近一次发送报文的标识符。 */
|
||||
uint8_t last_rx_channel; /**< 最近一次接收报文所在的 CAN 通道号(0/1/2)。 */
|
||||
uint8_t last_tx_channel; /**< 最近一次发送报文所在的 CAN 通道号(0/1/2)。 */
|
||||
uint8_t last_payload_length; /**< 最近一次收发报文的数据长度。 */
|
||||
uint8_t last_rx_fd_flag; /**< 最近一次接收报文的 FD 帧标志。 */
|
||||
uint8_t last_rx_brs; /**< 最近一次接收报文的波特率切换标志。 */
|
||||
uint8_t last_rx_esi; /**< 最近一次接收报文的错误状态指示位。 */
|
||||
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 状态发送载荷。
|
||||
* @note 当前保持协议兼容,仅包含温度与供电相关字段;VIN_ADC 单独在诊断打印中输出。
|
||||
*/
|
||||
struct StatusPayload {
|
||||
uint16_t temp_raw; /**< 内部温度通道原始 ADC 数值。 */
|
||||
uint16_t vref_raw; /**< 内部参考电压通道原始 ADC 数值。 */
|
||||
float vdda; /**< 根据内部参考电压换算得到的 MCU 供电电压,单位 V。 */
|
||||
float temperature; /**< 根据温度通道换算得到的芯片温度,单位 ℃。 */
|
||||
uint16_t temp_raw;
|
||||
uint16_t vref_raw;
|
||||
float vdda;
|
||||
float temperature;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 初始化 CANFD 外设、GPIO、模式控制、过滤器与中断。
|
||||
* @param[in] 无。
|
||||
* @param[out] 无。
|
||||
* @retval 无返回值。
|
||||
* @note 初始化后默认进入 Normal 模式,并使能 3 路 CAN 控制器的 RX0 中断用于异步接收。
|
||||
*/
|
||||
static void init();
|
||||
|
||||
/**
|
||||
* @brief 兼容保留的轮询接口,中断模式下为空壳。
|
||||
* @param[in] 无。
|
||||
* @param[out] 无。
|
||||
* @retval 无返回值。
|
||||
* @note 实际接收已由 CAN0/CAN1/CAN2 的 RX0 中断驱动。
|
||||
* @brief 切换 CANFD 接收过滤模式。
|
||||
*/
|
||||
static void setMode(Mode mode);
|
||||
|
||||
/** @brief 查询当前 CANFD 接收过滤模式。 */
|
||||
static Mode mode();
|
||||
|
||||
static void poll();
|
||||
|
||||
/**
|
||||
* @brief 根据状态载荷准备一帧待发送的 CANFD 状态报文,并广播入队到 3 路发送 FIFO。
|
||||
* @param[in] status 指向 StatusPayload 的指针;为空时不入队。
|
||||
* @param[out] 无。
|
||||
* @retval 无返回值。
|
||||
* @note 当前模块默认不会周期性调用该接口;仅在外部显式触发发送测试或业务发送时使用。
|
||||
*/
|
||||
static void prepareStatus(const StatusPayload *status);
|
||||
|
||||
/**
|
||||
* @brief 根据状态载荷仅向指定 CAN 通道的发送 FIFO 入队一帧状态报文。
|
||||
* @param[in] channelIndex 目标 CAN 通道号(0/1/2)。
|
||||
* @param[in] status 指向 StatusPayload 的指针;为空时不入队。
|
||||
* @param[out] 无。
|
||||
* @retval bool true 表示成功入队,false 表示通道非法或该通道发送 FIFO 已满。
|
||||
* @note 当前模块默认不会周期性调用该接口;仅在外部显式触发指定通道发送时使用。
|
||||
*/
|
||||
static bool prepareStatusForChannel(uint8_t channelIndex, const StatusPayload *status);
|
||||
|
||||
/**
|
||||
* @brief 发送当前已准备好的 CANFD 状态报文。
|
||||
* @param[in] 无。
|
||||
* @param[out] 无。
|
||||
* @retval 无返回值。
|
||||
* @note 当前模块默认不会周期性调用该接口;仅发送调用方显式准备过的报文;若队列为空则直接返回。
|
||||
*/
|
||||
static void sendPrepared();
|
||||
|
||||
/**
|
||||
* @brief 查询 3 个 CAN 通道中是否存在尚未消费的接收报文。
|
||||
* @param[in] 无。
|
||||
* @param[out] 无。
|
||||
* @retval bool true 表示至少有一路存在待消费报文,false 表示当前所有通道缓存为空。
|
||||
*/
|
||||
static bool hasRxFrame();
|
||||
|
||||
/**
|
||||
* @brief 读取并消费最近一轮扫描到的某一路缓存接收帧。
|
||||
* @param[in] 无。
|
||||
* @param[out] id 输出报文标识符的指针;允许为空。
|
||||
* @param[out] data 输出报文数据缓存区指针;允许为空。
|
||||
* @param[out] length 输出报文数据长度的指针;允许为空。
|
||||
* @param[out] channel 输出报文来源的 CAN 通道号指针;允许为空。
|
||||
* @retval bool true 表示成功消费一帧报文,false 表示当前 3 路缓存均为空。
|
||||
* @note 每路通道使用轻量环形缓冲保留多帧;消费顺序采用轮转扫描,避免长期偏向固定通道。
|
||||
*/
|
||||
static bool consumeRxFrame(uint32_t *id, uint8_t *data, uint8_t *length, uint8_t *channel = nullptr);
|
||||
|
||||
/**
|
||||
* @brief 直接向指定 CAN 通道发送一帧任意数据报文(扩展帧)。
|
||||
* @param[in] channelIndex 目标 CAN 通道号(0/1/2)。
|
||||
* @param[in] ext_id 扩展帧 ID(29 位)。
|
||||
* @param[in] data 数据负载指针。
|
||||
* @param[in] dlc 数据长度(1~64)。
|
||||
* @retval bool true 表示成功入队硬件邮箱,false 表示参数无效或邮箱已满。
|
||||
* @note 绕过软件发送队列,直接调用硬件发送;适用于 SPI 桥接等即时发送场景。
|
||||
*/
|
||||
static bool transmitFrame(uint8_t channelIndex, uint32_t ext_id,
|
||||
const uint8_t *data, uint8_t dlc);
|
||||
|
||||
/**
|
||||
* @brief 获取 CANFD 诊断统计信息只读指针。
|
||||
* @param[in] 无。
|
||||
* @param[out] 无。
|
||||
* @retval const Diag* 指向内部诊断统计结构体的只读指针。
|
||||
*/
|
||||
static const Diag *diag();
|
||||
|
||||
/**
|
||||
* @brief 将 TCAN1057A 收发器置为正常工作模式。
|
||||
* @param[in] 无。
|
||||
* @param[out] 无。
|
||||
* @retval 无返回值。
|
||||
* @note 模式控制脚按 STB 语义处理:低电平为 Normal,高电平为 Silent。
|
||||
* @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();
|
||||
|
||||
/**
|
||||
* @brief 将 TCAN1057A 收发器置为静默模式。
|
||||
* @param[in] 无。
|
||||
* @param[out] 无。
|
||||
* @retval 无返回值。
|
||||
* @note 静默模式下收发器不驱动总线显性位,可用于总线监听或受控隔离。
|
||||
*/
|
||||
static void setSilentMode();
|
||||
|
||||
/**
|
||||
* @brief CAN0 兼容中断处理入口。
|
||||
* @param[in] 无。
|
||||
* @param[out] 无。
|
||||
* @retval 无返回值。
|
||||
* @note 兼容保留给 CAN0 中断包装使用;三路统一接收逻辑已收口到 handleRxInterrupt()。
|
||||
*/
|
||||
static void onRx0Interrupt();
|
||||
|
||||
/**
|
||||
* @brief 处理指定 CAN 通道的 RX0 中断接收。
|
||||
* @param[in] channelIndex CAN 通道索引(0/1/2)。
|
||||
* @param[out] 无。
|
||||
* @retval 无返回值。
|
||||
*/
|
||||
static void handleRxInterrupt(uint8_t channelIndex);
|
||||
|
||||
private:
|
||||
@@ -184,25 +174,30 @@ private:
|
||||
volatile uint8_t count;
|
||||
};
|
||||
|
||||
/** @brief 初始化 CAN0/CAN1/CAN2 相关 GPIO。 */
|
||||
static void initGpio();
|
||||
/** @brief 为指定控制器配置接收过滤器。 */
|
||||
static void configureRxFilter(uint32_t canPeriph, uint8_t filterNumber);
|
||||
/** @brief 配置指定控制器的 CAN 仲裁段标称位时序。 */
|
||||
/**
|
||||
* @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);
|
||||
/** @brief 配置指定控制器的 CAN FD 数据段位时序与 TDC。 */
|
||||
static void initFdMode(uint32_t canPeriph);
|
||||
/** @brief 构造内部发送缓冲中的状态帧内容。 */
|
||||
static void buildStatusFrame(const StatusPayload *status);
|
||||
/** @brief 向指定 CAN 通道的发送 FIFO 写入一帧状态报文。 */
|
||||
static bool enqueueTxFrame(uint8_t channelIndex, const StatusPayload *status);
|
||||
|
||||
static Diag s_diag;
|
||||
static RxQueue s_rxQueues[3];
|
||||
static uint8_t s_nextConsumeChannel;
|
||||
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 */
|
||||
#endif /* DEVICE_CANFD_H */
|
||||
Reference in New Issue
Block a user