在车载控制器中,CAN采样点的测试是控制器的基本测试之一,那CAN总线的采样点一般怎么测试呢?今天一起来捋一捋。
首先CAN报文的位将分割为同步段(Sync Segment)、时间片段 1(TSEG1 Segment)和时间片段 2(TSEG2 Segment)。这些片段由不同数量的 TQ 组成, TQ 为该总线电平中最小的时间单位。预分频(Prescaler)值以及收发器使用的时钟频率直接影响了一个位长度的总 TQ 数量。采样点位置将由各个片段中 TQ 的数量计算得到。

1 个位中包含 8 或 16 个 TQ 的分段示意图
采样点的理论计算值可由下式得到:
= ( + 1)/( + 1 + 2)
在此必须知道所使用的 CAN 时钟频率,以此来计算一个标称位时间所使用的总 TQ 数量。
例如:若一个 TQ 的长度为 0.0625us,时钟频率是 16MHz(通常 CAN 所使用的时钟频率),预分频数为1。这就导致在 500kBaud 下一个位含有 32 个 TQ。若预分频数为 2,则一个位包含 16 个 TQ。
同步段(Sync Segment)在任何情况下均仅为 1 个 TQ 长度,剩余的 TQ 将会被分为 TSEG1 和 TSEG2。
例如:若一个位的总 TQ 数为 16,采样点位置为 75%,则 TSEG1 的 TQ 数为 11, TSEG2 的 TQ 数为 4。
CAN采样点测试的原理是节点判断信号逻辑电平的位置,对 CAN总线来说极其重要,尤其是在一个CAN网络里,多个节点要保持同一个采样点。如果其中一个偏差较大,有可能使整个网络出现故障,所以对 CAN节点进行采样点的测试显得尤为重要,采样点测试目的用于检查控制器的采样点设置是否遵守规范要求。
采样点的位置不受控制器所处的收发状态影响,故针对采样点测试既可以干扰控制器发送的指定报文的某个位,也可以通过测试工具发送特定干扰报文去检测控制器的行为。
下面以CANoe发送特定干扰报文的方法为例。VH6501 在检测到总线空闲时,发送较高优先级的特定干扰报文,完成一个干扰循环。每次干扰循环发送结束,微调 CRC Delimiter 位长度,使其逐次缩短,导致后一位 ACK Slot前移,并将 ACK Slot 长度增加,保证整帧报文的长度不变。当显性位电平由后往前,移至 DUT 采样点位置,会被 DUT 采到并判定 CRC Delimiter 位为高电平,出现格式错误,DUT 随即发送错误帧,并被 CANoe 采集到。另外每次干扰循环结束, VH6501 将发送 30 次控制器正常接收的任意一帧正常报文,从而使 DUT 始终保持 Error Active 状态,因其主动错误帧容易辨认。

那CANoe工程如何配置呢?首先打开软件后,选择CANoe的示例工程Disturbance SamplePoint Test (CAN)。进入工程后,将 VH6501 通道分配给软件通道 CAN1,在下图所示界面设置 Mode 为 CAN,并勾选 Activate 选项使能 VH6501 总线干扰功能。

VH6501 的采样点设置尽量靠前,确保优先干扰到控制器的采样点,此处BTL Cycles(指的是TQ数量,将一个位分为16个TQ) 和SJW(同步跳变宽度) 要选择数值较大的组合,可参考下图配置。

配置完成之后,就可以写capl测试脚本了。
/*@!Encoding:936*/
includes
{
}
variables
{
CanDisturbanceFrameTrigger frameTrigger;
CanDisturbanceFrameSequence frameSequence;
CanDisturbanceSequence sequence;
CanDisturbanceTriggerRepetitions repetitions;
const int repetition_times_in_one_cycle = 10;
//Number of disturbance repetitions in a cycle
long result;
long errfrmcount; //The error frame count in one cycle
long first_err_bit_length,first_error_occur, ten_error_occur;
long validityMask;
long cycleFlag;
message 0x100 triggerMessage; //The trigger
message.(ID is not important.)
message 0x0 spTestMsg; //The disturbance frame sequence which CRC DEL need to be shorten.
message 0x1 Keep_DUT_ErrorActive;
const long CountMsgKeepErrorActive = 30;
long MsgCntKeepErrorActive = 0;
char spTestDone[33] = "SPDone";
}
on errorFrame
{
if(this.msgChannel == @sysvar::CANDisturbanceInterface1::ChannelNo)
{
errfrmcount++;
if((errfrmcount == 1) && (first_error_occur == 0))
{
first_err_bit_length = frameSequence.CRCDelimiter.BitSequence[0].segmentLength[0];
first_error_occur = 1;
write("+++++++++First error frame occurs+++++++++++.");
}
if(errfrmcount == repetition_times_in_one_cycle)
{
ten_error_occur = 1;
testSupplyTextEvent(spTestDone);
}
}
}
on message 0x1
{
if(MsgCntKeepErrorActive <= CountMsgKeepErrorActive)
{
++MsgCntKeepErrorActive;
output(Keep_DUT_ErrorActive);
}
else
{
ActivateTriggerAgain();
}
}
void ActivateTriggerAgain()
{
if(ten_error_occur == 0)
{
errfrmcount = 0;
//CRC Delimiter is shorten with 6.25ns per cycle.
--frameSequence.CRCDelimiter.BitSequence[0].segmentLength[0];
++frameSequence.AckSlot.BitSequence[0].segmentLength[0];
result = canDisturbanceTriggerEnable(@sysvar::CANDisturbanceInterface1::DeviceNo,frameTrigger, frameSequence, repetitions);
if(result == 1)
{
write("Trigger is enabled,
frameSequence.CRCDelimiter.BitSequence[0].segmentLength[0] = %d",
frameSequence.CRCDelimiter.BitSequence[0].segmentLength[0]);
}
else
{
write("Enable trigger error Result = %d", result);
}
}
}
on sysvar sysvar::CANDisturbanceInterface1::Trigger::State
{
//6501 is Idle after repetition_times_in_one_cycle finish
if(@sysvar::CANDisturbanceInterface1::Trigger::State == 0)
{
//At the end of each disturbance cycle, the VH6501 need to outputsome normal message to prevent the DUT from being in a passive error state
//because the passive error frame is not easily to be observed and
//identified.
MsgCntKeepErrorActive = 0;
output(Keep_DUT_ErrorActive);
}
}
testcase SamplePointTest_forVH6501()
{
first_error_occur = 0;
ten_error_occur = 0;
errfrmcount = 0;
cycleFlag = 1;
frameSequence.SetMessage(@sysvar::CANDisturbanceInterface1::DeviceNo,spTestMsg);
validityMask = 0; //trigger on any CAN messages
frameTrigger.SetMessage(triggerMessage,
@sysvar::CANDisturbanceInterface1::DeviceNo, validityMask);
frameTrigger.TriggerFieldType =
@sysvar::CanDisturbance::Enums::FieldType::EndOfFrame;
frameTrigger.TriggerFieldOffset = 9; //Trigger position is the thirdbit of IFS.
write("CRC Delimiter Bit Length = %d",
frameSequence.CRCDelimiter.BitSequence[0].segmentLength[0]);
repetitions.Cycles = 1;
repetitions.HoldOffCycles = 0;
repetitions.HoldOffRepetitions = 0;
repetitions.Repetitions = repetition_times_in_one_cycle;
result = canDisturbanceTriggerEnable(@sysvar::CANDisturbanceInterface1::DeviceNo,frameTrigger,frameSequence,repetitions);
if(result == 1)
{
write("Trigger is enabled.");
}
else
{
write("Enable trigger error Result = %d", result);
}
result = testWaitForTextEvent(spTestDone, 10000);
if(result == 1)
{
write("frameSequence.CRCDelimiter.BitSequence[0].segmentLength[0] = %d
, sample point lies in %f%%~%f%%",
frameSequence.CRCDelimiter.BitSequence[0].segmentLength[0],
(frameSequence.CRCDelimiter.BitSequence[0].segmentLength[0] * 100.00) /
frameSequence.DLC.BitSequence[1].segmentLength[0], (first_err_bit_length *
100.00) / frameSequence.DLC.BitSequence[1].segmentLength[0]);
}
}
void maintest()
{
SamplePointTest_forVH6501();
}
那采样点的测试结果一般受什么影响呢?一般来说受3个因素影响。

在总线信号和 RxD 引脚信号上影响采样点测试结果的因素示意图
∆指VH6501每次缩短或增长的步进长度。
∆指控制器的CAN参数配置中一个TQ的时间长度。
∆指总线上一个位的电平长度与控制器内部主控芯片 RxD 引脚上的一个位电平长度的时间差。∆ = () - ()
如果一个 CAN 的设备使用的时钟对应的最小 TQ 时间长度在∆的范围内,并且实际 TQ 配置在此范围内,则∆所带来的误差需要考虑在采样点测试的结果中 。ISO11898-2: 2015规定了在2MBaud下,规定了∆的允许范围为-65ns 到+40ns。而对于 2MBaud下,一个位时间长度为500ns, 这意味着在RxD引脚上的为时间长度将会比在总线上的为时间长度短13%或长 8%。而 TQ 时间长度的计算公式为:∆ =/
如果在 2MBaud 下, 一个 TQ 的时间长度小于一个位的 13%, 则∆将会被考虑进采样点测试的结果当中。具体的误差将取决于 CAN 发送器和使用的波特率。
假设 CAN 时钟频率为 80MHz, ∆为 25ns,预分频(Prescaler) 为 1, ∆为 12.5ns, ∆为6.25ns。仲裁相为 500kBaud,数据相为 2MBaud。
这意味着∆所带来的误差在仲裁相为 1.25%,在数据相则会上升到 5%(由于单个位时间长度缩短了) 。这几乎相当于 2 个 TQ 的时间长度。测试工具 VH6501 步进长度∆所带来的误差分别为0.3125%和 1.25%。
由于 CAN 协议 11898 中并未规定重同步后跳变沿一定要在同步段(Sync Segment) 的哪个位置,从同步段(Sync Segment) 的开始到结束均可以,因此这会带来 1 个 TQ 的误差。在仲裁相和数据相中带来的误差分别为 0.625%和 2.5%。
因此综上所述,在仲裁相中总的最大误差为 2.1875%(1.25% + 0.3125% + 0.625%) ,在数据相中总的最大误差为 8.75%(5% + 1.25% + 2.5%)。
由上可知, 由 VH6501 所带来的误差所占比例是很小的。而大部分是由于 CAN 协议本身所带来的误差。
-end-
分享不易,恳请点个【】和【在看】
热门跟贴