4. 非同步节点启动
任务说明
在一个已有节点完成冷启动并进入同步运行的FlexRay网络中,需要新增一个节点(非同步启动节点)。该节点不参与冷启动,而是在网络运行期间上电,通过接收同步帧完成时钟同步并加入通信。本案例要求配置该节点的同步参数,使其能够正确同步到全局网络时间并正常收发数据。
同步原理与关键参数
非同步节点启动时,首先进入协议启动状态机中的“等待同步帧”状态。节点通过监听通道上的同步帧(来自已同步的同步节点),收集足够的同步帧对后,计算时钟校正值并应用,从而完成时间同步。关键参数包括:
- pAllowHaltDueToClockSyncFault:设为0,允许节点在同步失败时继续尝试,而非直接停止。
- pClusterDriftDamping:设为1,启用漂移阻尼,加快同步收敛。
- pDecodingCorrection:设为1,启用解码校正,补偿接收路径延迟。
- pDelayCompensationA/B:对应通道A/B的延迟补偿值,需根据实际总线长度设置。
- pKeySlotId:设为0,表示该节点不发送同步帧(非同步节点)。
- pKeySlotUsedForStartup:设为0,不参与冷启动。
- pKeySlotUsedForSync:设为0,不作为同步节点。
- pLatestTx:配置为允许发送数据帧的时隙。
代码实现
以下配置基于EB tresos生成的FlexRay驱动,展示非同步节点的核心参数设置。代码中省略了与同步无关的通信参数,聚焦于同步相关配置。
/* FlexRay非同步节点配置 - 基于EB tresos FlexRay驱动 */
#include "FlexRay.h"
#include "FlexRay_Internal.h"
/* 全局时间同步参数结构 */
const FlexRay_TimeSyncParamsType FlexRay_TimeSyncParams = {
.pAllowHaltDueToClockSyncFault = 0u, /* 同步故障时不允许停止 */
.pClusterDriftDamping = 1u, /* 启用漂移阻尼 */
.pDecodingCorrection = 1u, /* 启用解码校正 */
.pDelayCompensationA = 2u, /* A通道延迟补偿,单位: 微时隙(MT) */
.pDelayCompensationB = 2u, /* B通道延迟补偿 */
.pOffsetCorrectionStart = 1599u,/* 偏移校正起始点,位于周期末尾 */
.pOffsetCorrectionOut = 1599u,/* 偏移校正输出点 */
.pRateCorrectionOut = 1599u,/* 速率校正输出点 */
.pRateCorrectionStart = 1599u,/* 速率校正起始点 */
.pSyncFrameTable = 0u, /* 不使用外部同步帧表 */
.pSynchronizationFrameFilter = 0u /* 不启用同步帧过滤 */
};
/* 节点配置 - 非同步节点 */
const FlexRay_NodeConfigType FlexRay_NodeConfig = {
.pNodeId = 4u, /* 节点ID,用于调试 */
.pClusterParams = &FlexRay_ClusterParams,
.pTimeSyncParams = &FlexRay_TimeSyncParams,
.pKeySlotId = 0u, /* 关键时隙ID=0,非同步节点 */
.pKeySlotUsedForStartup = 0u, /* 不参与冷启动 */
.pKeySlotUsedForSync = 0u, /* 不作为同步节点 */
.pKeySlotOnlyEnabled = 0u, /* 允许发送数据帧 */
.pChannelA = 1u, /* 启用A通道 */
.pChannelB = 1u, /* 启用B通道 */
.pSingleSlotEnabled = 0u, /* 允许动态段发送 */
.pAllowHaltDueToClockSyncFault = 0u, /* 同步故障时继续运行 */
.pMaxWithoutClockCorrectionFatal = 0u, /* 不启用致命同步丢失检测 */
.pMaxWithoutClockCorrectionPassive = 0u /* 不启用被动同步丢失检测 */
};
/* 初始化函数 - 在系统启动时调用 */
void FlexRay_NonSyncNode_Init(void)
{
/* 设置节点为非同步模式 */
FlexRay_GlobalConfig.pNodeConfig = &FlexRay_NodeConfig;
/* 配置通信周期长度,与网络中已有节点一致 */
FlexRay_GlobalConfig.pMacroticksPerCycle = 3200u; /* 通信周期=3200MT */
FlexRay_GlobalConfig.pMicroticksPerMacrotick = 4u; /* 1MT=4uT */
/* 配置静态段时隙,与网络一致 */
FlexRay_GlobalConfig.pStaticSlotDuration = 40u; /* 静态时隙=40MT */
FlexRay_GlobalConfig.pNumberOfStaticSlots = 40u; /* 40个静态时隙 */
/* 配置同步帧期望接收的时隙(来自同步节点) */
FlexRay_GlobalConfig.pExpectedSyncFrameSlots[0] = 1u; /* 同步节点1在时隙1 */
FlexRay_GlobalConfig.pExpectedSyncFrameSlots[1] = 2u; /* 同步节点2在时隙2 */
FlexRay_GlobalConfig.pExpectedSyncFrameCount = 2u; /* 期望2个同步帧 */
/* 初始化硬件 */
FlexRay_InitController(&FlexRay_GlobalConfig);
}
/* 启动非同步节点 */
void FlexRay_NonSyncNode_Start(void)
{
/* 进入就绪状态,等待网络同步 */
FlexRay_ControllerEnterReadyState();
/* 启动协议引擎,开始监听同步帧 */
FlexRay_ControllerStartCommunication();
/* 等待同步完成,通过中断或轮询检查 */
/* 同步完成后,FlexRay_GetGlobalTime()将返回有效的全局时间 */
}
/* 主循环中的同步状态检查 */
uint8_t FlexRay_NonSyncNode_CheckSyncStatus(void)
{
FlexRay_SyncStatusType syncStatus;
syncStatus = FlexRay_GetSyncStatus();
if (syncStatus == FLEXRAY_SYNC_STATUS_SYNCED) {
/* 已同步到全局时间 */
return 1u;
} else if (syncStatus == FLEXRAY_SYNC_STATUS_PENDING) {
/* 正在同步中 */
return 0u;
} else {
/* 同步失败 */
return 2u;
}
}
同步状态机
落地与验证
集成步骤:
- 将上述配置代码集成到基于EB tresos生成的FlexRay驱动中,替换默认的同步参数。
- 确保网络中的同步节点(时隙1和2)已正常运行,通信周期为3200MT。
- 编译并烧录到目标节点,节点上电后调用
FlexRay_NonSyncNode_Init()和FlexRay_NonSyncNode_Start()。
验证方法:
- 使用FlexRay总线分析仪(如Vector CANoe)监控总线流量,观察节点是否在启动后约2~3个通信周期内完成同步。
- 调用
FlexRay_NonSyncNode_CheckSyncStatus(),返回值应为1(已同步)。 - 读取全局时间寄存器,与同步节点的全局时间差值应小于一个宏节拍(1MT=4μs@80Mbps)。
- 在静态时隙中发送数据帧,确认其他节点能正确接收。
判定标准:节点上电后5个通信周期内完成同步,全局时间偏差≤1MT,且数据通信正常,即视为通过。