Linux学习第40天:Linux SPI 驱动实验(一):乾坤大挪移

Linux版本号4.1.15   芯片I.MX6ULL                                    大叔学Linux    品人间百味  思文短情长 


       主从工作方式完成数据交换,形象的说就是武侠中的乾坤大挪移。

        本章实验的最终目的就是驱动 I.MX6UALPHA 开发板上的 ICM-20608 这个 SPI 接口的六轴传感器,可以在应用程序中读取 ICM-20608的原始传感器数据。

        本章的思维导图如下:

一、Linux 下SPI驱动框架简介

        重点在SPI 设备驱动编写。


1、SPI主机驱动

        Linux 内核使用 spi_master 表示 SPI 主机驱动, spi_master 是个结构体:

315 struct spi_master {
316 struct device dev;
317
318 struct list_head list;
......
326 s16 bus_num;
327
328 /* chipselects will be integral to many controllers; some others
329 * might use board-specific GPIOs.
330 */
331 u16 num_chipselect;
332
333 /* some SPI controllers pose alignment requirements on DMAable
334 * buffers; let protocol drivers know about these requirements.
335 */
336 u16 dma_alignment;
337
338 /* spi_device.mode flags understood by this controller driver */
339 u16 mode_bits;
340
341 /* bitmask of supported bits_per_word for transfers */
342 u32 bits_per_word_mask;
......
347 /* limits on transfer speed */
348 u32 min_speed_hz;
349 u32 max_speed_hz;
350
351 /* other constraints relevant to this driver */
352 u16 flags;
359 /* lock and mutex for SPI bus locking */
360 spinlock_t bus_lock_spinlock;
361 struct mutex bus_lock_mutex;
362
363 /* flag indicating that the SPI bus is locked for exclusive use */
364 bool bus_lock_flag;
......
372 int (*setup)(struct spi_device *spi);
373
......
393 int (*transfer)(struct spi_device *spi,/*transfer 函数,和 i2c_algorithm 中的 master_xfer 函数一样,控制器数据传输函
数。*/
394 struct spi_message *mesg);/*transfer_one_message 函数,也用于 SPI 数据发送,用于发送一个 spi_message,
SPI 的数据会打包成 spi_message,然后以队列方式发送出去。*/
......
434 int (*transfer_one_message)(struct spi_master *master,
435 struct spi_message *mesg);
......
462 };

        SPI 主机驱动的核心就是申请 spi_master,然后初始化 spi_master,最后向 Linux 内核注册spi_master。

1)、spi_master 申请与释放

struct spi_master *spi_alloc_master(struct device *dev,
unsigned size)

dev:设备,一般是 platform_device 中的 dev 成员变量。
size: 私有数据大小,可以通过 spi_master_get_devdata 函数获取到这些私有数据。
返回值: 申请到的 spi_master。
        spi_master 的释放通过 spi_master_put 函数来完成,当我们删除一个 SPI 主机驱动的时候就
需要释放掉前面申请的 spi_master, spi_master_put 函数原型如下:

void spi_master_put(struct spi_master *master)

master:要释放的 spi_master。
 

2)、spi_master 的注册与注销

        当 spi_master 初始化完成以后就需要将其注册到 Linux 内核, spi_master 注册函数为
spi_register_master,函数原型如下:

int spi_register_master(struct spi_master *master)

master:要注册的 spi_master。
返回值: 0,成功;负值,失败。
        I.MX6U 的 SPI 主机驱动会采用 spi_bitbang_start 这个 API 函数来完成 spi_master 的注册,spi_bitbang_start 函数内部其实也是通过调用 spi_register_master 函数来完成 spi_master 的注册。
        如果要注销 spi_master 的话可以使用 spi_unregister_master 函数,此函数原型为:

void spi_unregister_master(struct spi_master *master)

        如果使用 spi_bitbang_start 注册 spi_master 的话就要使用 spi_bitbang_stop 来注销掉
spi_master。

2、SPI设备驱动

        Linux 内核使用 spi_driver 结构体来表示 spi 设备驱动。

180 struct spi_driver {
181 const struct spi_device_id *id_table;
182 int (*probe)(struct spi_device *spi);
183 int (*remove)(struct spi_device *spi);
184 void (*shutdown)(struct spi_device *spi);
185 struct device_driver driver;
186 };

spi_driver 初始化完成以后需要向 Linux 内核注册, spi_driver 注册函数为
spi_register_driver,函数原型如下:
 

int spi_register_driver(struct spi_driver *sdrv)

        注销 SPI 设备驱动以后也需要注销掉前面注册的 spi_driver,使用 spi_unregister_driver 函
数完成 spi_driver 的注销,函数原型如下:

void spi_unregister_driver(struct spi_driver *sdrv)

spi_driver 注册示例程序如下:

1 /* probe 函数 *//*第 1~36 行, spi_driver 结构体,需要 SPI 设备驱动人员编写,包括匹配表、 probe 函数等。
和 i2c_driver、 platform_driver 一样*/
2 static int xxx_probe(struct spi_device *spi)
3 {
4 /* 具体函数内容 */
5 return 0;
6 }
7 8
/* remove 函数 */
9 static int xxx_remove(struct spi_device *spi)
10 {
11 /* 具体函数内容 */
12 return 0;
13 }
14 /* 传统匹配方式 ID 列表 */
15 static const struct spi_device_id xxx_id[] = {
16 {"xxx", 0},
17 {}
18 };
19
20 /* 设备树匹配列表 */
21 static const struct of_device_id xxx_of_match[] = {
22 { .compatible = "xxx" },
23 { /* Sentinel */ }
24 };
25
26 /* SPI 驱动结构体 */
27 static struct spi_driver xxx_driver = {
28 .probe = xxx_probe,
29 .remove = xxx_remove,
30 .driver = {
31 .owner = THIS_MODULE,
32 .name = "xxx",
33 .of_match_table = xxx_of_match,
34 },
35 .id_table = xxx_id,
36 };
37
38 /* 驱动入口函数 */
39 static int __init xxx_init(void)/*第 39~42 行,在驱动入口函数中调用 spi_register_driver 来注册 spi_driver。*/
40 
41 return spi_register_driver(&xxx_driver);
42 }
43
44 /* 驱动出口函数 */
45 static void __exit xxx_exit(void)/*第 45~48 行,在驱动出口函数中调用 spi_unregister_driver 来注销 spi_driver。*/
46 {
47 spi_unregister_driver(&xxx_driver);
48 }
49
50 module_init(xxx_init);
51 module_exit(xxx_exit);

3、SPI设备和驱动匹配

        SPI 设备和驱动的匹配过程是由 SPI 总线来完成的,SPI总线为 spi_bus_type,定义在 drivers/spi/spi.c 文件中,内容如下:

131 struct bus_type spi_bus_type = {
132 .name = "spi",
133 .dev_groups = spi_dev_groups,
134 .match = spi_match_device,
135 .uevent = spi_uevent,
136 };

        SPI 设备和驱动的匹配函数为 spi_match_device,函数内容如下:

99 static int spi_match_device(struct device *dev,
struct device_driver *drv)
100 {
101 const struct spi_device *spi = to_spi_device(dev);
102 const struct spi_driver *sdrv = to_spi_driver(drv);
103
104 /* Attempt an OF style match */
105 if (of_driver_match_device(dev, drv))/*第 105 行, of_driver_match_device 函数用于完成设备树设备和驱动匹配。比较 SPI 设备节
点的 compatible 属性和 of_device_id 中的 compatible 属性是否相等,如果相当的话就表示 SPI 设
备和驱动匹配。*/
106 return 1;
107
108 /* Then try ACPI */
109 if (acpi_driver_match_device(dev, drv))/*acpi_driver_match_device 函数用于 ACPI 形式的匹配。*/
110 return 1;
111
112 if (sdrv->id_table)
113 return !!spi_match_id(sdrv->id_table, spi);/*spi_match_id 函数用于传统的、无设备树的 SPI 设备和驱动匹配过程。比较 SPI
设备名字和 spi_device_id 的 name 字段是否相等,相等的话就说明 SPI 设备和驱动匹配。*/
114
115 return strcmp(spi->modalias, drv->name) == 0;/*比较 spi_device 中 modalias 成员变量和 device_driver 中的 name 成员变量是否
相等*/
116 }

        以下内容将在下一节学习:

二、I.MX6U SPI主机驱动分析

三、SPI设备驱动编写流程

1、SPI设备信息描述

2、SPI设备数据收发处理流程

四、硬件原理图分析

五、实验程序编写

1、修改设备树

2、编写ICM20608驱动

3、编写测试APP

六、运行测试

1、编译驱动程序和测试APP

1)、编译驱动程序

2)、编译测试APP

2、运行测试

七、总结


本文为参考正点原子开发板配套教程整理而得,仅用于学习交流使用,不得用于商业用途。

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

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

相关文章

3D渲染原理及朴素JavaScript实现【不使用WebGL】

在网页中显示图像和其他平面形状非常容易。 然而,当涉及到显示 3D 形状时,事情就变得不那么容易了,因为 3D 几何比 2D 几何更复杂。 为此,你可以使用专用技术和库,例如 WebGL 和 Three.js。 但是,如果你只…

菜单栏管理软件 Bartender 3 mac中文版功能介绍

​Bartender 3 mac是一款菜单栏管理软件,该软件可以将指定的程序图标隐藏起来,需要时呼出即可。 Bartender 3 mac功能介绍 Bartender 3完全支持macOS Sierra和High Sierra。 更新了macOS High Sierra的用户界面 酒吧现在显示在菜单栏中,使其…

Linux系统上搭建高可用Kafka集群(使用自带的zookeeper)

本次在CentOS7.6上搭建Kafka集群 Apache Kafka 是一个高吞吐量的分布式消息系统,被广泛应用于大规模数据处理和实时数据管道中。本文将介绍在CentOS操作系统上搭建Kafka集群的过程,以便于构建可靠的消息处理平台。 文件分享(KafkaUI、kafka…

Leetcode421. 数组中两个数的最大异或值

Every day a Leetcode 题目来源:421. 数组中两个数的最大异或值 解法1:贪心 位运算 初始化答案 ans 0。从最高位 high_bit 开始枚举 i,也就是 max⁡(nums) 的二进制长度减一。设 newAns ans 2i,看能否从数组 nums 中选两个…

servlet 的XML Schema从哪边获取

servlet 6.0的规范定义: https://jakarta.ee/specifications/servlet/6.0/ 其中包含的三个XML Schema:web-app_6_0.xsd、web-common_6_0.xsd、web-fragment_6_0.xsd。但这个页面没有给出下载的链接地址。 正好我本机有Tomcat 10.1.15版本的源码&#…

头歌答案--爬虫实战

目录 urllib 爬虫 第1关:urllib基础 任务描述 第2关:urllib进阶 任务描述 requests 爬虫 第1关:requests 基础 任务描述 第2关:requests 进阶 任务描述 网页数据解析 第1关:XPath解析网页 任务描述 第…

基于公共业务提取的架构演进——外部依赖防腐篇

1.背景 有了前两篇的帐号权限提取和功能设置提取的架构演进后,有一个问题就紧接着诞生了,对于诸多业务方来说,关键数据源的迁移如何在各个产品落地? 要知道这些数据都很关键: 对于帐号,获取不到帐号信息是…

如何在后台执行 SwiftData 操作

文章目录 前言Core Data 私有队列上下文SwiftData 并发支持使用 ModelActor合并上下文更改的问题通过标识符访问模型总结 前言 SwiftData 是一个用于处理数据操作的框架,特别是在 Swift 语言中进行并发操作。本文介绍了如何在后台执行 SwiftData 操作以及与 Core D…

基于springboot的在线文档管理系统

基于springboot的在线文档管理系统 摘要 基于Spring Boot的在线文档管理系统是一种通过使用Spring Boot框架构建的现代化应用程序,旨在有效地组织、存储和分享文档内容。该系统通过利用Spring Boot的快速开发和简化配置的优势,提供了一个稳健的基础架构&…

某手游完整性校验分析

前言 只是普通的单机手游,广告比较多,所以分析处理了下,校验流程蛮有意思的,所以就分享出来了 1.重打包崩溃处理 样本进行了加固,对其dump出dex后重打包出现崩溃 ida分析地址发现为jni函数引起 利用Xposed直接替换…

Yolo自制detect训练

Install 把代码拉下来 GitHub - ultralytics/yolov5 at v5.0 然后 pip install -r requirements.txt 安装完了,运行一下detect.py即可 结果会保存在对应的目录下 Intro ├── data:主要是存放一些超参数的配置文件(这些文件(yaml文件)是用来配置训练集和测试集还有验…

基于讯飞星火大语言模型开发的智能插件:小策问答

星火大语言模型是一种基于深度学习的自然语言处理技术,它能够理解和生成人类语言。这种模型的训练过程涉及到大量的数据和复杂的算法,但最终的目标是让机器能够像人一样理解和使用语言。 小策问答是一款基于星火大语言模型的定制化GPT插件小工具。它的主…

ios安全加固 ios 加固方案

​ 目录 一、iOS加固保护原理 1.字符串混淆 2.类名、方法名混淆 3.程序结构混淆加密 4.反调试、反注入等一些主动保护策略 二 代码混淆步骤 1. 选择要混淆保护的ipa文件 2. 选择要混淆的类名称 3. 选择要混淆保护的函数,方法 4. 配置签名证书 5. 混淆和测…

ida81输入密码验证算法分析以及破解思路

本文分析了ida81对输入密码的验证流程,分别对输入密码到生成解密密钥、密码素材的生成过程以及文件数据的加密过程这三个流程进行分析,并尝试找一些可利用的破绽。很遗憾,由于水平有限,目前也只是有个思路未能完全实现&#xff0c…

腾讯域名优惠卷领取

腾讯域名到到期了,听说申请此计划,可获得优惠卷,看到网上5年域名只需要10元,姑且试试看。 我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?in…

“辛巴猫舍”内网渗透、提权、撞库学习笔记

前言: 在拿到靶机时,我们最先需要做的是信息收集,包括不限于:C段扫描,端口探测,指纹识别,版本探测等。其次就是 漏洞挖掘、漏洞利用、提权、维持权限、日志清理、留下后门。 以上就是渗透的基本…

Autosar UDS开发01(UDS诊断入门概念(UDSOnCan))

目录 回顾接触UDS的过程 UDS基本概念 UDS的作用 UDS的宏观认识 UDS的CAN通讯链路 UDS的报文种类 回顾接触UDS的过程 自21年毕业后,我一直干了2年的Autosar CAN通讯开发。 开发的主要内容简单概括就是:应用报文开发、网管报文开发、休眠唤醒开发&am…

【PostgreSql本地备份为dump文件与恢复】使用脚本一键备份为dump文件

环境:windows数据库:postgresql 1.准备脚本 backUpDb.bat 脚本为备份脚本,双击运行,右键可以选择编辑;restoreDb.bat 脚本为恢复脚本,双击运行,右键选择编辑; 1.1 脚本介绍 如上图…

docker更改存储目录原因及方案

为什么一定要将docker的存储目录挂载到其他目录 docker在安装时默认存储目录在/var/lib/docker,而该目录是在系统盘下的。docker安装后,会使用各种各样的镜像,动辄几个G,那么如此多的镜像文件,装着装着系统盘就撑爆了…

【mysql】将逗号分割的字段内容转换为多行并group by

先说需求: 公司想让我通过mysql导出一个报表,内容为公司每个人参加会议的次数,现在有一个会议表fusion_meeting,正常的逻辑是通过人员直接group by就可以得出结果,但是我们的参会人是通过逗号分割这种方式存在一个字段…