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:
@@ -5,8 +5,8 @@
|
||||
#include "comm/esc_lan9252.h"
|
||||
#include "comm/esc_exmc_bus.h"
|
||||
#include "sys/config.h"
|
||||
|
||||
#if CONFIG_ETHERCAT_ENABLE
|
||||
#include "RTE_Components.h"
|
||||
#include CMSIS_device_header
|
||||
|
||||
namespace {
|
||||
/* LAN9252 ESC 关键寄存器地址(字节偏移,EXMC 访问) */
|
||||
@@ -20,16 +20,55 @@ constexpr uint16_t LAN9252_PDI_BASE_OFFSET = 0x1000U;
|
||||
|
||||
void EscLan9252::init()
|
||||
{
|
||||
/* 使能 DWT 周期计数器,供 periodicIsr 执行时间测量 */
|
||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||
DWT->CYCCNT = 0U;
|
||||
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
|
||||
|
||||
EscExmcBus::init();
|
||||
/* TODO: 配置 ESC 中断使能、AL 控制等基本寄存器(留待协议栈集成阶段实现) */
|
||||
|
||||
/* ============================================================
|
||||
* TODO: 完整 ESC 寄存器配置(需 SSC 或等价协议栈代码,本 spec 不实现)
|
||||
* ============================================================
|
||||
* 当前仅完成 EXMC 总线初始化与芯片 ID 读取。要使 SYNC0 实际触发,还需配置:
|
||||
*
|
||||
* 1. SyncManager(SM)初始化:
|
||||
* - SM0/SM1:邮箱输入/输出(IN/OUT),地址 0x0520-0x0530
|
||||
* - SM2:TxPDO(输入),地址 0x0530,配置为 3-buffer 模式
|
||||
* - SM3:RxPDO(输出),地址 0x0540,配置为 3-buffer 模式
|
||||
* - 各 SM 的 StartAddr/Length/Control/Status/Activate 寄存器
|
||||
*
|
||||
* 2. FMMU(Fieldbus Memory Mapping Unit)配置:
|
||||
* - FMMU0:TxPDO 映射(逻辑地址 → 物理地址,读)
|
||||
* - FMMU1:RxPDO 映射(逻辑地址 → 物理地址,写)
|
||||
* - 地址 0x0580-0x0590
|
||||
*
|
||||
* 3. AL Control(0x0120):写入 0x08 请求 OP 状态(需主站配合完成状态迁移)
|
||||
*
|
||||
* 4. SYNC0 生成寄存器:
|
||||
* - 0x0981-0x0982:SYNC0 周期(cycle time,单位 ns)
|
||||
* - 0x0983:SYNC0 脉冲长度
|
||||
* - 0x0984:SYNC0 控制(使能/触发模式)
|
||||
* - 需主站 DC 同步后由 ESC 自动生成 SYNC0 脉冲
|
||||
*
|
||||
* 这些步骤通常由 EtherCAT SSC(Slave Stack Code)或等价协议栈代码完成,
|
||||
* 涉及 AL 状态机管理、邮箱通信、PDO 映射协商等复杂逻辑。
|
||||
* 本 spec 仅通过 EthercatSlave::isEscReady() 的 AL 状态守卫使
|
||||
* "SYNC0 不会触发"在运行期可观测,完整配置留待 SSC 集成 spec。
|
||||
* ============================================================ */
|
||||
}
|
||||
|
||||
bool EscLan9252::selfTest()
|
||||
{
|
||||
const uint16_t id_low = readReg(LAN9252_REG_CHIP_ID_L);
|
||||
const uint16_t id_high = readReg(LAN9252_REG_CHIP_ID_H);
|
||||
const uint32_t chip_id = ((uint32_t)id_high << 16) | id_low;
|
||||
return (chip_id == LAN9252_CHIP_ID_VALUE);
|
||||
return (readChipId() == LAN9252_CHIP_ID_VALUE);
|
||||
}
|
||||
|
||||
uint32_t EscLan9252::readChipId()
|
||||
{
|
||||
/* INIT-ONLY:init 阶段中断未使能,但仍走 initOnly 路径保持一致性 */
|
||||
const uint16_t id_low = initOnlyReadReg(LAN9252_REG_CHIP_ID_L);
|
||||
const uint16_t id_high = initOnlyReadReg(LAN9252_REG_CHIP_ID_H);
|
||||
return ((uint32_t)id_high << 16) | id_low;
|
||||
}
|
||||
|
||||
uint16_t EscLan9252::readReg(uint16_t addr)
|
||||
@@ -43,6 +82,7 @@ void EscLan9252::writeReg(uint16_t addr, uint16_t val)
|
||||
EscExmcBus::write16((uint32_t)addr << 1U, val);
|
||||
}
|
||||
|
||||
__attribute__((section(".ramfunc"), noinline))
|
||||
void EscLan9252::readPdi(uint16_t offset, uint8_t *buf, size_t len)
|
||||
{
|
||||
if (buf == nullptr || len == 0U) {
|
||||
@@ -63,6 +103,7 @@ void EscLan9252::readPdi(uint16_t offset, uint8_t *buf, size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((section(".ramfunc"), noinline))
|
||||
void EscLan9252::writePdi(uint16_t offset, const uint8_t *buf, size_t len)
|
||||
{
|
||||
if (buf == nullptr || len == 0U) {
|
||||
@@ -79,4 +120,25 @@ void EscLan9252::writePdi(uint16_t offset, const uint8_t *buf, size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ETHERCAT_ENABLE */
|
||||
/* ---- initOnly* 接口:INIT-ONLY,仅允许在 EthercatSync::init() 使能 EXTI NVIC 之前调用 ----
|
||||
* 运行期禁止调用;需 ESC 寄存器访问须通过 SYNC0 ISR 代访队列(本 spec 不涵盖)。
|
||||
* 注:不再使用 PRIMASK 关中断(违反项目硬约束"Critical sections MUST use BASEPRI")。 */
|
||||
uint16_t EscLan9252::initOnlyReadReg(uint16_t addr)
|
||||
{
|
||||
return readReg(addr);
|
||||
}
|
||||
|
||||
void EscLan9252::initOnlyWriteReg(uint16_t addr, uint16_t val)
|
||||
{
|
||||
writeReg(addr, val);
|
||||
}
|
||||
|
||||
void EscLan9252::initOnlyReadPdi(uint16_t offset, uint8_t *buf, size_t len)
|
||||
{
|
||||
readPdi(offset, buf, len);
|
||||
}
|
||||
|
||||
void EscLan9252::initOnlyWritePdi(uint16_t offset, const uint8_t *buf, size_t len)
|
||||
{
|
||||
writePdi(offset, buf, len);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user