IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> CAN控制器芯片MCP2510调试记录 -> 正文阅读

[C++知识库]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正常收发包了,至此调试完成。^ _ ^

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

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-22 20:23:18  更:2022-02-22 20:24:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:41:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码