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] }; }; }; / { // 这里是配置MCP外部时钟用于2510,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 sucrhdevice
[ 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正常收发包了,至此调试完成。^ _ ^
开发板发送命令">