短文介绍如何使用全志H3和MCP2515进行can通信
软件资源:
1、全志H3 SDK,linux3.49
2、交叉编译器:arm-linux-gnueabi-gcc
硬件资源:
1、PC ubuntu14.04
2、MCP2515
3、H3 demo板
开发步骤:
1、首先确保能够使用交叉编译器编译出H3可运行的最小linux系统(可看小民之前写的另外一篇博客);
2、menuconfig如下,在网络设备文件支持里面选中RAW CAN Protocol ;
选中CAN Device Drivers;选中Microchip MCP251x SPI CAN controllers
3、配置SPI,MCP2515芯片使用SPI和主机通信
4、修改平台文件:/home/fanxiangqiang/src/lichee/linux-3.4/arch/arm/mach-sunxi/sun8i.c,对mcp2515_pdata的定义在文件/home/fanxiangqiang/src/lichee/linux-3.4/include/linux/can/platform/mcp251x.h
添加如下代码:
///////////////////////////////////////////////
/* spi device controller state, alloc */
struct sunxi_spi_config {
int bits_per_word; //8bit
int max_speed_hz; //80MHz
int mode; // pha,pol,LSB,etc..
};
struct mcp251x_platform_data mcp2515_pdata = {
8000000, 0, NULL, NULL, NULL,
};
struct sunxi_spi_config sunxi_data = {
8, 2000000, SPI_MODE_0
};
struct spi_board_info spi_infos[] = {
{
.modalias = "mcp2515",
.platform_data = &mcp2515_pdata,
.controller_data = &sunxi_data,//需查控制器的驱动代码,可得知需要提供struct sunxi_spi_config类型数据. 注意不同的同台,需要数据类型也会不同 //
//.irq = gpio_to_irq(GPIOA(10)),
.max_speed_hz = 2000000, //2MHz
.bus_num = 1, // 接着编号为0的控制器
.mode = SPI_MODE_0,
},
};
/////////////////////////////////////////
init sunxi_dev_init(void)这个函数中需要添加对MCP2515的注册,它会将MCP2515注册到 /sys/bus目录下
printk("ina219 devi--------------------------------------------ce registered\n");
///////////////////////////////
spi_infos[0].irq = gpio_to_irq(GPIOA(3));
spi_register_board_info(spi_infos, ARRAY_SIZE(spi_infos));
////////////////////////////////
5、改sys_config.fex,这里的这个文件相当于设备数文件,全志好像没给dts文件,还是我没找到。。。。,把所有的关于spi 设备相关的描述注释掉,不然不会生成can0 设备。
;----------------------------------------------------------------------------------
;SPI device configuration
;----------------------------------------------------------------------------------
;[spi_devices]
;spi_dev_num = 1
;[spi_board0]
;modalias = spidev
;max_speed_hz = 33000000
;bus_num = 1
;chip_select = 0
;mode = 0
5、编译,下载,CAN总线作为网络设备,使用ifconfig -a ,可以在网络接口设备中看见can0
启动log如下:
[ 1.360579] sunxi_spi_chan_cfg()1376 - [spi-0] has no spi_regulator.
[ 1.367637] sunxi_spi_chan_cfg()1376 - [spi-1] has no spi_regulator.
[ 1.374721] sunxi_spi_register_spidev()1987 - Get spi devices number failed
[ 1.382469] sunxi_spi_init()2073 - register spi devices board info failed
[ 1.390118] sunxi_spi_init()2082 - Sunxi SPI init channel 1
[ 1.396577] sunxi_spi_probe()1665 - [spi-1]: cs bitmap from cfg = 0x1
[ 1.403985] sunxi_spi_request_gpio()1416 - Pinctrl init 1 ... [spi1]
[ 1.411193] sunxi_spi_clk_init()1484 - [spi-1] mclk 100000000
[ 1.417580] spi_set_clk()219 - set spi clock 10000000, mclk 100000000
[ 1.424751] spi_set_clk()229 - CDR2 - n = 4
[ 1.429593] spi spi1: registered master spi1
[ 1.434355] spi spi1: master is unqueued, this is deprecated
[ 1.440674] spi spi1.0: setup mode 0, 8 bits/w, 2000000 Hz max --> 0
[ 1.447807] spi spi1: registered child spi1.0
[ 1.452666] sunxi_spi_probe()1719 - allwinners SoC SPI Driver loaded for Bus SPI-1 with 1 Slaves at most
[ 1.463212] sunxi_spi_probe()1720 - [spi-1]: driver probe succeed, base f1c69000, irq 98!
[ 1.472351] tun: Universal TUN/TAP device driver, 1.6
[ 1.477957] tun: (C) 1999-2004 Max Krasnyansky
[ 1.485047] CAN device driver interface
[ 1.489389] mcp251x spi1.0: setup mode 0, 8 bits/w, 2000000 Hz max --> 0
[ 1.496973] sunxi_spi_xfer()956 - [spi-1]: begin transfer, txbuf c4ee3fc0, rxbuf (null), len 1, mode 5
[ 1.507534] sunxi_spi_mode_check()873 - dual_mode_cfg = c0919b80
[ 1.514314] sunxi_spi_mode_check()917 - in single SPI mode
[ 1.520419] spi_set_bc_tc_stc()382 - tx: 1, rx: 0, stc: 1, dummy: 0
[ 1.527376] spi_set_bc_tc_stc()387 - REG BC = 0x1 --
[ 1.530404] spi_set_bc_tc_stc()393 - REG TC = 0x1 --
[ 1.530404] spi_set_bc_tc_stc()400 - REG BCC = 0x1 --
[ 1.544019] sunxi_spi_xfer()1085 - tx -> by ahb
[ 1.549152] sunxi_spi_handler()1256 - [spi-1]: irq status = 1032
[ 1.554003] sunxi_spi_handler()1261 - [spi-1]: SPI TC comes
[ 1.562142] spi_set_clk()219 - set spi clock 2000000, mclk 100000000
[ 1.569196] spi_set_clk()229 - CDR2 - n = 24
[ 1.574050] sunxi_spi_xfer()956 - [spi-1]: begin transfer, txbuf c4ee3fc0, rxbuf c4ee3f80, len 3, mode 5
[ 1.584595] sunxi_spi_mode_check()873 - dual_mode_cfg = c0919b80
[ 1.591375] sunxi_spi_mode_check()917 - in single SPI mode
[ 1.597465] spi_set_bc_tc_stc()382 - tx: 3, rx: 0, stc: 3, dummy: 0
[ 1.601363] spi_set_bc_tc_stc()387 - REG BC = 0x3 --
[ 1.601363] spi_set_bc_tc_stc()393 - REG TC = 0x3 --
[ 1.601363] spi_set_bc_tc_stc()400 - REG BCC = 0x3 --
[ 1.621061] sunxi_spi_xfer()1105 - rx and tx -> by ahb
[ 1.626880] sunxi_spi_handler()1256 - [spi-1]: irq status = 1033
[ 1.631048] sunxi_spi_handler()1261 - [spi-1]: SPI TC comes
[ 1.639863] spi_set_clk()219 - set spi clock 2000000, mclk 100000000
[ 1.646934] spi_set_clk()229 - CDR2 - n = 24
[ 1.651790] sunxi_spi_xfer()956 - [spi-1]: begin transfer, txbuf c4ee3fc0, rxbuf c4ee3f80, len 3, mode 5
[ 1.662335] sunxi_spi_mode_check()873 - dual_mode_cfg = c0919b80
[ 1.669098] sunxi_spi_mode_check()917 - in single SPI mode
[ 1.675204] spi_set_bc_tc_stc()382 - tx: 3, rx: 0, stc: 3, dummy: 0
[ 1.682161] spi_set_bc_tc_stc()387 - REG BC = 0x3 --
[ 1.685190] spi_set_bc_tc_stc()393 - REG TC = 0x3 --
[ 1.685190] spi_set_bc_tc_stc()400 - REG BCC = 0x3 --
[ 1.698800] sunxi_spi_xfer()1105 - rx and tx -> by ahb
[ 1.704635] sunxi_spi_handler()1256 - [spi-1]: irq status = 1033
[ 1.711398] sunxi_spi_handler()1261 - [spi-1]: SPI TC comes
[ 1.717618] spi_set_clk()219 - set spi clock 2000000, mclk 100000000
[ 1.724689] spi_set_clk()229 - CDR2 - n = 24
[ 1.729529] sunxi_spi_xfer()956 - [spi-1]: begin transfer, txbuf c4ee3fc0, rxbuf c4ee3f80, len 3, mode 5
[ 1.740073] sunxi_spi_mode_check()873 - dual_mode_cfg = c0919b80
[ 1.746837] sunxi_spi_mode_check()917 - in single SPI mode
[ 1.752952] spi_set_bc_tc_stc()382 - tx: 3, rx: 0, stc: 3, dummy: 0
[ 1.759908] spi_set_bc_tc_stc()387 - REG BC = 0x3 --
[ 1.762929] spi_set_bc_tc_stc()393 - REG TC = 0x3 --
[ 1.762929] spi_set_bc_tc_stc()400 - REG BCC = 0x3 --
[ 1.776549] sunxi_spi_xfer()1105 - rx and tx -> by ahb
[ 1.782384] sunxi_spi_handler()1256 - [spi-1]: irq status = 1033
[ 1.789147] sunxi_spi_handler()1261 - [spi-1]: SPI TC comes
[ 1.795367] spi_set_clk()219 - set spi clock 2000000, mclk 100000000
[ 1.795380] mcp251x spi1.0: CANSTAT 0x80 CANCTRL 0x07
[ 1.808046] spi_set_clk()229 - CDR2 - n = 24
[ 1.812902] sunxi_spi_xfer()956 - [spi-1]: begin transfer, txbuf c4ee3fc0, rxbuf c4ee3f80, len 3, mode 5
[ 1.823446] sunxi_spi_mode_check()873 - dual_mode_cfg = c0919b80
[ 1.830226] sunxi_spi_mode_check()917 - in single SPI mode
[ 1.836316] spi_set_bc_tc_stc()382 - tx: 3, rx: 0, stc: 3, dummy: 0
[ 1.840214] spi_set_bc_tc_stc()387 - REG BC = 0x3 --
[ 1.840214] spi_set_bc_tc_stc()393 - REG TC = 0x3 --
[ 1.840214] spi_set_bc_tc_stc()400 - REG BCC = 0x3 --
[ 1.859911] sunxi_spi_xfer()1105 - rx and tx -> by ahb
[ 1.865745] sunxi_spi_handler()1256 - [spi-1]: irq status = 1033
[ 1.872509] sunxi_spi_handler()1261 - [spi-1]: SPI TC comes
[ 1.878728] spi_set_clk()219 - set spi clock 2000000, mclk 100000000
[ 1.879241] mcp251x spi1.0: probed
总结:
1、spi设备驱动框架
#include
#include
#define DEVICE_NAME "sensor"
#define SENSOR_SPI_BUS 0
struct spi_device *sensor_spi=NULL;
int sensor_spi_write(void)
{
return 0;
}
int sensor_spi_read(void)
{
return 0;
}
static const struct spi_device_id sensor_spi_id[] = {
{ DEVICE_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, sensor_spi_id);
static int sensor_probe(struct spi_device *spi)
{
sensor_spi=spi;
return 0;
}
static int sensor_remove(struct spi_device *spi)
{
return 0;
}
static struct spi_driver sensor_driver = {
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
},
.probe = sensor_probe,
.remove = sensor_remove,
.id_table = sensor_spi_id,
};
static __init int sensor_spi_init(void)
{
int status=-1;
struct spi_master *master;
struct spi_device *spi;
struct spi_board_info chip =
{
.modalias = DEVICE_NAME,
.mode = 0x00,
.bus_num = 0,
.chip_select = 0,
.max_speed_hz = 2000000,
};
spi_register_driver(&sensor_driver);
if (status<0)
{
pr_err("%s: spi_register_driver spi_driver failure. status = %d\n", __func__, status);
}
pr_err("%s: spi_register_driver spi_driver success. status = %d\n", __func__, status);
master = spi_busnum_to_master(SENSOR_SPI_BUS);
if (!master)
{
status = -ENODEV;
goto error_busnum;
}
spi = spi_new_device(master, &chip);
if (!spi)
{
status = -EBUSY;
goto error_mem;
}
return status;
error_mem:
error_busnum:
spi_unregister_driver(&sensor_driver);
return status;
}
static __exit void sensor_spi_exit(void)
{
spi_unregister_driver(&sensor_driver);
if(sensor_spi!=NULL)
spi_unregister_device(sensor_spi);
}
module_init(sensor_spi_init);
module_exit(sensor_spi_exit);
MODULE_LICENSE("GPL v2");
参考:
https://blog.csdn.net/dearsq/article/details/51953610
https://blog.csdn.net/jklinux/article/details/74347820