资讯详情

CAN控制器芯片MCP2510调试记录

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 

修改驱动配置

有两种改法,选一种。

  1. 设备树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>;  }; }; 
  1. 代码中的初始在代码中 如果您不想更改设备树文件,可以直接更改代码,找到驱动文件drivers/net/can/spi/mcp251x.c,添加到文件中:static struct mcp251x_platform_data mcp251x_info"和"static struct spi_board_info spi_board_info具体内容见[]mcp251x.c文件开头的注释。

  2. 确认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; 

调试

  1. 接口启动报错 启动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)
  1. 收发包有问题 继续调试,发现主板无法收包,发包对端收不到,发送第二个包报错。 加打印,发包后无中断响应。 连接逻辑分析仪,发现初始化和发包,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正常收发包了,至此调试完成。^ _ ^

<a target=开发板发送命令">

标签: 8pin电子终端连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台