SPI驱动(九) -- SPI_Master驱动程序
文章目录
- 参考资料:
- 一、SPI传输概述
- 二、SPI传输的两种方法
- 2.1 旧方法
- 2.2 新方法
参考资料:
参考资料:
- 参考内核源码:
drivers\spi\spi.c
一、SPI传输概述
SPI控制器的作用是发起与它下面挂接的SPI设备之间的数据传输,那么控制器驱动程序的核心就是实现与设备之间的数据传输过程。在内核中,SPI传输的最小单位是spi_transfer,对于一个设备,可以发起多个spi_transfer。这些spi_transfer,会放入一个spi_message里面。每个SPI设备都有一个自己的spi_message,同一个spi_master下的spi_message,放在一个队里。
- spi_transfer:指定tx_buf、rx_buf、len
struct spi_transfer {const void *tx_buf;void *rx_buf;...}
- 同一个SPI设备的spi_transfer,使用spi_message来管理:
struct spi_message {struct list_head transfers; //管理spi_transfer...
}
- 同一个SPI Master下的spi_message,放在一个队列里:
struct spi_master {...struct list_head queue; //存放每个spi_device的spi_message...
}
所以,反过来,SPI传输的流程是:
- 从
spi_master的队列里取出每一个spi_message- 从
spi_message的队里里取出一个spi_transfer- 处理
spi_transfer
- 处理
- 从
二、SPI传输的两种方法
在spi_master结构中,有两个传输函数,函数指针transfer 代表旧方法,函数指针transfer_one代表新方法。
struct spi_master {
...
/* 旧方法 */
int (*transfer) (struct spi_device *spi, struct spi_message *mesg);
/* 新方法 */
int (*transfer_one)(struct spi_master *master, struct spi_device *spi, struct spi_transfer *transfer);
...
}
2.1 旧方法

内核传输函数入口spi_sync():
int spi_sync(struct spi_device *spi, struct spi_message *message)
{ret = __spi_sync(spi, message);
}
继续调用__spi_sync(),里面设置了传输完成回调函数spi_complete,如果master->transfer == spi_queued_transfer表示使用新方法,新方法使用内核提供的transfer 函数,它会帮我们把spi_message放入queue并处理。else分支spi_async_locked表示的是旧方法,需要我们自己实现transfer函数,自己管理queue,自己触发传输。spi_async_locked是异步传输,触发传输后马上返回,随后wait_for_completion(&done)等待传输结果。
static int __spi_sync(struct spi_device *spi, struct spi_message *message)
{DECLARE_COMPLETION_ONSTACK(done);int status;struct spi_master *master = spi->master;unsigned long flags;status = __spi_validate(spi, message);if (status != 0)return status;message->complete = spi_complete; //传输完成回调函数message->context = &done;message->spi = spi;SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, spi_sync);SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync);/* If we're not using the legacy transfer method then we will* try to transfer in the calling context so special case.* This code would be less tricky if we could remove the* support for driver implemented message queues.*/if (master->transfer == spi_queued_transfer) { //新方法spin_lock_irqsave(&master->bus_lock_spinlock, flags);trace_spi_message_submit(message);status = __spi_queued_transfer(spi, message, false);spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);} else {status = spi_async_locked(spi, message); //老方法,异步传输}if (status == 0) {/* Push out the messages in the calling context if we* can.*/if (master->transfer == spi_queued_transfer) {SPI_STATISTICS_INCREMENT_FIELD(&master->statistics,spi_sync_immediate);SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics,spi_sync_immediate);__spi_pump_messages(master, false);}wait_for_completion(&done); //等待传输结果status = message->status;}message->context = NULL;return status;
}
继续看spi_async_locked(), 它调用__spi_async(), 继续往下,最终调用master->transfer(spi, message),这个就是自己实现的transfer函数。
int spi_async_locked(struct spi_device *spi, struct spi_message *message)
{struct spi_master *master = spi->master;int ret;unsigned long flags;ret = __spi_validate(spi, message);if (ret != 0)return ret;spin_lock_irqsave(&master->bus_lock_spinlock, flags);ret = __spi_async(spi, message);spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);return ret;}static int __spi_async(struct spi_device *spi, struct spi_message *message)
{struct spi_master *master = spi->master;message->spi = spi;SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, spi_async);SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_async);trace_spi_message_submit(message);return master->transfer(spi, message); //需要自己实现transfer
}
2.2 新方法

新方法第一步会调用__spi_queued_transfer()将spi_message放入队列,然后在调用__spi_pump_messages()压出数据进行处理。流程如上图。
相关文章:
SPI驱动(九) -- SPI_Master驱动程序
文章目录 参考资料:一、SPI传输概述二、SPI传输的两种方法2.1 旧方法2.2 新方法 参考资料: 参考资料: 参考内核源码: drivers\spi\spi.c 一、SPI传输概述 SPI控制器的作用是发起与它下面挂接的SPI设备之间的数据传输,那么控制…...
MySQL常用函数详解及SQL代码示例
MySQL常用函数详解及SQL代码示例 引言当前日期和时间函数字符串函数数学函数聚合函数结论 引言 MySQL作为一种广泛使用的关系型数据库管理系统,提供了丰富的内置函数来简化数据查询、处理和转换。掌握这些函数可以大大提高数据库操作的效率和准确性。本文将详细介绍…...
Linux 进程的创建、终止、等待与程序替换函数 保姆级讲解
目录 一、 进程创建 fork函数 二、进程的终止: 1. 想明白:终止是在做什么? 2.进程终止的3种情况? a.退出码是什么?存在原因?为什么int main()return 0? b.第三种进程终止的情况…...
大数据(1.1)纽约出租车大数据分析实战:从Hadoop到Azkaban的全链路解析与优化
目录 一、背景与数据价值 二、技术选型与组件分工 三、数据准备与预处理 四、实战步骤详解 1. 数据上传至HDFS 2. Hive数据建模与清洗 4.2.1 建表语句(分区表按年份): 4.2.2 数据清洗(剔除无效…...
BSCAN2-1:load design
1. DFT Flow Using Tessent Shell Tessent BoundaryScan 具有一个基本的高层次流程顺序。下图展示了将 Tessent BoundaryScan 插入设计所需的高层次步骤顺序。图中的每个步骤都链接到有关可测试性设计(DFT)流程的更详细信息,包括示例。 Desi…...
个人学习编程(3-18) leetcode刷题
爬楼梯: 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 示例 1: 输入:n 2 输出:2 解释:有两种方法可以爬到楼顶。 1. 1 阶 1 阶 2. 2 …...
【css酷炫效果】纯CSS实现立体旋转立方体
【css酷炫效果】纯CSS实现立体旋转立方体 缘创作背景html结构css样式完整代码效果图 想直接拿走的老板,链接放在这里:https://download.csdn.net/download/u011561335/90492014 缘 创作随缘,不定时更新。 创作背景 刚看到csdn出活动了&am…...
Android Fresco 框架兼容模块源码深度剖析(六)
Android Fresco 框架兼容模块源码深度剖析 一、引言 在 Android 开发的多元环境中,兼容性是衡量一个框架优劣的重要指标。Fresco 作为一款强大的图片加载框架,其兼容模块在确保框架能在不同 Android 版本、不同设备和不同图片格式下稳定运行方面发挥着…...
ABSD基于架构的软件设计
基于架构的设计(ABSD)Architecture-Based Software Design是一种软件设计方法,强调软件架构设计应该由商业、质量和功能需求共同驱动。这种方法允许设计活动在明确项目总体功能框架的前提下开始,并且需求抽取和分析活动应与设计活…...
LLM中lora的梯度更新策略公式解析
LLM中lora的梯度更新策略公式解析 目录 LLM中lora的梯度更新策略公式解析区别如何使用LoRA代码中的参数更新方式二阶导数(如右侧公式关联的Fisher信息)的作用区别 定义与理论来源: 左公式 F ( w i ) = 1 n...
开源数据仓库全解 — 从原理到实践
🎯 一、什么是数据仓库? 数据仓库(Data Warehouse,简称 DW)是面向分析和决策的专门数据存储系统,旨在整合来自多个源的数据,支持复杂查询和大规模分析任务。 特点包括: 面向主题&…...
Mac下Ollama安装全攻略:开启本地大模型之旅
文章目录 Mac下Ollama安装全攻略:开启本地大模型之旅一、Ollama 是什么功能特点优势应用场景 二、安装前准备(一)系统要求(二)硬件要求 三、下载安装包(一)官网下载(二)其…...
线程大乱斗:从入门到精通,解锁Java并发编程的终极秘籍
目录 什么是线程? jave创建线程方式有几种? 线程中常用的方法 线程状态 多线程 解决线程安全问题 线程通信 何为并发编程? 并发执行和并行执行 线程的三个主要问题: 1、不可见性: 2、乱序性: …...
Web3游戏行业报告
一,gamefi经济 什么是gamefi GameFi是一个缩写,它结合了游戏和去中心化金融(“DeFi”)这两个术语,关注的是游戏玩法如何在去中心化系统中实现货币化。对于游戏而言,只要开放了交易市场,允许玩家自由买卖,…...
hibernate 自动生成数据库表和java类 字段顺序不一致 这导致添加数据库数据时 异常
hibernate 自动生成的数据库表和java类 字段顺序不一致 这导致该书写方式添加数据库数据时 异常 User user new User( null, username, email, phone, passwordEncoder.encode(password) ); return userRepository.save(user);Hibernate 默认不会保证数据库表字段的顺序与 Ja…...
bbbbb
import java.util.ArrayList; import java.util.List; public class KthPermutation { public static String getPermutation(int n, int k) { // 计算阶乘 int[] factorial new int[n]; factorial[0] 1; for (int i 1; i < n; i) …...
《基于Workspace.java的Launcher3改造:HotSeat区域动态阻断文件夹生成机制》
1. 需求背景与技术挑战 在Android 13系统Launcher3定制化开发中,需实现禁止HotSeat区域创建文件夹的功能。原始逻辑中,当用户拖拽应用图标至HotSeat区域相邻图标时,会触发FolderIcon的实例化。本文将深入分析Launcher3的文件夹创建机制&…...
Cursor在内网环境配置自定义DeepSeek API
关键字 Cursor、DeepSeek、API配置、内网代理、HTTP/2 背景环境 使用Cursor集成环境开发程序。但是我使用公司的内网并不能使用cursor自带的模型,于是我就想使用DeepSeek官方的API服务。 环境:Windows 11系统 解决过程 网络检测 首先进行环境检测&am…...
【数据库】掌握MySQL事务与锁机制-数据一致性的关键
在数据库的世界里,数据就是一切。而确保数据的准确性和一致性,则是数据库系统的核心任务之一。想象一下,如果没有合适的机制,当多个用户同时试图修改同一条数据时,会发生什么? chaos(混乱&#…...
在Vue3中使用$router.push方法进行路由跳转时,如何传递多个路径参数?
在 Vue 3 里,你可以借助 $router.push 方法进行路由跳转,同时传递多个路径参数。下面为你详细介绍具体实现方式: 1. 路由配置 首先,要在路由配置中定义好需要的路径参数。示例如下: import { createRouter, createW…...
【初学者】解释器和脚本各是什么?有什么区别与联系?
李升伟 整理 解释器和脚本的定义 1. 解释器(Interpreter) 定义:解释器是一个程序,负责逐行读取并执行代码。它将源代码翻译成机器能理解的指令,并立即执行。特点: 逐行执行代码。适合交互式编程…...
Kafka跨集群数据备份与同步:MirrorMaker运用
#作者:张桐瑞 文章目录 前言MirrorMaker是什么运行MirrorMaker各个参数的含义 前言 在大多数情况下,我们会部署一套Kafka集群来支撑业务需求。但在某些特定场景下,可能需要同时运行多个Kafka集群。比如,为了实现灾难恢复&#x…...
AI学习第二天--监督学习 半监督学习 无监督学习
目录 1. 监督学习(Supervised Learning) 比喻: 技术细节: 形象例子: 2. 无监督学习(Unsupervised Learning) 比喻: 技术细节: 形象例子: 3. 半监督学…...
设计模式(创建型)-抽象工厂模式
摘要 在软件开发的复杂世界中,设计模式作为解决常见问题的最佳实践方案,一直扮演着至关重要的角色。抽象工厂模式,作为一种强大的创建型设计模式,在处理创建一系列或相关依赖对象的场景时,展现出了独特的优势和灵活性。它通过提供一个创建对象的接口,让开发者能够在不指定…...
linux系统 Ubuntu22.04安装Nvidia驱动,解决4060系列显卡重启黑屏方法
一、禁用Nouveau 1.查看nouveau lsmod | grep nouveau 2.编辑 blacklist.conf sudo gedit /etc/modprobe.d/blacklist.conf 3.在文件最后加入 blacklist nouveau options nouveau modeset0 4.保存并关闭文件 5.更新 sudo update-initramfs -u 6.重启之后,检…...
观察者模式详解:用 Qt 信号与槽机制深入理解
引言 你是否曾遇到这样的需求:一个对象的状态发生变化后,希望通知其他对象进行相应的更新?比如: 新闻订阅系统:当新闻发布后,所有订阅者都会收到通知。股票行情推送:股价变化时,所…...
OSWorld:开启多模态智能体的真实计算机环境革命
OSWorld:开启多模态智能体的真实计算机环境革命 在人工智能技术突飞猛进的今天,多模态智能体正逐步突破实验室的限制,试图融入人类的日常工作场景。然而,如何评估这些智能体在真实计算机环境中处理开放式任务的能力,成为学术界和产业界共同关注的难题。2024年,由xlang-ai…...
LabVIEW烟气速度场实时监测
本项目针对燃煤电站烟气流速实时监测需求,探讨了静电传感器结构与速度场超分辨率重建方法,结合LabVIEW多板卡同步采集与实时处理技术,开发出一个高效的烟气速度场实时监测系统。该系统能够在高温、高尘的复杂工况下稳定运行,提供高…...
电脑管家如何清理内存及垃圾,提升电脑性能
电脑在长时间使用后,常常会变得越来越卡顿,打开程序的速度变慢,甚至响应迟缓。这时,不少用户会选择使用电脑管家来进行内存清理和垃圾清理。那么,电脑管家是如何清理内存的?它又是如何清理垃圾的࿱…...
强化学习基础篇二:马尔可夫决策过程
写在前面 本文是对李沐等“动手学强化学习”教程的个人阅读总结,原文链接:动手学强化学习。 第3章 马尔可夫决策过程 3.1 重要性 马尔可夫决策过程是强化学习中的基础概念,强化学习中的环境就是一个马尔可夫决策过程,与多臂老虎…...
