




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、spi slave 及 master 接口驱动及传输时序spi slave 驱动spi slave驱动在kernel中可以主要参考spidev.c,这是一个字符驱动,可以匹 配kernel中的多个名称为“spideV的spi设备,分析这个文件,主要有以下几个重点:1. 如何编写多设备公用驱动2. 如何封装读写请求到 spi 框架层3. spi message请求如何分发至U master自spi_boardnfo或者spi master注册后,两者就已经完成了匹配的工作, spi slave驱动不关心任何匹配的细节,它只需要完成与spi slave的匹配,就可以通过slave进而找到maste
2、r。这里是通过spi_register_driver(&spidev_spi_driver);注册进kernel,而后spi框架进行name match,再调用probe,完成关于设备的一 些成员初始化操作。下面针对上面的三个问题,进行分析这个驱动,spi 设备全局链及保护信号量:static LIST_HEAD(device_list);static DEFINE_MUTEX(device_list_lock);相对与设备的驱动数据:struct spidev_data dev_t devt;/ 设备号spinlock_t spi_lock;/spi 结构体的 pin 锁struct spi
3、_device *spi;struct list_head device_entry;/ 挂接到 device_liststruct mutex buf_lock;/ 保护数据的 lockunsignedusers;/ 使用者u8*buffer;/ 实际数据区,由 open 时进行动态分配, release 时释放;spi 中任何会由多个使用者访问的区域,都需要使用锁保护,如这里的 users,个人觉得需要使用原子变量而不应该简单的使用整形。在probe的时候,首先分配spidev_data并初始化其 spi/device_entry/buf_lock/spi_lock ,查找一个可用的 bi
4、t 用作次设备号,创建设备spidev busnum.cs挂到全局链中,并将私有数据 spidev_data 放至U dev-p-driver_data 中。open时,从in ode中获取dev_t,然后对比整个链,找到目标数据 spidev_data,放到 file-private_data 中,并分配缓存读写时,直接从file中获取对应的spidev_data数据,然后通过spi device来 传递 spi 请求。以上主要是数据如何传递的问题。SPI读写请求的圭寸装很简单,如下:static inline ssize_t spidev_sync_write(struct spidev_
5、data *spidev, size_t len) struct spi_transfer t = .tx_buf= spidev-buffer,.len= len,;struct spi_message m;spi_message_init(&m);spi_message_add_tail(&t, &m);return spidev_sync(spidev, &m);static inline ssize_t spidev_sync_read(struct spidev_data *spidev, size_t len)struct spi_transfer t = .rx_buf= spi
6、dev-buffer,.len= len,;struct spi_message m;spi_message_init(&m);spi_message_add_tail(&t, &m);retur n spidev_s yn c(spidev, &m);封装的同步函数:static ssize_t spidev_sync(struct spidev_data *spidev, struct spi_message *message)DECLARE_COMPLETION_ONSTACK(done);int status;message-context =spin_lock_irq(&spidev
7、-spi_lock);if (spidev-spi = NULL)status = -ESHUTDOWN;elsestatus = spi_async(spidev-spi, message);spin_unlock_irq(&spidev-spi_lock);if (status = 0) status = message-status;if (status = 0)status = message-actual_length;return status;只需要调用 spi_async就可以 完成数据读取 / 写入的操作。这个函数在内部真正做了什么?如何分发 / 回调?我们走一遍代码:首先
8、master 内部有两个锁:spinlock_t bus_lock_spiniock;【用于异步】spi_asyncstruct mutex bus_lock_mutex;【用于同步】spi_sync对于不同的场景,需要对 master进行不同类型的加锁,异步:spin_lock_irqsave(&master-bus_lock_spinlock, flags);ret = _spi_async(spi, message);message-spi = spi; message-status = -EINPROGRESS;return master-transfer(spi, message);
9、spin_unlock_irqrestore(&master-bus_lock_spinlock, flags);同步:message-context =if (!bus_locked)mutex_lock(&master-bus_lock_mutex);status = spi_async_locked(spi, message);if (!bus_locked)mutex_unlock(&master-bus_lock_mutex);if (status = 0) status = message-status这里即在kernel内部完成了同步的工作,不需要 像 spidev 那样需要自己
10、等待完成量,使用的是 bus_lock_mutex内部与异步的调用方式一致:spin_lock_irqsave(&master-bus_lock_spinlock, flags);ret = _spi_async(spi, message);spin_unlock_irqrestore(&master-bus_lock_spinlock, flags);从这里可以看出,同步与异步没有本质差别,只是多了一个完成量的操作 而已。最终调用的函数为:master-transfer(spi, message);这个函数将在spi master中分析。在spi slave侧需要熟悉传输的参数的每个域的功能
11、,才能很好的完成工作struct spi_transfer const void *tx_buf;/ 非 dma 发送地址void *rx_buf;/ 非 dma 读取地址unsigned len;/tx/rx bufffer sizedma_addr_t tx_dma;/ 若spi_message.is_dma_mappec置位,为 transfer 的 dma addressdma_addr_t rx_dma;/ 若spi_message.is_dma_mappec置位,为 read 的 dma addressunsignedcs_change:1;传输完成后,修改 cs信号u8bits_
12、per_word;/ 长度,优先覆盖 spi_board_info 的设置(32)u16delay_usecs;传输后继续传输或者cs结束传输的中间时隙u32speed_hz;本次传输的速度,可以优先覆盖spi_boardnfo里的设置struct list_head transfer_list; 挂接至U spi_message上的连接体;struct spi_message struct list_head transfers;/transfer 链struct spi_device *spi;/ 对应的 spi 设备unsignedis_dma_mapped:1;是否启动 dma 功能v
13、oid *context;/ 回调参数unsigned actual_length;/ 传输的真正长度int status;/0 ,成功struct list_head que;/driver 使用void *state;每个域的使用方法,这里直接看起来并不明确,必须结合 master 的驱动spi master 驱动SPI 设备资源:static struct resource s3c_spi0_resource = 0 = DEFINE_RES_MEM(S3C24XX_PA_SPI, SZ_32),1 = DEFINE_RES_IRQ(IRQ_SPI0),;struct platform_
14、device s3c_device_spi0 = .name= s3c2410-spi,.id= 0,.num_resources= ARRAY_SIZE(s3c_spi0_resource),.resource= s3c_spi0_resource,.dev= .dma_mask= &samsung_device_dma_mask, .coherent_dma_mask= DMA_BIT_MASK (32),;static struct resource s3c_spi1_resource = 0 = DEFINE_RES_MEM(S3C24XX_PA_SPI1, SZ_32),1 = DE
15、FINE_RES_IRQ(IRQ_SPI1),;struct platform_device s3c_device_spi1 = .name= s3c2410-spi,.id= 1,.num_resources= ARRAY_SIZE(s3c_spi1_resource),.resource= s3c_spi1_resource,.dev= .dma_mask= &samsung_device_dma_mask,.coherent_dma_mask= DMA_BIT_MASK(32),;在此之间,走过了一些弯路学了 verilog/modelsim ,在之前一直不明白的事 情在逐渐的尝试中获得
16、了新的认识,硬件的 ip core 的工作是由 clock 来驱动的,而不是软件意义上的过程,在 同步时钟的上升 / 下降沿中进行数据处理,移位等在 SPI 的 ip core 设计中,主要有三个模块:1. clock generate2. data shift3. register control首先通过 AP 过来的系统时钟及设备能够支持的最大时钟频率,计算出对应 的最接近的分频系数,而模块 1 就是根据这个分频系数来通过系统的源clock产生对应的目标clock【因为对于SPI IF不需要独立 的精确的晶振】生成了与slave同步的clock之后,输出到模块2,模块2负责具体的发送 数据
17、功能。具体的采数发数时序见第三节。而 register control 则负责所有的可配置接口,如:分频系数,支持位宽,FIFO深度,支持的片选数,以及相应的MSB/LSB设置选项在 SPI 的协议中,最大的误区在于 master 与 slave 之间的私有协议:SPI master的本生设计中并不支持具体的传输协议,而是简单的提供了一个 传输数据的通路,而协议则是由实现的slave端,以及slave端驱动来决定的。下面来总结这个数据发送与接收的具体过程:读指定地址:read(addr, &value, len);1. 配置相关读取操作的寄存器2. slave驱动圭寸装协议 CMD【描述bas
18、e + addr + len + flagS3. 拉下slave对应在master上的cs【低电平有效】4发送指定位宽cmd到slave端【由master来驱动,而slave只需要发送数 据到对应 fifo 并启动发送即可】5. slave端接收到指定的cmd,在MISO线上回应对应的数据6. slave驱动从master的fifo中等待数据,当 master读取到对应的线上数 据,并放于FIFO中7. 读取到数据,拉高 CS/*make sure len is word units*/int gps_spi_read_bytes_test3( u32 len,u32 addr,u32 *da
19、ta, bool sys, u32base)u32 read_cmd2;local_spi_init();read_cmd0 = SPI_READ_CMD(len,addr 2 + base);spi_assert_function(0);local_spi_write(u8*)read_cmd, 4);local_spi_read(u8 *)data, 4);spi_assert_function(1);return 0; 写指定地址:write(addr, &value, len);int gps_spi_write_bytes_test2( u32 len,u32 addr,u32 da
20、ta) u32 write_cmd2,one_read;local_spi_init();write_cmd0 = SPI_WRITE_SYS_CMD(len*1,addr 2);write_cmd1 = data;spi_assert_function(0);local_spi_write(u8 *)write_cmd, 8);spi_assert_function(1);return 0; 一些读写的实现细节:int local_spi_read(u8 *buf, u32 size)/*wait for data*/while (reg-sts2 & (0x1 READ_TIME_OUT)goto read_exit;*p = (u32)reg-txd;p+;/*if tx fifo is not full*/while (reg-sts2 & (0x1 6);writel(*p, SPRD_SPI1_BASE);p+;/*bitlen is 4*/以上为 master 驱动需要实现传输的一些流程spi 传输时序问题主要关注两个参数:CPOL:Clock 初始电平( 0:低电平, 1:高电平)CPHA:采样位置( 0:第一个跳变边沿, 1:第二个跳变边沿):上升沿采样,下
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 合成气梭菌发酵乙醇的机制、现状与前景探析
- 合作学习赋能:普通高中英语词汇教学的创新与实践
- 教师招聘之《小学教师招聘》综合提升测试卷带答案详解(培优b卷)
- 2025年教师招聘之《幼儿教师招聘》题库综合试卷附参考答案详解(考试直接用)
- 2025年教师招聘之《幼儿教师招聘》测试卷附参考答案详解【预热题】
- 2025年公务员时事政治试题库附参考答案详解(培优a卷)
- 教师招聘之《小学教师招聘》通关模拟卷附参考答案详解(典型题)
- 教师招聘之《小学教师招聘》考前冲刺练习题库提供答案解析【历年真题】附答案详解
- 2025年教师招聘之《小学教师招聘》考试题库附参考答案详解【考试直接用】
- 2025内蒙古呼伦贝尔东北阜丰生物科技有限公司招聘8人笔试备考及完整答案详解一套
- 二年级语文上册《有趣的动物》课件PPT
- 不干胶贴标机设计学士学位论文
- 《劳动合同书》-河南省人力资源和社会保障厅劳动关系处监制(2016.11.15)
- 钢轨检测报告
- 战略管理:概念与案例
- GB/T 3505-2009产品几何技术规范(GPS)表面结构轮廓法术语、定义及表面结构参数
- GB/T 11186.1-1989涂膜颜色的测量方法第一部分:原理
- 09S304 卫生设备安装图集
- 功能材料概论-课件
- 微纳加工课件
- 危重病人紧急气道管理课件
评论
0/150
提交评论