SPI总线

SPI是motorola首先提出的全双工同步串行总线,采用主从模式,支持多slave,只支持单master,时钟由master控制.在时钟移位脉冲下,数据按位传输,高位在前,低位在后.CLK/MOSI/MISO/CS,数据可达几M.

SPI优点:全双工,操作简单,传输速率高.
缺点:多个spi设备需要占用主机较多的管脚.(每个主机都需要一根片选线).只支持单个主机.没有流控,没有应答机制.

在一个SPI时钟周期内,会完成如下操作:
1.主机通过MOSI线发送1位数据,从机通过该线读取这1位数据.
2.从机通过MISO线发送1位数据,主机通过该线读取这1位数据.这是通过移位寄存器来实现的.主机和从机各有一个移位寄存器,且二者连接成环,随着时钟脉冲,数据按照从高位到低位的方式一次移出主机寄存器和从机寄存器.当寄存器中的内容全部移出时,相当于完成了两个寄存器内容的交换.

SPI编程主要搞清的问题:模式.master的模式必须和slave的模式一致.

SPI四种工作模式,具体由CPOL(Clock Polarity时钟极性),CPHA(Clock Phase时钟相位)决定.
CPOL决定,空闲时候SCLK电平的高低(CPOL为0,空闲时SCLK电平为低).
CPHA决定采样的时钟边缘.

SPI硬件拓扑
SOC可以由多个SPI控制器,每个SPI控制器接口可以接多个SPI slave device,通过CS选择某个device.

驱动
SPI驱动,和Linux设备驱动模型一致,分master,bus,device,三个硬件层次,都对应不同的driver.
SPI驱动分spi_master_driver,spi_core,spi_device_driver.主机和设备分离.

master端…
master作为platform_device,一方面需要配置/初始化硬件,实现本地回调函数,另一方面作为硬件资源,需要提供api,供slave设备获取与调用.

以rk3288为例,SPI控制器驱动文件spi-rockchip.c
Linux kernel将SPI控制器抽象为struct spi_master.
probe中,显示申请内存资源,然后获取platform_device硬件资源,ioremap,然后开时钟等初始化master.然后指定master的本地成员及回调函数(setup,transfor,can-dma,set_cs,transfer_one,prepare_message等),然后申请rx/tx的dma资源,最后spi_register_master.
spi_master的申请和注册过程,会同步组成其总线节点下的设备.

spi总线的注册在spi.c里面.SPI.C同时实现了spi核心层的代码,为spi device的注册,消息发送等提供接口.

spi设备端
Linux kernel将spi 设备驱动抽象为struct spi_driver.将spi 从设备抽象为,struct spi_device.
以ads7846.c为例.

static struct spi_driver ads7846_driver = {
.driver = {
.name = “ads7846”;
.pm = &ads7846_pm,
.of_match_table = of_match-ptr(ads7846_dt_ids);
},
.probe = ads7846_probe,
.remove = ads7846_remove,
};
module_spi_driver(ads7846_driver)
module_spi_driver()里面同时封装了spi_register_drive和spi_unregister_driver.
也就是说这个最后也会跑到经典模型的bus_match,然后比较设备节点的compatible和spi_driver的of_match_table的字段,如果match ok,会调用到本驱动的probe.
在probe中,先是对spi_device spi,调用master的setup,对maste初始化(注意,struct spi_device中含有struct spi_master结构变量.),并选中本device的CS,然后为本spi-device申请中断等.

然后在合适的时机构建struct spi_message.并调用spi中的api:spi_sync()通过master->transfer()收发送数据.实现master与spi的数据通信,并将数据返回给device driver.driver接受到数据后解析之,再传给TP/disk等设备.

spi数据的传输事务,Linux driver将其抽象为struct spi_transfer.SPI是全双工,spi_transfer中含有 tx/RX双缓冲区.
消息message中传输事务的transfer是以链表形式组织在一起,Linux提供了一套api
static inline void spi_message_init(struct spi_message *m)
spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)
spi_transfer_del(struct spi_transfer *t)
spi_sync(struct spi_device *spi, struct spi_message *message);

在应用层,用户也科通通过ioctl,通过构建struct spi_ioc_transfer来对spi 设备进行读写.
master->transfer()其实现,也是将transfer挂载workqueue中,通过kthread_worker和kthread_work,通过创建内核线程来实现kthread_work的func.
最终也是调用master的spi_transfer_one_message等方法收发数据.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九月天-深圳专业软硬件开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值