在线咨询
eetop公众号 创芯大讲堂 创芯人才网
切换到宽版

EETOP 创芯网论坛 (原名:电子顶级开发网)

手机号码,快捷登录

手机号码,快捷登录

找回密码

  登录   注册  

快捷导航
搜帖子
芯片精品文章合集(500篇!)    创芯人才网--重磅上线啦!
查看: 2217|回复: 1

[原创] 【从0教学嵌入式Linux】第二十五集

[复制链接]
发表于 2016-6-21 14:49:14 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x

第25课:SPI驱动程序开发

图片100.jpg

(一)SPI子系统驱动

一、概述

基于子系统去开发驱动程序已经是Linux内核中普遍的做法了。前面写过基于I2C
子系统的驱动开发。本文介绍另一种常用总线。SPI子系统的开发和I2C有很多相似性,大家可以对比学习。

二、SPI总线协议简介

介绍驱动开发前,需要先熟悉下SPI通讯协议中的几个关键的地方,后面再编写驱动时,需要考虑相关因素。

SPI总线由MISO(串行数据输入)、MOSI(串行数据输出)、SCK(串行移位时钟)、CS(使能信号)4个信号线组成。

SPI常用四种数据传输模式的主要差别在于:输出串行同步时钟极性(CPOL)和相位(CPHA)可以进行配置。如果CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。如果CPHA=0,在串行同步时钟的前沿(上升或下降)数据被采样;如果CPHA=1,在串行时钟的后沿(上升或下降)数据被采样。

图片1.jpg

图片2.jpg

这四种模式中究竟选择哪种模式取决于设备。

三、LinuxSPI驱动开发

首先明确SPI驱动层次,如下图:

图片3.jpg

我们以上面这个图为思路

1.Platform bus

Platform bus对应的结构是platform_bus_type,这个内核是开始就定义好的。

2.Platform_device

SPI控制器对应platform_device的定义方式,参看arch/arm/plat-samsung/dev-spi.c文件

图片4.jpg

3.Platform_driver

再来看platform_driver,参看drivers/spi/spi_s3c.c文件

图片5.jpg

Platform_driver_probe(&s3c_spi_driver,s3c_spi_probe);注册driver

然后根据传入的platform_device参数,构建一个用于描述SPI控制器的结构体spi_master并注册。Spi_register_master(master)。后续注册的spi_device需要选定自己的spi_master,并利用spi_master提供的传输功能传输spi数据。

I2C类似,SPI也有一个描述控制器的对象叫spi_master,其主要成员是主机控制器的序号(系统中可能存在多个SPI主机控制器)、片选数量、SPI模式和时钟设置用到的函数、数据传输用到的函数等。

图片6.jpg

4.Spi bus

SPI总线对应的总线类型为spi_bus_type,在内核的drivers/spi/spi.c中定义

图片7.jpg

对应的匹配规则是(高版本的匹配规则会稍有变化,引入了id_table,可以匹配多个spi设备名称

图片8.jpg

5.spi_devic

下面讲spi_device的构建与注册。Spi_device对应的含义是挂载在spi总线上的一个设备,所以描述它的时候应该明确它自身的设备特性、传输要求、及挂接在哪个总线上。

图片9.jpg

spi_register_board_infos3c_spi_devs,ARRAY_SIZE(s3c_spi_devs);//注册spi_board_info。这个代码会把spi_board_info注册到链表board_list上。

事实上上文提到的spi_master的注册会在spi_register_board_info之后,spi_master注册的过程中会调用scan_board_info扫描board_list,找到挂接在它上面的spi设备,然后创建并注册spi_device

图片10.jpg

6.spi_driver(参考)

本文先以Linux内核中的/driver/mtd/devices/m25p80.c驱动为参考。

图片11.jpg

Spi_register_driver(&m25p80_driver);   //spi driver 的注册

在有匹配的spi driver时,会调用m25p_probe

Static int_devinit m25p_probestruct spi_device *spi

{

........

}

根据传入的spi_device参数,可以找到对应的spi_master,接下来就可以利用spi子系统为我们完成数据交互了,可以参看m25p80_read函数,要完成传输先理解下面几个给够的含义(这两个结构的定义及详细注释参见include/linux/spi/spi.h

Spi_message:描述一次完整的传输,即cs信号从高->->高的传输

Spi_transfer:多个api_transfer构成一个spi_message

举例说明:m25p80的读过程如下图

图片12.jpg

可以分解为两个spi_transfer,一个是写命令,另一个是读数据具体实现参见m25p80.c中的m25p80_read函数,下面内容摘取之此函数

图片13.jpg

Spi_sync为同步方式发送,还可以用spi_async异步方式,需要设置回调完成函数。

另外也可以选择一些封装好的更容易使用的函数,这些函数可以在include/linux/spi/spi.h文件中找到,如:

extern int spi_write_then_read(struct spi_device *spi,

const u8 *txbuf,unsigned n_tx,

u8 *rxbuf,unsigned n_rx);

(二)编写SPI驱动概述(参考)

本文不具体分析Linux内核中SPI总线的架构,只针对这种架构阐述如何进行SPI设备驱动的编写。简而言之,SPI驱动的编写分为两个部分:

第一:spi_device的构建和注册

第二:spi_driver的构建和注册

1.spi_device的构建并注册

首先在板文件中添加spi_board_info,例如:

图片14.jpg

并在板文件的init函数中调用spi_register_board_infos3c_spi_devsARRAY_SIZEs3c_spi_devs));这个函数会把spi_board_info注册到链表board_list上,spi_device封装了一个spi_master结构体,事实上spi_master的注册会在spi_register_board_info之后,spi_master注册的过程中会调用scan_boardinfo扫描board_list,找到挂接在它上面的spi设备然后创建并注册spi_device

2.Spi_driver的构建与注册分为三步:

(1)构建spi_driver

图片15.jpg

(2)Spi_driver的注册

Spi_register_driver&m25p80_driver); 当匹配了spi_device以后调用probe

(3)实现probe操作

Spi_transfer(里面集成了数据buf空间地址等信息)

Spi_message(是spi_transfer的集合)的构建:spi_message_init(初始化spi_message)、spi_message_add_tail(将新的spi_transfer添加到spi_message队列尾部)

Spi_sync函数的调用(调用spi_master发送spi_message

例如:

图片16.jpg

这样就基本完成了SPI设备的驱动编写,读写具体操作要根据芯片的时序来确定,具体如何利用SPI传数据那么就要看自己程序的逻辑。

发表于 2016-6-24 04:29:03 | 显示全部楼层
经典经典!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

站长推荐 上一条 /1 下一条

小黑屋| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-6-4 21:30 , Processed in 0.025211 second(s), 10 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
快速回复 返回顶部 返回列表