CAN BUS的總線負載率是CAN總線架構協議設計時的一個重要的指標。一般建議負載率峰值不要高于80%,平均負載率不要超過50%。當然這只是一般建議,具體根據使用場景和系統設計而定。
負載率定義
關于CAN負載率的定義和計算,很多文章寫得不求甚解,用幀數量來計算負載率是非常不正確的做法。
其實總線負載率的定義其實是非常簡單明了的:
*總線負載率=總線每秒上傳輸占用時間/1s 100%
CAN2.0的總線負載率
對于CAN2.0而言,由于波特率是固定的,所以:
總線負載率=總線每秒上傳輸的實際bit數量/總線波特率100%*
原理非常簡單,波特率的定義就是每秒CAN總線上可以傳輸多少CAN數據bit,總線負載率自然就是總線實際傳輸的bit數量比上總線可以承載的最大bit數了。
例如,100K的總線波特率,總線上最大承載的數據量就是100K個bit。如果總線上實際傳輸了50K個bit位,那么負載率就是50%。
CAN FD的總線負載率
CAN FD由于支持速率可變,總線占用時間的計算就稍微麻煩一些
負載率計算
對于上面的計算公式,對于一個CAN總線而言,波特率一般都是已知的。計算負載率的關鍵就是通過CAN報文統計出總線上每秒傳輸的bit數量。那么就需要回到CAN的幀格式來計算實際發生的bit數。
一幀數據包含以下數量的bit構成:
1位起始位。
11位標識符
1位RTR
6位控制域
0到64位數據字段
15位CRC
位填充是可能的,在上面的每一個序列的5個連續位相同的水平。最壞情況下大約是19位。
3位分隔符,ack等。
幀結束7位
幀后的3位間隔域。
如果軟件需要精確計算負載率,無疑是比較麻煩的。因為對于軟件層面,并感知不到除了標識符,控制域和數據域以外的其他bit,并且由于填充位的數量因數據不同而不同,軟件做精確的bit位數量計算就比較耗費資源。
軟件計算負載率
基于這樣的情況,實際可以考慮3種方案
1. 按最少的填充位可能性來計算(忽略填充位)
忽略填充位顯然會少統計很多bit數量,導致計算出的負載率比實際的偏低,但是每幀的bit數計算方式簡單。
/* eff : 擴展幀標識 */
can_frame_length = (eff ? 67 : 47) + frame->len * 8;
2. 按最多的填充位的可能性來計算
按最多的填充位計算負載率,會導致計算出的負載率比實際的偏高,但是每幀的bit數計算方式也比較簡單。
/* eff : 擴展幀標識 */
can_frame_length = (eff ? 80 : 55) + frame->len * 10;
3.依據每一幀數據,精確的計算出填充位的數量
這種方式是最精確的,但是由軟件計算會比較復雜,開銷較大,需要軟件講每一幀的bit按照二進制進行排列,然后按照CAN協議位填充的要求,遇到5個相同的bit就插入一個相反的填充位,也就是增加一個bit數。
以下是幀bit數計算代碼
static unsigned cfl_exact(struct can_frame *frame)
{
uint8_t bitmap[16];
unsigned start = 0, end;
crc_t crc;
uint16_t crc_be;
uint8_t mask, lookfor;
unsigned i, stuffed;
const int8_t clz[32] = /* count of leading zeros in 5 bit numbers */
{ 5, 4, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
/* Prepare bitmap */
memset(bitmap, 0, sizeof(bitmap));
if (frame- >can_id & CAN_EFF_FLAG) {
/* bit 7 0 7 0 7 0 7 0
* bitmap[0-3] |.sBBBBBB BBBBBSIE EEEEEEEE EEEEEEEE| s = SOF, B = Base ID (11 bits), S = SRR, I = IDE, E = Extended ID (18 bits)
* bitmap[4-7] |ER10DLC4 00000000 11111111 22222222| R = RTR, 0 = r0, 1 = r1, DLC4 = DLC, Data bytes
* bitmap[8-11] |33333333 44444444 55555555 66666666| Data bytes
* bitmap[12-15] |77777777 ........ ........ ........| Data bytes
*/
bitmap[0] = (frame- >can_id & CAN_EFF_MASK) > > 23;
bitmap[1] = ((frame- >can_id > > 18) & 0x3f) < < 3 |
3 < < 1 | /* SRR, IDE */
((frame- >can_id > > 17) & 0x01);
bitmap[2] = (frame- >can_id > > 9) & 0xff;
bitmap[3] = (frame- >can_id > > 1) & 0xff;
bitmap[4] = (frame- >can_id & 0x1) < < 7 |
(!!(frame- >can_id & CAN_RTR_FLAG)) < < 6 |
0 < < 4 | /* r1, r0 */
(frame- >can_dlc & 0xf);
memcpy(&bitmap[5], &frame- >data, frame- >can_dlc);
start = 1;
end = 40 + 8*frame- >can_dlc;
} else {
/* bit 7 0 7 0 7 0 7 0
* bitmap[0-3] |.....sII IIIIIIII IRE0DLC4 00000000| s = SOF, I = ID (11 bits), R = RTR, E = IDE, DLC4 = DLC
* bitmap[4-7] |11111111 22222222 33333333 44444444| Data bytes
* bitmap[8-11] |55555555 66666666 77777777 ........| Data bytes
*/
bitmap[0] = (frame- >can_id & CAN_SFF_MASK) > > 9;
bitmap[1] = (frame- >can_id > > 1) & 0xff;
bitmap[2] = ((frame- >can_id < < 7) & 0xff) |
(!!(frame- >can_id & CAN_RTR_FLAG)) < < 6 |
0 < < 4 | /* IDE, r0 */
(frame- >can_dlc & 0xf);
memcpy(&bitmap[3], &frame- >data, frame- >can_dlc);
start = 5;
end = 24 + 8 * frame- >can_dlc;
}
/* Calc and append CRC */
crc = calc_bitmap_crc(bitmap, start, end);
crc_be = htons(crc < < 1);
assert(end % 8 == 0);
memcpy(bitmap + end / 8, &crc_be, 2);
end += 15;
/* Count stuffed bits */
mask = 0x1f;
lookfor = 0;
i = start;
stuffed = 0;
while (i < end) {
unsigned change;
unsigned bits = (bitmap[i / 8] < < 8 | bitmap[i / 8 + 1]) > > (16 - 5 - i % 8);
lookfor = lookfor ? 0 : mask; /* We alternate between looking for a series of zeros or ones */
change = (bits & mask) ^ lookfor; /* 1 indicates a change */
if (change) { /* No bit was stuffed here */
i += clz[change];
mask = 0x1f; /* Next look for 5 same bits */
} else {
i += (mask == 0x1f) ? 5 : 4;
if (i <= end) {
stuffed++;
mask = 0x1e; /* Next look for 4 bits (5th bit is the stuffed one) */
}
}
}
return end - start + stuffed +
3 + /* CRC del, ACK, ACK del */
7 + /* EOF */
3; /* IFS */
}
軟件計算負載率的缺陷
對于軟件統計負載率,即使采用精確計算填充位的算法,由于以下原因仍然不能真實的反應總線的負載情況。
- 對于CRC校驗錯誤,或者格式錯誤的幀,軟件層面一般不會接收到,也難以統計這部分錯誤幀產生的總線負載
硬件統計負載率
相比軟件計算負載率,對需要精確計算總線負載的場合,更好的方案是用專業的硬件來統計發生的bit數量,并計算負載率。
測量CAN BUS總線負載率的工具和軟件
canbusload 是linux CAN工具canutils的其中一個程序。它可以很方便的計算并刷新當前CAN總線上的負載率信息,并且提供了上述的3種軟件算法進行統計(即忽略填充位,最大計算填充位,精確計算填充位)。
以下是canbusload 的使用方法
ubuser@ubuser-Lenovo-Product:/$ canbusload
Usage: canbusload [options] < CAN interface >+
(use CTRL-C to terminate canbusload)
Options: -t (show current time on the first line)
-c (colorize lines)
-b (show bargraph in 5% resolution)
-r (redraw the terminal - similar to top)
-i (ignore bitstuffing in bandwidth calculation)
-e (exact calculation of stuffed bits)
Up to 16 CAN interfaces with mandatory bitrate can be specified on the
commandline in the form: < ifname >@
測量負載率的硬件工具
SysMax的PCAN PRO和PCAN FD使用Pcanview軟件,以及USBCAN-II的ZCANpro軟件均支持總線負載率的顯示。
評論
查看更多