CAN控制器芯片MCP2510调试记录
配置CAN内核选项
配置CAN相关的内核选项,将下面几项配置添加到defconfig中:
kernel/arch/arm/configs/xxx_defconfig
CONFIG_CAN=y
CONFIG_CAN_RAW=y
CONFIG_CAN_BCM=y
CONFIG_CAN_GW=y
CONFIG_CAN_DEV=y
CONFIG_CAN_CALC_BITTIMING=y
CONFIG_CAN_MCP251X=y
在defconfig添加了配置后就不用手动配置了。要手动配置可以进入kernel目录,打开menuconfig配置。
make ARCH=arm menuconfig
进入这个路径配置can相关配置:Networking support ---> CAN bus subsystem support
修改驱动配置
有两种改法,选其一即可。
- 设备树DTS文件中修改
&spi2 {
status = "okay";
can@0 {
compatible = "microchip,mcp2510";
reg = <0>;
clocks = <&xin16m>;
// GPIO中断
interrupt-parent = <&gpio3>;
interrupts = <10 GPIO_ACTIVE_LOW>; // CAN_INT [21]
// 不同电压支持的SPI最大速率不同,SPI: VDD = 3.0V to 4.5V, 2.5MHz
spi-max-frequency = <2500000>;
pinctrl-names = "default";
pinctrl-0 = <&can_pin_ctrl &can_int>;
// SPI的极性与相位 默认是0,0
//spi-cpha = <1>;
//spi-cpol = <1>;
};
};
&pinctrl {
can {
can_int: can-int {
rockchip,pins = <3 10 RK_FUNC_GPIO &pcfg_pull_up>; // CAN_INT [21]
};
can_pin_ctrl: can-pin-ctrl {
rockchip,pins = <4 27 RK_FUNC_GPIO &pcfg_pull_none>, // CAN_STB [21]
<3 17 RK_FUNC_GPIO &pcfg_pull_up>, // CAN_RST [21]
<3 11 RK_FUNC_GPIO &pcfg_pull_none>, // CAN_RXB0 [21]
<3 12 RK_FUNC_GPIO &pcfg_pull_none>, // CAN_RXB1 [21]
<3 13 RK_FUNC_GPIO &pcfg_pull_up>, // CAN_TXB0 [21]
<3 14 RK_FUNC_GPIO &pcfg_pull_up>, // CAN_TXB1 [21]
<3 15 RK_FUNC_GPIO &pcfg_pull_up>; // CAN_TXB2 [21]
};
};
};
/ {
// 这里是配置MCP2510使用的外部时钟,16MHz
xin16m: xin16m {
compatible = "fixed-clock";
clock-frequency = <16000000>;
clock-output-names = "xin16m";
#clock-cells = <0>;
};
};
-
代码中初始化结构体 不想改设备树文件,可以直接改代码,找到驱动文件drivers/net/can/spi/mcp251x.c,在文件中添加:“static struct mcp251x_platform_data mcp251x_info"和"static struct spi_board_info spi_board_info[]”,具体内容看mcp251x.c文件开头的注释。 -
确认SPI通信 SPI没有调通时,可以打开SPI回环测试的驱动,调通了再进行下一步。 瑞星微平台参考这个方法进行SPI回环测试:
drivers/spi/Makefile添加一行代码编译
obj-y += spi-rockchip-test.o
设备树dts文件中,添加:
&spi2 {
// loop test ok
// should add 'spi-rockchip-test.o' build in 'kernel/drivers/spi/Makefile'
/*spi_test@00 {
compatible = "rockchip,spi_test_bus0_cs0";
reg = <0>; //chip select 0:cs0 1:cs1
id = <0>;
spi-max-frequency = <24000000>; //spi output clock
//spi-cpha; not support
//spi-cpol; //if the property is here it is 1:clk is high, else 0:clk is low when idle
};
spi_test@01 {
compatible = "rockchip,spi_test_bus0_cs1";
reg = <1>;
id = <1>;
spi-max-frequency = <24000000>;
spi-cpha;
spi-cpol;
};*/
};
编译和更新后,调用下面命令进行SPI回环测试:
/* how to test spi
* echo write 0 10 255 > /dev/spi_misc_test // spi-id, times, size
* echo write 0 10 255 init.rc > /dev/spi_misc_test
* echo read 0 10 255 > /dev/spi_misc_test
* echo loop 0 10 255 > /dev/spi_misc_test
* echo setspeed 0 1000000 > /dev/spi_misc_test // spi-id, max_speed_hz
*/
移植软件
移植canutils+libsocketcan软件 参考我的这篇文章 https://blog.csdn.net/liteblue/article/details/123061488 移植好的canutils程序 https://download.csdn.net/download/liteblue/54730175
CAN硬件环境准备
使用CAN分析仪,把CAN_H连接到目标板子的CAN_H,把CAN_L连接到目标板子的CAN_L。我板子上有120Ω终端电阻了,所以CAN分析仪拨一个码打开一个120Ω电阻,确保断电测量CAN_H和CAN_L间电阻是60Ω(电阻并联公式 (120*120)/(120+120)=60)。
启动CAN接口命令
设置波特率为50kbps;triple-sampling好像是收包时3次采样,也可以不要;
ip link set can0 type can bitrate 50000 triple-sampling on;
回环模式,芯片自收自发,会屏蔽CAN收发器的信号;
ip link set can0 type can bitrate 50000 loopback on;
侦听模式,不会发包;
ip link set can0 type can bitrate 50000 listen-only on;
启动接口;
ip link set can0 up;
发送一个CAN数据包;
cansend can0 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88;
cansend can0 -i 0x10 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88;
查看详细统计;
ip -details link show can0;
cat /proc/net/can/stats;
打印收到的包,可以发包时在后台同时执行;
candump can0;
关闭CAN接口
ip link set can0 down;
调试
- 接口启动报错
启动can0接口时,有报错(RTNETLINK answers: No sucrh device),加打印后,发现是mcp251x_hw_reset出错了。可以自行在mcp251x_open函数内的mcp251x_hw_reset函数后添加错误打印。
130|console:/ # ip link set can0 up;
RTNETLINK answers: No sucrh device
[ 612.849549] E CAN mcp251x_open 1020: failed mcp251x_hw_reset, ret=-19
尝试将mcp251x_hw_reset函数内的延时增大后,就解决了。问题原因是驱动发送第一个reset指令时,芯片还未初始化完成,读到的状态不对,加大延时就解决了。
#define MCP251X_OST_DELAY_MS (20)//(5)
- 收发包有问题
继续调试,发现主板无法收包,发包对端收不到,发送第二个包报错。 加打印,发包后无中断响应。 连接逻辑分析仪,发现初始化和发包,SPI都有信号。 打开回环测试模式,发包,能正确收到自己发的包。 用逻辑分析仪发包,逻辑分析仪的两个口能互相收到,说明总线是正常的。
加dump寄存器的代码:
#define MCP251X_DEBUG
#ifdef MCP251X_DEBUG
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/kobject.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
static struct dentry *mcp251x_debug_root = NULL;
static struct dentry *mcp251x_debug_dir = NULL;
void dump_mcp251x_regs(void *priv_ptr, const char *msg)
{
struct mcp251x_priv *priv;
struct spi_device *spi;
if (!priv_ptr) {
return;
}
priv = (struct mcp251x_priv *)priv_ptr;
spi = priv->spi;
/* Configuration Registers */
#define REG_BFPCTRL 0x0C
#define REG_TXRTSCTRL 0x0D
#define REG_CANSTAT 0x0E // CAN 状态寄存器 p53
#define REG_CANCTRL 0x0F // CAN 控制寄存器 p52
#define REG_TEC 0x1C // 发送错误计数器 p42
#define REG_REC 0x1D // 接收错误计数器
#define REG_CNF3 0x28 // 配置寄存器3 p40
#define REG_CNF2 0x29 // 配置寄存器2 p40
#define REG_CNF1 0x2A // 配置寄存器1 p39
#define REG_CANINTE 0x2B // 中断使能寄存器 p47
#define REG_CANINTF 0x2C
#define REG_EFLG 0x2D
/* Tx Buffer 0, 14 bytes, 6+8 */
// TXBnEIDH - 发送缓冲器 n 扩展标识符高位 p19
#define REG_TXB0CTRL 0x30 // 发送缓冲器 n 控制寄存器 p17
#define REG_TXB0SIDH 0x31 // 发送缓冲器 n 标准标识符高位 p18
#define REG_TXB0SIDL 0x32 // 发送缓冲器 n 标准标识符低位 p19
#define REG_TXB0EID8 0x33 // 发送缓冲器 n 扩展标识符低位 p19
#define REG_TXB0EID0 0x34 // 发送缓冲器 n 扩展标识符低位 p20
#define REG_TXB0DLC 0x35
// TXBnDm - 发送缓冲器 n 数据段字节 m p20
#define REG_TXB0D0 0x36
#define REG_TXB0D1 0x37
#define REG_TXB0D2 0x38
#define REG_TXB0D3 0x39
#define REG_TXB0D4 0x3A
#define REG_TXB0D5 0x3B
#define REG_TXB0D6 0x3C
#define REG_TXB0D7 0x3D
#define PRINT_REG(REG) \
CAN_DBG("Reg %s 0x%02X = 0x%02X", #REG, REG, mcp251x_read_reg(spi, (REG)))
mutex_lock(&priv->mcp_lock);
#ifdef ENABLE_DEBUG_REG_RW
is_print_reg_rw = 0;
#endif
CAN_DBG("----------- %s dump regs -----------", msg);
PRINT_REG(REG_CANSTAT );
PRINT_REG(REG_CANCTRL );
PRINT_REG(REG_BFPCTRL );
PRINT_REG(REG_TEC );
PRINT_REG(REG_REC );
PRINT_REG(REG_CNF3 );
PRINT_REG(REG_CNF2 );
PRINT_REG(REG_CNF1 );
PRINT_REG(REG_CANINTE );
PRINT_REG(REG_CANINTF );
PRINT_REG(REG_EFLG );
PRINT_REG(REG_TXRTSCTRL);
PRINT_REG(REG_TXB0CTRL );
PRINT_REG(REG_TXB0SIDH );
PRINT_REG(REG_TXB0SIDL );
PRINT_REG(REG_TXB0EID8 );
PRINT_REG(REG_TXB0EID0 );
PRINT_REG(REG_TXB0DLC );
PRINT_REG(REG_TXB0D0 );
PRINT_REG(REG_TXB0D1 );
PRINT_REG(REG_TXB0D2 );
PRINT_REG(REG_TXB0D3 );
PRINT_REG(REG_TXB0D4 );
PRINT_REG(REG_TXB0D5 );
PRINT_REG(REG_TXB0D6 );
PRINT_REG(REG_TXB0D7 );
CAN_DBG("---------------------------------");
#ifdef ENABLE_DEBUG_REG_RW
is_print_reg_rw = 1;
#endif
mutex_unlock(&priv->mcp_lock);
}
// cat /sys/kernel/debug/can/mcp251x/dumpreg
static int mcp251x_debugfs_show(struct seq_file *m, void *v)
{
struct mcp251x_priv *priv = m->private;
struct spi_device *spi = priv->spi;
dump_mcp251x_regs(priv, "sysfile dump");
//seq_printf(m, "\n--- mcp251x_debugfs_show ---\n");
return 0;
}
static int mcp251x_debugfs_open(struct inode *inode, struct file *file)
{
return single_open(file, mcp251x_debugfs_show, inode->i_private);
}
static const struct file_operations mcp251x_debugfs_fops = {
.owner = THIS_MODULE,
.open = mcp251x_debugfs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#endif // MCP251X_DEBUG
//在probe和remove函数中创建/删除调试节点:
static int mcp251x_can_probe(struct spi_device *spi)
{
...
#ifdef MCP251X_DEBUG
mcp251x_debug_root = debugfs_create_dir("can", NULL);
if (mcp251x_debug_root) {
mcp251x_debug_dir = debugfs_create_dir("mcp251x", mcp251x_debug_root);
if (!mcp251x_debug_dir) {
CAN_ERR("failed to register to debugfs\n");
} else {
debugfs_create_file("dumpreg", 0400, mcp251x_debug_dir,
priv, &mcp251x_debugfs_fops);
}
} else {
CAN_ERR("Warning: Cannot create mcp251x directory in debugfs\n");
}
#endif
}
static int mcp251x_can_remove(struct spi_device *spi)
{
...
#ifdef MCP251X_DEBUG
debugfs_remove_recursive(mcp251x_debug_dir);
mcp251x_debug_dir = NULL;
debugfs_remove_recursive(mcp251x_debug_root);
mcp251x_debug_root = NULL;
#endif
}
dump寄存器后发现CAN配置和发包的14个寄存器(6+8)都非常正常,于是从硬件角度分析可能存在的问题。
测量MCP2510和CAN收发器TJA1042T-SO8相关Pin,基本上各个Pin电压都符合手册上的要求,可疑的点就是MCP2510是3.3V供电,这里可能存在问题,因为以前调试过同族的芯片MCP2515当时就是5V供电,这里电压变化直接影响就是SPI的最大速率会下降。
咨询了硬件同事,他看出了问题,可能CAN芯片和CAN收发器要相同电压才能正常通信,于是换了一个3.3V的CAN收发器。
重新测试,CAN正常收发包了,至此调试完成。^ _ ^
|