SPI驱动学习七(SPI_Slave_Mode驱动程序框架)

目录

  • 一、SPI_Slave_Mode驱动程序框架
    • 1. Master和Slave模式差别
      • 1.1 主设备 (Master)
      • 1.2 从设备 (Slave)
      • 1.3 示例
    • 2. SPI传输概述
      • 2.1 数据组织方式
      • 2.2 SPI控制器数据结构
    • 3. SPI Slave Mode数据传输过程
    • 4. 如何编写程序
      • 4.1 设备树
      • 4.2 内核相关
      • 4.3 简单的示例代码
        • 4.3.1 master和slave驱动示例
        • 4.3.2 master和slave使用示例
  • 二、SPI_Slave_Mode驱动程序源码解读(drivers/spi/spi-imx.c)
    • 1. 设备树
    • 2. 控制器驱动程序
      • 2.1 分配一个spi_controller
      • 2.2 设置spi_controller
      • 2.3 注册spi_controller
      • 2.4 硬件操作
    • 3. 设备驱动程序
      • 3.1 Master模式
      • 3.2 Slave模式

一、SPI_Slave_Mode驱动程序框架

  • 参考内核源码: Linux-5.x\drivers\spi\spi-imx.c
  • 注意:Linux 4.9的内核未支持SPI Slave Mode
  • 参考文档:《Linux_as_an_SPI_Slave_Handouts.pdf》

1. Master和Slave模式差别

  SPI(串行外设接口,Serial Peripheral Interface)是一种常用的同步串行通信协议,用于微控制器与各种外设(如传感器、存储器、显示器等)之间的通信。在 SPI 通信中,通常有两个角色:主设备(Master)和从设备(Slave)。这两者之间的区别如下:

1.1 主设备 (Master)

  • 定义:主设备负责控制 SPI 通信,生成时钟信号,并管理从设备的选择。

  • 功能

    • 时钟产生:主设备生成 SPI 时钟信号(SCK),并控制数据传输的速率。
    • 选择从设备:通过选择线(如 Chip Select,CS)选择与其通信的特定从设备。通常在传输数据前,主设备会将 CS 线拉低以使对应的从设备准备接收数据。
    • 数据发送和接收:主设备负责读取从设备发送的数据,并向从设备发送命令和数据。
  • 例子:微控制器通常充当主设备,与多个传感器或存储器从设备通信。

1.2 从设备 (Slave)

  • 定义:从设备被动地响应主设备的命令。它不会主动启动通信,而是等待主设备进行操作。

  • 功能

    • 响应主设备:从设备在主设备的指令下工作,并在主设备发送时钟信号时提供数据。
    • 数据接收和发送:从设备接收来自主设备的数据,并将其处理后,发送响应或数据回主设备。
  • 例子:传感器、EEPROM、LCD 显示屏等通常作为从设备,实现数据的接收和响应。

1.3 示例

以IMX6ULL为例,Master和Slave模式的异同如下图:

  • 初始化

    • 使用的SPI寄存器有所不同
    • 引脚有所不同:Master模式下SS、CLK引脚是输出引脚,Slave模式下这些引脚是输入引脚
  • 准备数据:都需要准备好要发送的数据,填充TX FIFO

  • 发起传输:Master模式下要主动发起传输,等待发送完成(等待中断)

  • 使能接收中断:Slave模式下无法主动发起传输,只能被动地等待,使能接收中断即可

  • 中断函数里:读取RXFIFO得到数据

  • 传输完成

  • 在这里插入图片描述

2. SPI传输概述

2.1 数据组织方式

  使用SPI传输时,最小的传输单位是"spi_transfer",对于一个设备,可以发起多个spi_transfer,这些spi_transfer,会放入一个spi_message里。
在这里插入图片描述
所以,反过来,SPI传输的流程是这样的:

  • 从spi_master的队列里取出每一个spi_message
    • 从spi_message的队列里取出一个spi_transfer
      • 处理spi_transfer

2.2 SPI控制器数据结构

  参考内核文件:include\linux\spi\spi.h,Linux中SPI控制器struct spi_controller,有两套传输方法:
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/a3c374792e144463b6bb6113c558bbde.png

3. SPI Slave Mode数据传输过程

在这里插入图片描述

4. 如何编写程序

4.1 设备树

  • SPI控制器设备树节点中,需要添加一个空属性:spi-slave
  • 要模拟哪类slave设备?需要添加slave子节点,这是用来指定slave protocol
    在这里插入图片描述

4.2 内核相关

  • 新配置项:CONFIG_SPI_SLAVE

  • 设备树的解析:增加对spi-slaveslave子节点的解析

  • sysfs:新增加/sys/devices/.../CTLR/slave,对应SPI Slave handlers

  • 新API

    • spi_alloc_slave( )
    • spi_slave_abort( )
    • spi_controller_is_slave( )
  • 硬件设置不一样

    • master:SS、SCLK引脚是输出引脚
    • slave:SS、SCLK引脚是输入引脚
  • 传输时等待函数不一样

    • master:master主动发起spi传输,它可以指定超时时间,使用函数wait_for_completion_timeout() 进行等待
    • slave:slave只能被动等待传输,它无需指定超时时间,使用函数wait_for_completion_interruptible()进行等待 ,使用.slave_abort() 来取消等待

4.3 简单的示例代码

4.3.1 master和slave驱动示例

在这里插入图片描述

4.3.2 master和slave使用示例

  对于设置为spi master模式的spi控制器,下面接的是一个一个spi slave设备,我们编写各类spi slave driver,通过spi master的函数读写spi slave 设备。

  对于设置为spi slave模式的spi控制器,它是作为一个spi slave设备被其他单板的spi master设备来访问,它如何接收数据、如何提供数据?我们编写对应的spi slave handler。

  对于master和slave,有两个重要概念:

  • SPI Slave Driver:通过SPI Master控制器跟SPI Slave设备通信
  • SPI Slave Handler:通过SPI Slave控制器监听远端的SPI Master
    在这里插入图片描述

二、SPI_Slave_Mode驱动程序源码解读(drivers/spi/spi-imx.c)

1. 设备树

下图是摘自《Linux_as_an_SPI_Slave_Handouts.pdf》:
在这里插入图片描述

2. 控制器驱动程序

  在Linux 5.x版本中,SPI控制器的驱动程序仍然使用原理的名字:struct spi_master,但是它已经是一个宏:

#define spi_master			spi_controller

  这意味着它可以工作于master模式,也可以工作于slave模式。

2.1 分配一个spi_controller

在这里插入图片描述

2.2 设置spi_controller

  工作于slave模式时,跟master模式最大的差别就是如下函数不一样:

  • bitbang.txrx_bufs函数不一样
    • 在IMX6ULL中,这个函数为spi_imx_transfer,里面对master、slave模式分开处理
    • master模式:使用spi_imx_pio_transfer函数
    • slave模式:使用spi_imx_pio_transfer_slave函数
  • 增加了bitbang.master->slave_abort函数
    在这里插入图片描述
      不同厂家的SOC的SPI 驱动实现会有所不同,有的就不会用到bitbang;spi_bitbang 结构体定义了一种软件模拟SPI通信的方式,通过软件控制GPIO引脚来实现SPI通信所需的时序和信号。这种方法通常用于那些没有内置SPI硬件控制器的微控制器或系统上。

2.3 注册spi_controller

  无论是master模式,还是slave模式,注册函数时一样的:
在这里插入图片描述
  在spi_bitbang_start内部,会处理设备树中的子节点,创建并注册spi_device:

spi_bitbang_startspi_register_masterspi_register_controllerof_register_spi_devices

  对于master模式,设备树中的子节点对应真实的spi设备;但是对于slave模式,这些子节点只是用来选择对应的spi slave handler:就是使用哪个驱动来模拟spi slave设备,比如:
在这里插入图片描述

/* drivers/spi/spi-slave-time.c* SPI从机处理器,接收上一条SPI消息后报告系统运行时间** 该SPI从机处理器以二进制格式和网络字节顺序发送上一条SPI消息接收时间* 的两个32位无符号整数,分别表示自系统启动以来的秒数和小数秒数(以微秒为单位)。** 版权所有 (C) 2016-2017 Glider bvba** 本文件受 GNU 通用公共许可证条款和条件的约束。请参阅此存档主目录中的 "COPYING" 文件以获取更多详细信息。** 使用方法(假设 /dev/spidev2.0 对应远程系统上的 SPI 主设备):**   # spidev_test -D /dev/spidev2.0 -p dummy-8B*   spi 模式: 0x0*   每字的位数: 8*   最大速度: 500000 Hz (500 KHz)*   RX | 00 00 04 6d 00 09 5b bb ...*		^^^^^    ^^^^^^^^*		秒数    微秒数*/#include <linux/completion.h>
#include <linux/module.h>
#include <linux/sched/clock.h>
#include <linux/spi/spi.h>struct spi_slave_time_priv {struct spi_device *spi;struct completion finished;struct spi_transfer xfer;struct spi_message msg;__be32 buf[2];
};static int spi_slave_time_submit(struct spi_slave_time_priv *priv);/*** @brief SPI从机时间补偿函数* * 当SPI从机传输完成或者发生错误时,此函数被调用以处理相应的后续操作。主要功能包括检查上一次传输状态,* 并根据状态决定是否继续提交时间补偿处理或者终止并通知上层。* * @param arg 传递给此函数的参数,实际类型为struct spi_slave_time_priv*,用于访问SPI从机时间补偿相关的数据。*/
static void spi_slave_time_complete(void *arg)
{// 将参数转换为相应的结构体指针,以便访问私有数据struct spi_slave_time_priv *priv = arg;// 存储操作结果的变量int ret;// 检查上一次SPI从机消息的状态,如果存在错误,则不继续操作ret = priv->msg.status;if (ret)goto terminate;// 尝试提交下一次时间补偿处理,如果提交失败,则跳转到terminate块ret = spi_slave_time_submit(priv);if (ret)goto terminate;// 如果没有错误,正常返回return;terminate:// 当出现错误或者传输完成时,记录日志并通知上层处理已经完成dev_info(&priv->spi->dev, "Terminating\n");complete(&priv->finished);
}/*** 提交SPI从机时间同步请求** 该函数用于从SPI从机角度,向SPI主机请求时间同步。它会将本地时钟和剩余微秒封装成数据,* 并通过SPI异步传输的方式发送给SPI主机。时间同步对于需要在分布式系统中保持时间一致性的* 应用非常关键。** @param priv 指向SPI从机时间私有数据结构的指针,包含必要的传输数据和配置信息。* @return 返回spi_async调用的结果,如果失败则记录错误信息。*/
static int spi_slave_time_submit(struct spi_slave_time_priv *priv)
{// 剩余的微秒部分u32 rem_us;// 返回值int ret;// 时间戳,以纳秒为单位u64 ts;// 获取当前的本地时钟值,以纳秒为单位ts = local_clock();// 从纳秒转换到微秒,并将结果保存到rem_usrem_us = do_div(ts, 1000000000) / 1000;// 将纳秒和微秒部分分别转换为大端字节序,并存入缓冲区priv->buf[0] = cpu_to_be32(ts);priv->buf[1] = cpu_to_be32(rem_us);// 初始化SPI消息,只包含一个传输操作spi_message_init_with_transfers(&priv->msg, &priv->xfer, 1);// 设置SPI消息的完成回调函数和上下文数据priv->msg.complete = spi_slave_time_complete;priv->msg.context = priv;// 异步发送SPI消息ret = spi_async(priv->spi, &priv->msg);// 如果发送失败,记录错误信息if (ret)dev_err(&priv->spi->dev, "spi_async() failed %d\n", ret);return ret;
}/*** spi_slave_time_probe - SPI从机时间延迟自动探测函数* @spi: 指向SPI设备结构体的指针** 本函数用于在SPI从机模式下,自动探测和调整时间延迟参数,以确保SPI通信的正确性和稳定性。* 它通过分配私有数据空间,初始化必要的结构,然后提交一个SPI传输请求来进行时间延迟探测。* 若探测过程出错,则返回相应的错误码。** 返回: 0表示成功,负值表示遇到的相应错误。*/
static int spi_slave_time_probe(struct spi_device *spi)
{struct spi_slave_time_priv *priv;int ret;/* 分配内存用于存储私有数据,包括时间延迟探测所需的各种数据 */priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);if (!priv)return -ENOMEM;/* 初始化私有数据结构中的成员 */priv->spi = spi;init_completion(&priv->finished);priv->xfer.tx_buf = priv->buf;priv->xfer.len = sizeof(priv->buf);/* 提交SPI传输请求,进行时间延迟探测 */ret = spi_slave_time_submit(priv);if (ret)return ret;/* 将私有数据结构与SPI设备驱动模型数据关联,以便后续使用 */spi_set_drvdata(spi, priv);return 0;
}/*** 从SPI设备中移除slave定时器功能* * 本函数主要用于从SPI设备中移除slave定时器功能在一些情况下,可能需要* 中止当前的SPI传输操作,并确保所有相关的定时器处理已经完成此函数通过* 调用spi_slave_abort来尝试中止当前的SPI操作,并通过等待完成来确保所有* 相关的定时器处理已经结束这对于在设备移除或者重新配置时清理资源非常有用* * @param spi 指向SPI设备结构的指针该参数是必需的,用于标识需要进行操作的SPI设备* * @return 该函数返回0,表示执行成功这里不使用其他的返回值,因为当前的实现* 不需要区分更多的错误类型* * 注意:该函数假定传入的spi参数是非空的,并且spi所指向的设备已经正确初始化并* 具有slave定时器功能*/
static int spi_slave_time_remove(struct spi_device *spi)
{// 获取与SPI设备相关的私有数据struct spi_slave_time_priv *priv = spi_get_drvdata(spi);// 尝试中止当前的SPI操作spi_slave_abort(spi);// 等待直到所有定时器相关的操作完成wait_for_completion(&priv->finished);return 0;
}static struct spi_driver spi_slave_time_driver = {.driver = {.name	= "spi-slave-time",},.probe		= spi_slave_time_probe,.remove		= spi_slave_time_remove,
};
module_spi_driver(spi_slave_time_driver);MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
MODULE_DESCRIPTION("SPI slave reporting uptime at previous SPI message");
MODULE_LICENSE("GPL v2");

2.4 硬件操作

在这里插入图片描述

3. 设备驱动程序

3.1 Master模式

在这里插入图片描述

3.2 Slave模式

  参考代码:Linux-5.x\drivers\spi\spi-slave-time.c
在这里插入图片描述

  本文章参考了韦东山老师驱动大全部分笔记,其余内容为自己整理总结而来。水平有限,欢迎各位在评论区指导交流!!!😁😁😁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/435288.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jenkins本地安装配置与远程访问管理本地服务详细流程

文章目录 前言1. 安装Jenkins2. 局域网访问Jenkins3. 安装 cpolar内网穿透软件4. 配置Jenkins公网访问地址5. 公网远程访问Jenkins6. 固定公网地址 前言 本文主要介绍如何在Linux CentOS 7中安装Jenkins并结合cpolar内网穿透工具实现远程访问管理本地部署的Jenkins服务. Jenk…

活动报名| 探索存内计算的未来,共话AGI时代

活动日期&#xff1a;2024年09月28日 下午1&#xff1a;00-6&#xff1a;00 活动地点&#xff1a;杭州技术转移中心 三楼路演厅 议程亮点&#xff1a; 存内计算技术架构以及最新趋势AGI开源项目交流存内计算实操上板体验 存内计算 ——突破物理极限的下一代算力技术 直接…

kubernetes存储入门(kubernetes)

实验环境依旧是三个节点拉取镜像&#xff0c;然后在master节点拉取资源清单&#xff1a; 然后同步会话&#xff0c;导入镜像&#xff1b; 存储入门 ConfigMap volume卷--》volumemount&#xff08;挂载卷&#xff09; Glusterfs NFS ISCSI HostPath ConfigMap Secret E…

玄机--蚁剑流量

木马的连接密码是多少 黑客执行的第一个命令是什么 id 黑客读取了哪个文件的内容&#xff0c;提交文件绝对路径 /etc/passwd 黑客上传了什么文件到服务器&#xff0c;提交文件名 黑客上传的文件内容是什么 黑客下载了哪个文件&#xff0c;提交文件绝对路径 蚁剑流量特征总结 …

基于SpringBoot+Vue+MySQL的在线酷听音乐系统

系统展示 用户前台界面 管理员后台界面 系统背景 随着互联网技术的飞速发展&#xff0c;网络已成为人们日常生活中不可或缺的一部分。在线音乐服务因其便捷性和丰富性&#xff0c;逐渐成为用户获取音乐内容的主要渠道。然而&#xff0c;传统的音乐播放平台往往存在歌曲资源有限…

SpringCloud 2023各依赖版本选择、核心功能与组件、创建项目(注意事项、依赖)

目录 1. 各依赖版本选择2. 核心功能与组件3. 创建项目3.1 注意事项3.2 依赖 1. 各依赖版本选择 SpringCloud: 2023.0.1SpringBoot: 3.2.4。参考Spring Cloud Train Reference Documentation选择版本 SpringCloud Alibaba: 2023.0.1.0*: 参考Spring Cloud Alibaba选择版本。同时…

C Primer Plus 第7章——第二篇

你该逆袭了 第7章:重点摘录 三、逻辑运算符1、备选拼写&#xff1a;iso646.h 头文件2、优先级3、求值顺序4、范围 四、一个统计单词的程序1、针对代码&#xff0c;提出疑问&#xff0c;第8章节进行讲解2、我结合自己的理解&#xff0c;自己写的代码 五、条件运算符 &#xff1f…

解决macOS MySQL安装后不能远程访问的问题

主要是因为我的后端服务是通过docker部署的, 无法和宿主机的MySQL进行通信. 首先输入 use mysql; 之后输入 update user set host “%” where user “root”; 最后输入 flush privileges; 合起来就是: use mysql;update user set host "%" where user &qu…

TypeScript 基本使用指南【前端 26】

TypeScript 基本使用指南 引言 TypeScript 是 JavaScript 的一个超集&#xff0c;它添加了类型系统和一些其他特性&#xff0c;使得开发大型应用时更加高效和可靠。TypeScript 代码最终会被编译成普通的 JavaScript 代码&#xff0c;这意味着你可以在任何支持 JavaScript 的环…

轻量级日志管理系统SpringBoot3+Loki+grafana的使用实例

目录 文章目录 目录1、简介2、SpringBoot3应用发送日志到Loki2.1、基本介绍2.2、添加依赖2.3、配置文件application.yml2.4、创建logback配置2.5、添加日志示例2.6、运行SpringBoot3 3、在grafana中查看日志3.1、登录grafana3.2、查询日志3.3、查询我们的SpringBoot发送过来的日…

828华为云征文|针对Flexus X实例云服务器的CPU和内存性能测评

目录 一、Flexus X实例云服务器简介 1.1 产品摘要 1.2 产品优势 1.3 本次测评服务器规格 二、CPU性能测试 2.1 操作说明 2.2 操作步骤 2.2 结果分析 三、测试内存负载 3.1 操作说明 3.2 操作步骤 3.3 结果分析 四、测试终评 一、Flexus X实例云服务器简介 1.1 产品…

PostgreSQL数据库与PostGIS在Windows中的部署与运行

本文介绍在Windows电脑中&#xff0c;下载、安装、部署并运行PostgreSQL与PostGIS数据库服务的方法。 PostgreSQL是一种功能强大的开源关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;以其稳定性、可靠性和丰富的功能而闻名&#xff1b;其支持多种高级特性&…

今天推荐一个文档管理系统 Dorisoy.Pan

Dorisoy.Pan 是一个基于 .NET 8 和 WebAPI 构建的文档管理系统&#xff0c;它集成了 Autofac、MediatR、JWT、EF Core、MySQL 8.0 和 SQL Server 等技术&#xff0c;以实现一个简单、高性能、稳定且安全的解决方案。 这个系统支持多种客户端&#xff0c;包括网站、Android、iO…

Mybatis缓存机制(图文并茂!)

目录 一级缓存 需求我们在一个测试中通过ID两次查询Monster表中的信息。 二级缓存 案例分许(和上述一样的需求) EhCache第三方缓存 在了解缓存机制之前&#xff0c;我们要先了解什么是缓存&#xff1a; ‌缓存是一种高速存储器&#xff0c;用于暂时存储访问频繁的数据&…

Dubbo快速入门(一):分布式与微服务、Dubbo基本概念

文章目录 一、分布式与微服务概念1.大型互联网架构目标2.集群和分布式&#xff08;1&#xff09;集群 (Cluster)&#xff08;2&#xff09;分布式计算 (Distributed Computing)&#xff08;3&#xff09;集群与分布式的关系&#xff08;4&#xff09;实践中的应用案例 3.架构演…

了解独享IP的概念及其独特优势

在网络世界中&#xff0c;IP地址是用来识别和定位设备的标识符。独享IP是一种服务模式。使用代理服务器时&#xff0c;用户拥有一个不与其他用户共享的专用独立IP地址。与共享IP相比&#xff0c;独享IP为用户提供了更高的独立性和隐私保护。下面详细介绍独享IP的定义、工作原理…

SQL高可用优化-优化SQL中distinct和Where条件对索引字段进行非空检查语句

最近做一个需求&#xff0c;关于SQL高可用优化&#xff0c;需要优化项目中的SQL&#xff0c;提升查询效率。 SQL高可用优化 一、优化SQL包含distinct场景二、优化SQL中Where条件中索引字段是否为NULL三、代码验证1. NodeMapper2. NodeService3. NodeController4.数据库数据5.项…

【LLM大模型】Ollama 运行 GGUF 模型

Ollama 默认直接支持很多模型&#xff0c;只需要简单的使用 ollama run命令&#xff0c;示例如下&#xff1a; ollama run gemma:2b就可安装、启动、使用对应模型。 通过这样方式直接支持的模型我们可以通过https://ollama.com/library 找到。 在https://huggingface.co/mod…

Mac优化清理工具CleanMyMac X 4.15.6 for mac中文版

CleanMyMac X 4.15.6 for mac中文版下载是一款功能更加强大的系统优化清理工具&#xff0c;软件只需两个简单步骤就可以把系统里那些乱七八糟的无用文件统统清理掉&#xff0c;节省宝贵的磁盘空间。CleanMyMac X 4.15.6 for mac 软件与最新macOS系统更加兼容&#xff0c;流畅地…

启动 Ntopng 服务前需先启动 redis 服务及 Ntopng 常用参数介绍

启动Ntopng服务之前需要先启动redis服务&#xff0c;因为Ntopng服务依赖于redis服务的键值存储。 服务重启 服务启动 Ntopng常用参数&#xff1a; -d 将 Ntopng 进程放入后台执行。默认情况下&#xff0c;Ntop 在前台运行。 -u 指定启动Ntopng执行的用户&#xff0c;默认为…