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]
		};
	};
};

/ {
	// 这里是配置MCP2510使用的外部时钟,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 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)
  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正常收发包了,至此调试完成。^ _ ^

开发板发送命令
另一端接收到包

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: MCP2516FD是Microchip推出的一款CAN总线收发器和控制器。它支持CAN FD(Flexible Data-Rate,灵活数据率)协议,该协议是CAN总线协议的进一步优化和延伸。 收发器部分是指MCP2516FD的物理层接口,它能够将控制器部分产生的CAN消息转换成电信号,并通过CAN总线发送出去;同时,它能够接收CAN总线上的电信号,并将其转换成可以被控制器读取和处理的CAN消息。通过收发器,MCP2516FD能够实现与其他CAN节点的通信。 控制器部分是指MCP2516FD的逻辑层实现,它包括了CAN协议的处理和数据帧的装填、发送和接收等功能。通过控制器,MCP2516FD实现了CAN节点的协议栈功能,使得它能够与其他CAN节点建立通信,并传输数据。 MCP2516FD的控制器采用了灵活的数据率(Flexible Data-Rate)技术,使得它能够在高速CAN网络环境下实现更高的数据传输速率。同时,它也支持标准CAN协议,可以与传统的CAN节点进行兼容。 总之,MCP2516FD收发器和控制器的结合使得它成为一种功能强大的CAN解决方案。它适用于需要高速、可靠通信的应用场景,如汽车电子、工业自动化等领域。 ### 回答2: MCP2516FD是一款CAN总线通信协议的收发器和控制器。CAN(Controller Area Network)是一种广泛应用于汽车和工业控制等领域的通信总线协议,用于设备之间的数据传输。 MCP2516FD提供了双向的CAN总线通信功能,可以从外部接收CAN消息,并将其解析为控制器可读的数据。同时,它也可以将控制器生成的数据转换为CAN消息,通过总线发送给其他设备。 MCP2516FD的主要功能包括消息传输、地址过滤、错误检测和计时器等。其中,消息传输是指它能够实现在CAN总线上发送和接收数据。地址过滤是通过设置过滤规则,只接收特定地址的消息,从而提高通信效率。错误检测功能可以检测和管理总线上的错误,包括位错误、帧错误等。计时器的作用是保证数据的同步传输,实现数据的有效接收和发送。 MCP2516FD还具有可配置的通信速率,可以根据应用需求选择不同的通信速率,以满足不同数据传输的要求。它还支持SPI(串行外设接口)接口,可以与主控制器进行串行通信。 总的来说,MCP2516FD是一款功能强大的CAN总线通信收发器和控制器,具有可靠的数据传输和错误检测功能,能满足汽车和工控领域等应用对CAN总线通信的要求。 ### 回答3: MCP2516FD是一种高性能的CAN收发器和控制器,用于CAN总线通信系统。它具有以下特点和功能。 首先,MCP2516FD采用先进的技术和设计,支持CAN FD(Flexible Data-Rate)协议。CAN FD协议相比传统的CAN协议,具有更高的数据传输速率和更大的数据负载容量。这使得MCP2516FD能够在高速和大数据量的通信环境下,提供可靠和高效的数据传输。 其次,MCP2516FD具有强大的收发能力。它能够同时实现CAN消息的接收和发送,并支持多个CAN标识符和数据长度。它还提供了多种接收和发送模式,包括标准模式、扩展模式和混合模式,以满足不同应用场景的需求。 此外,MCP2516FD具有灵活且易于使用的控制功能。它提供了丰富的控制寄存器和位定义,使得用户可以方便地配置和控制MCP2516FD的工作模式和参数。它还支持自动的错误检测和处理,包括错误帧的接收和错误状态的指示。 最后,MCP2516FD的硬件设计精良,具有低功耗和高可靠性。它采用了低功耗设计,能够在待机模式下降低功耗,从而延长电池寿命。它还具有过压保护和热保护等功能,以确保系统的稳定运行和安全性。 综上所述,MCP2516FD是一款功能强大、灵活易用的CAN收发器和控制器。它的高性能和可靠性使得它在汽车、工业控制、通信等领域得到广泛应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值