CAN BUS的总线负载率是CAN总线架构协议设计时的一个重要的指标。一般建议负载率峰值不要高于80%,平均负载率不要超过50%。当然这只是一般建议,具体根据使用场景和系统设计而定。
负载率定义
关于CAN负载率的定义和计算,很多文章写得不求甚解,用帧数量来计算负载率是非常不正确的做法。
其实总线负载率的定义其实是非常简单明了的:
总线负载率=总线每秒上传输的实际bit数量/总线波特率*100%
原理非常简单,波特率的定义就是每秒CAN总线上可以传输多少CAN数据bit,总线负载率自然就是总线实际传输的bit数量比上总线可以承载的最大bit数了。
例如,100K的总线波特率,总线上最大承载的数据量就是100K个bit。如果总线上实际传输了50K个bit位,那么负载率就是50%。
负载率计算
对于上面的计算公式,对于一个CAN总线而言,波特率一般都是已知的。计算负载率的关键就是通过CAN报文统计出总线上每秒传输的bit数量。那么就需要回到CAN的帧格式来计算实际发生的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数。
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 */
}
软件计算负载率的缺陷
对于软件统计负载率,即使采用精确计算填充位的算法,由于以下原因仍然不能真实的反应总线的负载情况。
1. 对于CRC校验错误,或者格式错误的帧,软件层面一般不会接收到,也难以统计这部分错误帧产生的总线负载
硬件统计负载率
相比软件计算负载率,对需要精确计算总线负载的场合,更好的方案是用专业的硬件来统计发生的bit数量,并计算负载率。
测量CAN BUS总线负载率的工具和软件
Linux下使用canbusload?
canbusload 是linux CAN工具canutils的其中一个程序。它可以很方便的计算并刷新当前CAN总线上的负载率信息,并且提供了上述的3种软件算法进行统计(即忽略填充位,最大计算填充位,精确计算填充位)。
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>@<bitrate>
The bitrate is mandatory as it is needed to know the CAN bus bitrate to
calcultate the bus load percentage based on the received CAN frames.
Due to the bitstuffing estimation the calculated busload may exceed 100%.
For each given interface the data is presented in one line which contains:
(interface) (received CAN frames) (used bits total) (used bits for payload)
Example:
user$> canbusload can0@100000 can1@500000 can2@500000 can3@500000 -r -t -b -c
canbusload 2014-02-01 21:13:16 (worst case bitstuffing)
can0@100000 805 74491 36656 74% |XXXXXXXXXXXXXX......|
can1@500000 796 75140 37728 15% |XXX.................|
can2@500000 0 0 0 0% |....................|
can3@500000 47 4633 2424 0% |....................|
硬件工具
PEAK的PCAN PRO和PCAN FD,以及周立功的ZCANpro软件均支持总线负载率的显示。
开源的Busmaster也同样支持负载率统计,并且都支持负载率实时曲线绘制
|