首页 > 学院 > 开发设计 > 正文

SPI,MCP2515调试总结

2019-11-09 14:30:06
字体:
来源:转载
供稿:网友

转自http://www.xuebuyuan.com/2055253.html

MCP2515是一SPI转CAN总线的芯片,对于CPU来说,CPU就是主设备,SPI就是从设备,所以在内核里,MCP2515就是一个SPI设备,而SPI设备在内核中的结构是对应的,是一个spi控制器对应一个SPI设备,也就是一个spi_master对应一个spi设备,而SPI设备在内核中,尤其是新的内核中(新的内核越来越注重分层和分离的结构),则是在驱动中填充spi_driver驱动信息,在板载中填充spi_board_info信息.

要移植好SPI设备,有几点是要注意的.

1,make menuconfig中,CONFIG_SPI_S3C54XX和SPI_SPIDEV这两个及其相关的选项需要打开,因为第一个是spi控制器(驱动在dev-spi.c里),第二个就是SPI设备.

2,当然作为主角的MCP251x.c的驱动选项页当然要打开,内核中,MCP251X.C这个源码已经包含,在drivers/net/can下,检查下Makefile和Kconfig,然后menuconfig里打开编译选项,这一步大概也不会有什么问题.唯一要注意的是在此源码中,需要改一下DEVICE_NAME这个宏,要跟下面提到的modalias一致,因为这是用来match用的.

3,SPI控制器好了,SPI设备驱动有了,那就还差的是SPI控制器配置,SPI的设备信息等的填充了.在/arch/arm/mach-exynos/下的machine_init函数所在源码文件中添加填充

static struct s3c64xx_spi_csinfo spi0_csi[]=//这个结构体用来设置片选引脚的{[0] = {.line = //片选引脚.set_level = gpio_set_value,.fb_delay = 0x2,},};static struct mcp251x_platform_data mcp251x_info//这个结构体用来设置振荡器频率的,至于剩下的参数要不要设,需要具体看原理图的接线情况,头文件在///include/linux/can/platform/mcp251x.hstatic struct spi_board_info spi0_board_info[]=//这个结构体用来配置SPI设备,也就是对应MCP251X.c这个设备驱动用的,注意modalias要对上.{.modalias = ,//要跟mcp251x.c上的DEVICE_NAME宏对上.max_speed_hz = ,//CPU支持最高50MHz,但MCP2515芯片最高只支持到10MHZ,这里要好好权衡一下.bus_num = ,//SPI总线的选择,CPU提供3条SPI总线.chip_select = ,//SPI总线上第几个设备的选择.mode = SPI_MODE_0,//关于CPOL CPHA这2个值得选择,有4种模式 00 01 10 11.platform_data = &mcp251x_info,//传给mcp251x.c驱动用的参数,就是上面的一个结构体..controller_data = &spi0_csi[0],//上面的一结构体,片选所用.irq = ,//mcp2515芯片有一中断脚连到CPU,把复用后的中断量复制在此}

这三个结构体填充完后(记得加上相应的头文件),就在static struct platform_device上添加初始化用的设备的变量exynos_device_spi的地址,这是给machine_init函数在添加这三个变量的时候用的,

struct clk *sclk = NULL;struct clk *PRnt = NULL;struct device *spi0_dev = &exynos_device_spi0.dev;sclk = clk_get(spi0_dev, "dout_spi0");if (IS_ERR(sclk))dev_err(spi0_dev, "failed to get sclk for SPI-0/n");prnt = clk_get(spi0_dev, "mout_mpll_user");if (IS_ERR(prnt))dev_err(spi0_dev, "failed to get prnt/n");if (clk_set_parent(sclk, prnt))printk(KERN_ERR "Unable to set parent %s of clock %s./n",prnt->name, sclk->name);

clk_set_rate(sclk, 10 * 1000 * 1000);clk_put(sclk);clk_put(prnt);

if (!gpio_request(片选引脚宏地址, 片选引脚名)) {gpio_direction_output(片选引脚宏地址, 1);s3c_gpio_cfgpin(片选引脚宏地址, S3C_GPIO_SFN(1));s3c_gpio_setpull(片选引脚宏地址, S3C_GPIO_PULL_UP);exynos_spi_set_info(0, EXYNOS_SPI_SRCCLK_SCLK,ARRAY_SIZE(spi0_csi));}spi_register_board_info(spi0_board_info, ARRAY_SIZE(spi0_board_info));

而这里主要是注册SPI设备和SPI的时钟配置,配置好这些后正常的话就已经把mcp2515的can0设备驱动移植好了.如果在这里出了问题,不防先设置好spidev.c的驱动,先调好spi的控制器,再把spidev替换成mcp2515.

4,CAN总线在新版本的内核中,并不是以字符设备的形式出现的,原因内核也有说明,主要是因为内核把CAN设备看成了网络设备(当然由于CAN设备的特殊性,CAN是没有IP地址可言的),需要用到socketcan协议,所以要想运行CAN总线,那么就要再menuconfig上打开can的协议(打开项在Networking support-->CAN bus subsystem support下).

5,内核部分完成后,就到Android部分了,由于不是字符设备,不能对其进行简单的读写操作,所以要用到2个工具,iproute2 和 canutiliproute2在安卓源码上就有,external/iproute2,而canutil则在网上可以下到,而是用canutil内的命令,还需要用到libsocketcan的库.

调试总结:在刚开始调试的时候,spi在内核中的框架并不熟悉,困惑于spidev.c和mcp251x.c之间的关系怎么处理,spi的设备怎么设置时钟,为什么mcp251x.c驱动调出来之后再spi下的目录里没有mcp251x的字符设备可供调用等等.其实spidev跟mcp251x是处于同一位置的spi设备,都由spi控制器控制,或许是可以在spi0_board_info结构体填充chip_select的时候填上排序的序号,可是最后没有用上,因为spidev不是一个实质的设备.而spi下没有mc251x的字符设备供调用是因为mcp251x的驱动节点在net/can0里,意味着内核把它注册为网络设备.这里在调试的时候最好还是先用spidev来先调好spi控制器,因为spidev的驱动提供了可调用的 spi下的字符设备节点,而在内核中,已经提供了spi设备的测试代码在document/spi下,在编译好后放到开发板上,并将spi发送接收的2条线接上,那么正常的情况下spi就能实现自收自发,这时再去调试mcp251x.c的驱动,就可以不用担心spi在系统上出太大问题了(不过关于时钟这一部分,需要好好地配置).然后再测试can接口的时候,iproute2这个工具出现过bitrate这个参数无法辨认的情况,其实是在iproute2/ip目录下对iplink_can.c并没有实际调用,归根到底,是在编译android的时候,某些iplink_can.c内某些头文件没有顺利调用导致最后ip命令的参数不支持can,最后吧头文件的include写成了相对地址来调用,就可以了.而对于canutil这个工具,要顺利编译好,也经过了一些波折,自己用的编译器比较多,环境变量不全,是个挺麻烦的问题,最后自己添加了环境变量,同时无视了伯克利相关的库后,勉强编译成功了cansend candump canecho和cansequence四个工具去调用.现在,使用ip link set can0 type can bitrate xxx这些命令来设置波特率,用cansend和candump来发送接收,能用示波器看到波形了,但是数据在接收那边还没能出来,这个在之后得后续更新原因.

6、本文主要验证Linux-imx_share/Documentation/spi目录下spidev_test.c的测试例程,能否正常控制SPI接口。在命令行下输入ifconfig -a,已经出现can0信息


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表