在車載控制器中,CAN采樣點(diǎn)的測(cè)試是控制器的基本測(cè)試之一,那CAN總線的采樣點(diǎn)一般怎么測(cè)試呢?今天一起來捋一捋。
首先CAN報(bào)文的位將分割為同步段(Sync Segment)、時(shí)間片段 1(TSEG1 Segment)和時(shí)間片段 2(TSEG2 Segment)。這些片段由不同數(shù)量的 TQ 組成, TQ 為該總線電平中最小的時(shí)間單位。預(yù)分頻(Prescaler)值以及收發(fā)器使用的時(shí)鐘頻率直接影響了一個(gè)位長度的總 TQ 數(shù)量。采樣點(diǎn)位置將由各個(gè)片段中 TQ 的數(shù)量計(jì)算得到。
![]()
1 個(gè)位中包含 8 或 16 個(gè) TQ 的分段示意圖
采樣點(diǎn)的理論計(jì)算值可由下式得到:
= ( + 1)/( + 1 + 2)
在此必須知道所使用的 CAN 時(shí)鐘頻率,以此來計(jì)算一個(gè)標(biāo)稱位時(shí)間所使用的總 TQ 數(shù)量。
例如:若一個(gè) TQ 的長度為 0.0625us,時(shí)鐘頻率是 16MHz(通常 CAN 所使用的時(shí)鐘頻率),預(yù)分頻數(shù)為1。這就導(dǎo)致在 500kBaud 下一個(gè)位含有 32 個(gè) TQ。若預(yù)分頻數(shù)為 2,則一個(gè)位包含 16 個(gè) TQ。
同步段(Sync Segment)在任何情況下均僅為 1 個(gè) TQ 長度,剩余的 TQ 將會(huì)被分為 TSEG1 和 TSEG2。
例如:若一個(gè)位的總 TQ 數(shù)為 16,采樣點(diǎn)位置為 75%,則 TSEG1 的 TQ 數(shù)為 11, TSEG2 的 TQ 數(shù)為 4。
CAN采樣點(diǎn)測(cè)試的原理是節(jié)點(diǎn)判斷信號(hào)邏輯電平的位置,對(duì) CAN總線來說極其重要,尤其是在一個(gè)CAN網(wǎng)絡(luò)里,多個(gè)節(jié)點(diǎn)要保持同一個(gè)采樣點(diǎn)。如果其中一個(gè)偏差較大,有可能使整個(gè)網(wǎng)絡(luò)出現(xiàn)故障,所以對(duì) CAN節(jié)點(diǎn)進(jìn)行采樣點(diǎn)的測(cè)試顯得尤為重要,采樣點(diǎn)測(cè)試目的用于檢查控制器的采樣點(diǎn)設(shè)置是否遵守規(guī)范要求。
采樣點(diǎn)的位置不受控制器所處的收發(fā)狀態(tài)影響,故針對(duì)采樣點(diǎn)測(cè)試既可以干擾控制器發(fā)送的指定報(bào)文的某個(gè)位,也可以通過測(cè)試工具發(fā)送特定干擾報(bào)文去檢測(cè)控制器的行為。
下面以CANoe發(fā)送特定干擾報(bào)文的方法為例。VH6501 在檢測(cè)到總線空閑時(shí),發(fā)送較高優(yōu)先級(jí)的特定干擾報(bào)文,完成一個(gè)干擾循環(huán)。每次干擾循環(huán)發(fā)送結(jié)束,微調(diào) CRC Delimiter 位長度,使其逐次縮短,導(dǎo)致后一位 ACK Slot前移,并將 ACK Slot 長度增加,保證整幀報(bào)文的長度不變。當(dāng)顯性位電平由后往前,移至 DUT 采樣點(diǎn)位置,會(huì)被 DUT 采到并判定 CRC Delimiter 位為高電平,出現(xiàn)格式錯(cuò)誤,DUT 隨即發(fā)送錯(cuò)誤幀,并被 CANoe 采集到。另外每次干擾循環(huán)結(jié)束, VH6501 將發(fā)送 30 次控制器正常接收的任意一幀正常報(bào)文,從而使 DUT 始終保持 Error Active 狀態(tài),因其主動(dòng)錯(cuò)誤幀容易辨認(rèn)。
![]()
那CANoe工程如何配置呢?首先打開軟件后,選擇CANoe的示例工程Disturbance SamplePoint Test (CAN)。進(jìn)入工程后,將 VH6501 通道分配給軟件通道 CAN1,在下圖所示界面設(shè)置 Mode 為 CAN,并勾選 Activate 選項(xiàng)使能 VH6501 總線干擾功能。
![]()
VH6501 的采樣點(diǎn)設(shè)置盡量靠前,確保優(yōu)先干擾到控制器的采樣點(diǎn),此處BTL Cycles(指的是TQ數(shù)量,將一個(gè)位分為16個(gè)TQ) 和SJW(同步跳變寬度) 要選擇數(shù)值較大的組合,可參考下圖配置。
![]()
配置完成之后,就可以寫capl測(cè)試腳本了。
/*@!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();
}那采樣點(diǎn)的測(cè)試結(jié)果一般受什么影響呢?一般來說受3個(gè)因素影響。
![]()
在總線信號(hào)和 RxD 引腳信號(hào)上影響采樣點(diǎn)測(cè)試結(jié)果的因素示意圖
?指VH6501每次縮短或增長的步進(jìn)長度。
?指控制器的CAN參數(shù)配置中一個(gè)TQ的時(shí)間長度。
?指總線上一個(gè)位的電平長度與控制器內(nèi)部主控芯片 RxD 引腳上的一個(gè)位電平長度的時(shí)間差。? = () - ()
如果一個(gè) CAN 的設(shè)備使用的時(shí)鐘對(duì)應(yīng)的最小 TQ 時(shí)間長度在?的范圍內(nèi),并且實(shí)際 TQ 配置在此范圍內(nèi),則?所帶來的誤差需要考慮在采樣點(diǎn)測(cè)試的結(jié)果中 。ISO11898-2: 2015規(guī)定了在2MBaud下,規(guī)定了?的允許范圍為-65ns 到+40ns。而對(duì)于 2MBaud下,一個(gè)位時(shí)間長度為500ns, 這意味著在RxD引腳上的為時(shí)間長度將會(huì)比在總線上的為時(shí)間長度短13%或長 8%。而 TQ 時(shí)間長度的計(jì)算公式為:? =/
如果在 2MBaud 下, 一個(gè) TQ 的時(shí)間長度小于一個(gè)位的 13%, 則?將會(huì)被考慮進(jìn)采樣點(diǎn)測(cè)試的結(jié)果當(dāng)中。具體的誤差將取決于 CAN 發(fā)送器和使用的波特率。
假設(shè) CAN 時(shí)鐘頻率為 80MHz, ?為 25ns,預(yù)分頻(Prescaler) 為 1, ?為 12.5ns, ?為6.25ns。仲裁相為 500kBaud,數(shù)據(jù)相為 2MBaud。
這意味著?所帶來的誤差在仲裁相為 1.25%,在數(shù)據(jù)相則會(huì)上升到 5%(由于單個(gè)位時(shí)間長度縮短了) 。這幾乎相當(dāng)于 2 個(gè) TQ 的時(shí)間長度。測(cè)試工具 VH6501 步進(jìn)長度?所帶來的誤差分別為0.3125%和 1.25%。
由于 CAN 協(xié)議 11898 中并未規(guī)定重同步后跳變沿一定要在同步段(Sync Segment) 的哪個(gè)位置,從同步段(Sync Segment) 的開始到結(jié)束均可以,因此這會(huì)帶來 1 個(gè) TQ 的誤差。在仲裁相和數(shù)據(jù)相中帶來的誤差分別為 0.625%和 2.5%。
因此綜上所述,在仲裁相中總的最大誤差為 2.1875%(1.25% + 0.3125% + 0.625%) ,在數(shù)據(jù)相中總的最大誤差為 8.75%(5% + 1.25% + 2.5%)。
由上可知, 由 VH6501 所帶來的誤差所占比例是很小的。而大部分是由于 CAN 協(xié)議本身所帶來的誤差。
-end-
分享不易,懇請(qǐng)點(diǎn)個(gè)【】和【在看】
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.