目录
[ID 波形](#ID 波形)
[CAN 压测](#CAN 压测)
原理图部分

DTS部分
\kernel\drivers\net\can\spi\mcp251x.c
除了SPI及CAN 部分,另外有INT# \RST#管脚及时钟配置,此处使用了16M。芯片本身支持8M和16M两种。
/ {
can3_osc: can3-osc {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <16000000>;
};
};
/* 中断引脚电气配置 */
&pinctrl {
mcp2515 {
mcp2515_int_pins: mcp2515-int-pins {
rockchip,pins = <3 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};
&spi4 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&spi4m1_cs0 &spi4m1_pins>;
max-freq = <10000000>;
can3: mcp2515@0 {
status = "okay";
compatible = "microchip,mcp2515";
reg = <0>;
spi-max-frequency = <10000000>;
interrupt-parent = <&gpio3>;
interrupts = <RK_PC7 IRQ_TYPE_LEVEL_LOW >; /* GPIO3_C7 */
pinctrl-names = "default";
/* 中断引脚 pinctrl 配置 */
pinctrl-0 = <&mcp2515_int_pins>;
/* 复位引脚配置 */
// reset-gpios = <&gpio3 RK_PC6 GPIO_ACTIVE_HIGH>; /* GPIO3_C6 */
clocks = <&can3_osc>;
vdd-supply = <&vcc_3v3_s3>;
xceiver-supply = <&vcc_3v3_s3>;
};
};
注意这里重点配置了低电平触发,网上有很多配置为下降沿的教程。
复位的配置被注释掉了,理由如下:

实际上该芯片支持两种复位方式,通过其中一种复位即可。
驱动的复位代码
在probe时,调用了spi 命令对芯片进行复位操作。
static int mcp251x_hw_reset(struct spi_device *spi)
{
struct mcp251x_priv *priv = spi_get_drvdata(spi);
u8 value;
int ret;
/* Wait for oscillator startup timer after power up */
mdelay(MCP251X_OST_DELAY_MS);
priv->spi_tx_buf[0] = INSTRUCTION_RESET;
ret = mcp251x_spi_write(spi, 1);
if (ret)
return ret;
/* Wait for oscillator startup timer after reset */
mdelay(MCP251X_OST_DELAY_MS);
/* Wait for reset to finish */
ret = mcp251x_read_stat_poll_timeout(spi, value, value == CANCTRL_REQOP_CONF,
MCP251X_OST_DELAY_MS * 1000,
USEC_PER_SEC);
if (ret)
dev_err(&spi->dev, "MCP251x didn't enter in conf mode after reset\n");
return ret;
}
SPI调试
将设备配置为spidev,以便调试spi的通路
&spi0 {
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&spi0m3_cs0 &spi0m3_pins>;
num-cs = <1>; /* 或按需设置,例如 <1> 只使用CS0 */
spidev@0 {
compatible = "rockchip,spidev";
reg = <0>;
spi-max-frequency = <1000000>;
};
};
测试命令
apt-get install spi-tools
读取ID
printf '\x9F\x00\x00\x00' | spi-pipe -d /dev/spidev0.0 -b 4 -n 1 -s 100000 |hexdump -C
00000000 00 ef 40 18 |..@.|
00000004
参数含义: -b (--blocksize): 数据块大小
这个参数设定一个数据块的大小,单位是字节 (Bytes)。
例如 -b 4:告诉 spi-pipe,把数据切成一个个 4字节 的小块来处理。
-n (--number): 数据块数量
这个参数设定要传输多少个这样的数据块。
例如 -n 10:表示总共要传输 10个 数据块。
特殊值 -1:一个非常有用的值,表示连续不间断地传输。这在你想用示波器长时间观察 CLK(时钟)或 CS(片选)信号时特别方便。
如下的命令在读取ID时,虽然信号MOSI量到的数据OK,但MISO无输出。
printf '\x9F' | spi-pipe -d /dev/spidev0.0 -s 100000 | hexdump -C (命令不可行)
spi-config -d /dev/spidev0.0 -q
/dev/spidev0.0: mode=0, lsb=0, bits=8, speed=10000000, spiready=0
ID 波形

命令4B 。
第一个低电平非数据位,从第二个低电平开始0100 1011=4B

MISO 返回数据
如果此管脚仅仅是抖一下,可能是CS控制不对,不一定是硬件问题。

0x55 通过上述命令可以发个0x55 ,虽然不是正规命令,但可以分析MOSI是否正常。0x55波形如下:

spi驱动解绑
有时为了隐藏设备,避免用户误操作,可以通过如下命令卸载设备节点及重新恢复。
|---------------------------------------------------------|
| echo -n "spi0.0" > /sys/bus/spi/drivers/spi-nor/unbind |
| |
| echo -n "spi0.0" > /sys/bus/spi/drivers/spi-nor/bind |
CAN 压测
PC单向压测0.5ms
按照如下参数配置,PC发送,单板接收。单板不发送。总线负载不到30%

ip -details -statistics link show can3
6: can3: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UP mode DEFAULT group default qlen 10
link/can promiscuity 0 minmtu 0 maxmtu 0
can state ERROR-ACTIVE restart-ms 0
bitrate 1000000 sample-point 0.750
tq 125 prop-seg 2 phase-seg1 3 phase-seg2 2 sjw 1 brp 1
mcp251x: tseg1 3..16 tseg2 2..8 sjw 1..4 brp 1..64 brp_inc 1
clock 8000000
re-started bus-errors arbit-lost error-warn error-pass bus-off
0 0 0 2 2 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
RX: bytes packets errors dropped missed mcast
3199969 400018 13 0 0 0
TX: bytes packets errors dropped carrier collsns
1600000 200000 0 0 0 0
"
PC单向压测1ms
5从100万都没有丢包

第一次测试

第二次测试

单板发送
cangen can0 -g 1 -I 101 -L 8 -D 1122334455667788 -x -n 100000 -p 1 (压测)
p 参数可以在发送缓存满时重试。
CPU占用率
2154 root 20 0 16016 9184 7300 S 28.4 0.2 1:04.92 sshd
2045 root -51 0 0 0 0 D 15.2 0.0 0:34.21 irq/124-spi4.0
2207 root 20 0 2272 772 696 S 13.9 0.0 0:31.91 candump
201 root 20 0 0 0 0 S 9.6 0.0 0:22.49 spi4
协议栈
cat /proc/net/can/stats

mcp251x_can_ist
if (intf & CANINTF_ERRIF) {
/* Handle overflow counters */
if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
if (eflag & EFLG_RX0OVR) {
net->stats.rx_over_errors++;
net->stats.rx_errors++;
}
if (eflag & EFLG_RX1OVR) {
net->stats.rx_over_errors++;
net->stats.rx_errors++;
}
can_id |= CAN_ERR_CRTL;
data1 |= CAN_ERR_CRTL_RX_OVERFLOW;
}
mcp251x_error_skb(net, can_id, data1);
}
这里即使有overrun的统计,驱动也会将报文上报的协议栈层,进而上报到数据层面。这会导致在协议栈层看到的报文数量比实际大,例如PC发送20万,有4个over错误,这时在协议栈层面看到的统计可以是20万04个。
taskset -c 7 candump -s 2 can3
echo 2 > /proc/irq/100/smp_affinity
3588 canfd
rockchip_canfd fea50000.can can0: incorrect/missing data bit-timing
用如下命令可以解决上报错
ip link set can0 type can bitrate 1000000 dbitrate 4000000 fd on
ip -details -statistics link show can1
4: can1: <NOARP,UP,LOWER_UP,ECHO> mtu 72 qdisc pfifo_fast state UP mode DEFAULT group default qlen 10
link/can promiscuity 0 minmtu 0 maxmtu 0
can <FD> state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 1
bitrate 1000000 sample-point 0.747
tq 10 prop-seg 36 phase-seg1 37 phase-seg2 25 sjw 1 brp 2
rockchip_canfd: tseg1 1..128 tseg2 1..128 sjw 1..128 brp 1..256 brp_inc 2
dbitrate 1000000 dsample-point 0.727
dtq 90 dprop-seg 3 dphase-seg1 4 dphase-seg2 3 dsjw 1 dbrp 18
rockchip_canfd: dtseg1 1..32 dtseg2 1..16 dsjw 1..16 dbrp 1..256 dbrp_inc 2
clock 198000000
re-started bus-errors arbit-lost error-warn error-pass bus-off
0 0 0 0 0 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
RX: bytes packets errors dropped missed mcast
83336 10417 0 0 0 0
CAN FD 模式在驱动层已经成功启用 ,mtu 72 和 can <FD>
总结
该芯片支持缓存两帧数据。如果对端发送过快,例如本例测试的0.5ms间隔,会有少量溢出及丢包(丢包只存在统计中,例如对端发送20万,本端收到19万8,有几个包丢失)
此外该芯片不支持CANFD,属于老一代芯片。对于当前的需求不友好。
实际业务的发包间隔及需求才是选型的王道。