IMX6之SPI接口驱动测试


本文主要验证Linux-imx_share\Documentation\spi目录下spidev_test.c的测试例程,能否正常控制SPI接口。

一.开发环境分析

虚拟机导入的Ubuntu内核版本


ARM内核版本:


ARM的CPU处理器:freescale的i.mx6系列的处理器,型号为MCIMX6U7CVM08AC ,ARM双核A9。

官网上查到对应的数据手册为《i.MX 6Solo/6DualLite Applications Processor Reference Manual》。


根据数据手册,第8章8.5.4.3.1节,P421,表8-23表示,该i.mx6dl的处理器只有4个SPI接口。


检查杭州迈冲科技发货的底板,没有SPI接口引出来,该底板唯一引出的ECSPI5接口只有四核的处理器可以用,不适合该处理器。


二.驱动配置

1.修改设备树

找到内核源码的linux-imx_share\arch\arm\boot\dts目录下的imx6qdl-sabresd.dtsi,找到ecspi1的代码


将spidev这段注释去掉,开启这段代码。


2.修改内核配置

输入:make ARCH=arm menuconfig进行内核配置,进入配置界面,依次选择Device Drivers->SPI support,使User mode SPI device driver support选项起作用,选择Y,并save。


选择这个的目的是使spidev.c参与编译,原因可以参考linux-imx_share\drivers\spi目录下的Kconfig和Makefile。



配置好之后,运行./build.sh,编译生成zImage,zImage-imx6dl-sabresd-emmc.dtb烧写进板子。

检查新烧进去的系统里,dev目录下有无spidev32766.0。如有,表示spidev的设备驱动烧写成功。



三.测试

1.找到ECSPI的引脚,连接MISO和MOSI,进行自回环测试。




2.编写makefile生成自测代码spidev_test.c对应的可执行程序。



 使用rz命令,将spidev_test上载至板子


接收的数据正确,自回环测试成功。

------------------------------------------------------------------------------------------------------------------------------------

疑问:生成的设备节点为什么是spidev32766.0?


在spidev.c中的函数spidev_probe里,找到设备节点的赋值。

  1. spidev->devt = MKDEV(SPIDEV_MAJOR, minor);  //计算出设备号  
  2. //创建设备/dev/spidev%d.%d(spidev总线号.片选号)  
  3. dev = device_create(spidev_class, &spi->dev, spidev->devt,  
  4.             spidev, "spidev%d.%d",  
  5.             spi->master->bus_num, spi->chip_select);  
spidev->devt = MKDEV(SPIDEV_MAJOR, minor);  //计算出设备号
//创建设备/dev/spidev%d.%d(spidev总线号.片选号)
dev = device_create(spidev_class, &spi->dev, spidev->devt,
			spidev, "spidev%d.%d",
			spi->master->bus_num, spi->chip_select);

下面看下spi->master->bus_num和spi->chip_select的值。


在drivers/spi目录下的spi.c文件中,spi_alloc_master函数中,给master->bus_num = -1进行了初始化。

  1. struct spi_master *spi_alloc_master(struct device *dev, unsigned size)  
  2. {  
  3.     struct spi_master   *master;  
  4.   
  5.     if (!dev)  
  6.         return NULL;  
  7.   
  8.     master = kzalloc(size + sizeof(*master), GFP_KERNEL);  
  9.     if (!master)  
  10.         return NULL;  
  11.   
  12.     device_initialize(&master->dev);  
  13.     <span style="color:#3333ff;">master->bus_num = -1;  //初始化  
  14.     <span style="color:#3333ff;">master->num_chipselect = 1;  
  15.     master->dev.class = &spi_master_class;  
  16.     master->dev.parent = get_device(dev);  
  17.     spi_master_set_devdata(master, &master[1]);  
  18.   
  19.     return master;  
  20. }  
struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
{
	struct spi_master	*master;

	if (!dev)
		return NULL;

	master = kzalloc(size + sizeof(*master), GFP_KERNEL);
	if (!master)
		return NULL;

	device_initialize(&master->dev);
	<span style="color:#3333ff;">master->bus_num = -1;  //初始化
	<span style="color:#3333ff;">master->num_chipselect = 1;
	master->dev.class = &spi_master_class;
	master->dev.parent = get_device(dev);
	spi_master_set_devdata(master, &master[1]);

	return master;
}

在spi_register_master函数中,对bus_num进行了处理

  1. /* convention:  dynamically assigned bus IDs count down from the max */  
  2.     if (master->bus_num < 0) <span style="font-family: Arial, Helvetica, sans-serif;">{</span>  
/* convention:  dynamically assigned bus IDs count down from the max */
	if (master->bus_num < 0) <span style="font-family: Arial, Helvetica, sans-serif;">{</span>
  1. /* FIXME switch to an IDR based scheme, something like 
  2.  * I2C now uses, so we can't run out of "dynamic" IDs 
  3.  */  
  4. master->bus_num = atomic_dec_return(&dyn_bus_id);  
  5. dynamic = 1;  
		/* FIXME switch to an IDR based scheme, something like
		 * I2C now uses, so we can't run out of "dynamic" IDs
		 */
		master->bus_num = atomic_dec_return(&dyn_bus_id);
		dynamic = 1;
	}


其中dyn_bus_id计算结果是32767

  1. static atomic_t     dyn_bus_id = ATOMIC_INIT((1<<15) - 1);  
static atomic_t		dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
  1. #define atomic_dec_return(v)    (atomic_sub_return(1, v))  
#define atomic_dec_return(v)    (atomic_sub_return(1, v))
  1. static inline int atomic_sub_return(int i, atomic_t *v)  
  2. {  
  3.     unsigned long flags;  
  4.     int val;  
  5.   
  6.     raw_local_irq_save(flags);  
  7.     val = v->counter;  
  8.     v->counter = val -= i;  
  9.     raw_local_irq_restore(flags);  
  10.   
  11.     return val;  
  12. }  
static inline int atomic_sub_return(int i, atomic_t *v)
{
	unsigned long flags;
	int val;

	raw_local_irq_save(flags);
	val = v->counter;
	v->counter = val -= i;
	raw_local_irq_restore(flags);

	return val;
}

如此计算出master->bus_num=32766。

of_register_spi_devices函数里chip_select的获得是通过value赋值的,而value是通过设备树里的reg后面的值取得的

  1. /* Device address */  
  2.         rc = of_property_read_u32(nc, "reg", &value);  
  3.         if (rc) {  
  4.             dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n",  
  5.                 nc->full_name, rc);  
  6.             spi_dev_put(spi);  
  7.             continue;  
  8.         }  
  9.         spi->chip_select = value;  
/* Device address */
		rc = of_property_read_u32(nc, "reg", &value);
		if (rc) {
			dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n",
				nc->full_name, rc);
			spi_dev_put(spi);
			continue;
		}
		spi->chip_select = value;
  1. spidev: spidev@0 {  
  2.         spi-max-frequency = <24000000>;    
  3.         reg = <0>;    
  4.         compatible = "rohm,dh2228fv";         
  5.     };  
spidev: spidev@0 {
		spi-max-frequency = <24000000>;  
		reg = <0>;  
		compatible = "rohm,dh2228fv"; 		
	};

所以生成的设备节点号是spidev32766.0。


如果在imx6qdl-sabresd.dtsi设备树里,改成下面这样,则生成的设备节点号是spidev32766.1。

  1. &ecspi1 {  
  2.     fsl,spi-num-chipselects = <2>; //改成2  
  3.     cs-gpios = <&gpio2 30 0>;  
  4.     pinctrl-names = "default";  
  5.     pinctrl-0 = <&pinctrl_ecspi1_1>;  
  6.     status = "okay";  
  7.   
  8.     flash: m25p32@0 {  
  9.         #address-cells = <1>;  
  10.         #size-cells = <1>;  
  11.         compatible = "winbond,w25q32";  
  12.         spi-max-frequency = <20000000>;  
  13.         reg = <0>;  
  14.     };  
  15.   
  16.     spidev: spidev@1 {  
  17.         spi-max-frequency = <24000000>;    
  18.         reg = <1>;    
  19.         compatible = "rohm,dh2228fv";         
  20.     };  
  21.   
  22. };  


  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值