这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 开源硬件 » 【从0教学嵌入式Linux】第二十五集

共1条 1/1 1 跳转至

【从0教学嵌入式Linux】第二十五集

助工
2016-06-21 10:40:46     打赏

第25课:SPI驱动程序开发

(一)SPI子系统驱动

一、概述

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

二、SPI总线协议简介

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

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

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

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

三、LinuxSPI驱动开发

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

我们以上面这个图为思路

1.Platform bus

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

2.Platform_device

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

3.Platform_driver

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

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模式和时钟设置用到的函数、数据传输用到的函数等。

4.Spi bus

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

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

5.spi_devic

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

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

6.spi_driver(参考)

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

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的读过程如下图

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

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,例如:

并在板文件的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

(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

例如:

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



共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]