19.SPI核心框架简介

news2024/11/24 13:45:10

目录

SPI物理总线

信号线

spi时序

spi通信模式

常见spi设备

SPI驱动框架简介

spi主机驱动:spi_controller结构体

spi设备驱动:spi_device结构体、spi_driver结构体

spi总线注册:spi_init()

spi总线定义:spi_bus_type

spi控制器驱动

设备树节点

module_platform_driver()宏


SPI物理总线

信号线

SCK:时钟线,数据收发同步。

MOSI:数据线,主设备数据发送、从设备数据接收。

MISO:数据线,从设备数据发送、主设备数据接收。

NSS、CS:片选信号线。

支持一主多从,全双工通信,最大速率可达上百MHz。

spi时序

起始信号:NSS信号线由高变低。

停止信号:NSS信号线由低变高。

数据传输:在SCK的每个时钟周期MOSI和MISO同时传输一位数据,高/低位传输没有硬件规定。

        传输单位:字节/半字

        单位数量:不受限制

spi通信模式

总线空闲时SCK的时钟状态以及数据采样时刻。

时钟极性CPOL:指spi通讯设备处于空闲状态时,SCK信号线的电平信号

        CPOL = 0时,SCK在空闲状态时为低电平

        CPOL = 1时,SCK在空闲状态时为高电平

时钟相位CPHA:数据的采样时刻

        CPHA = 0时,数据在SCK时钟线的“奇数边沿”被采样

        CPHA = 1时,数据在SCK时钟线的“偶数边沿”被采样

SPI模式CPOLCPHA空闲时SCK时钟采样时刻
000低电平奇数边沿
101低电平偶数边沿
210高电平奇数边沿
311高电平偶数边沿

常见spi设备

EEPROM、FLASH、实时时钟、AD转换器等

SPI驱动框架简介

SPI核心层

        提供SPI控制器驱动和设备驱动的注册方法、注销方法、SPI通信硬件无关接口

SPI主机驱动

        主要包含SPI硬件体系结构中适配器(spi控制器)的控制,用于产生SPI读写时序

        主要数据结构:spi_master(spi_controller)

SPI设备驱动

        通过SPI主机驱动与CPU交换数据

        主要数据结构:spi_device和spi_driver

spi主机驱动:spi_controller结构体

代码存放在内核/include/linux/spi/spi.h文件。

#define spi_master                      spi_controller

struct spi_controller {
	struct device		dev;
	struct list_head 	list;			// 连接全部spi_master链表节点
	s16					bus_num;		// spi控制器编号
	u16					num_chipselect;	// 片选信号的个数,用来和多个从设备进行通信
	...
	
	/* 当前正待处理的消息队列。抽象表示一条spi消息,要发送的内容填充此结构体 */
	struct spi_message		*cur_msg;
	...
	
	/* 初始化spi设备硬件 */
	int			(*setup)(struct spi_device *spi);
	/* 传输spi消息,异步传输,此函数把消息加入spi控制器的消息队列,下面的queue */
	int			(*transfer)(struct spi_device *spi, struct spi_message *mesg);
	/* spi通信结束后,释放 spi_master所需要的清理工作 */
	void		(*cleanup)(struct spi_device *spi);
	
	struct kthread_worker	kworker;		// 内核流水线工人,由其来完成发送,由于spi速度快,数据量大,因此可采用异步传输方式发送数据
	struct task_struct		*kworker_task;	// 进程/线程结构体,配合上面的kworker来工作
	struct kthread_work		pump_messages;	// 具体的工作,即发送spi消息
	struct list_head		queue;			// 所有等待传输的消息队列挂在该链表下
	struct spi_message		*cur_msg;
	
	...
	int (*transfer_one)(struct spi_controller *ctlr, struct spi_device *spi,struct spi_transfer *transfer);
	int (*prepare_transfer_hardware)(struct spi_controller *ctlr);
	// 发送一个spi消息,类似IIC适配器里的algo->master_xfer,产生spi通信时序
	int (*transfer_one_message)(struct spi_controller *ctlr,struct spi_message *mesg);
	void (*set_cs)(struct spi_device *spi, bool enable);
	...
	
	int			*cs_gpios;	// 数组,负责记录此spi设备上具体的片选信号线所对应的gpio
} // 一个结构体代表一个spi控制器,多个控制器通过其list_head链表节点串连起来

spi主机设备也被当成spi设备挂载在spi总线上。 

相关API

        int spi_register_master(struct spi_master *master):注册一个spi_controller。

        int spi_unregister_master(struct spi_master *master):注销一个spi_controller。

spi设备驱动:spi_device结构体、spi_driver结构体

代码存放在内核/include/linux/spi/spi.h文件。

struct spi_device {
	struct device		dev;				// 继承
	struct spi_controller	*controller;	// 当前的spi设备属于哪一个spi主控制器,一个主控器下面可能有多个spi设备
	struct spi_controller	*master;		/* compatibility layer */
	
	u32			max_speed_hz;				// 此spi最大的通信速率:Maximum clock rate to be used with this chip	
	u8			chip_select;				// 片选
	u8			bits_per_word;				// 传输单位,8或16,由此成员来制定
	u16			mode;						// 重要,指定四大模式中的哪一个
	
	// 下面的宏都是用来设置spi设备某方面的具体属性
	#define	SPI_CPHA	0x01				/* clock phase */
	#define	SPI_CPOL	0x02				/* clock polarity */
	#define	SPI_MODE_0	(0|0)				/* (original MicroWire) */
	#define	SPI_MODE_1	(0|SPI_CPHA)
	#define	SPI_MODE_2	(SPI_CPOL|0)
	#define	SPI_MODE_3	(SPI_CPOL|SPI_CPHA)
	#define	SPI_CS_HIGH	0x04				/* chipselect active high? */
	#define	SPI_LSB_FIRST	0x08			/* per-word bits-on-wire */
	#define	SPI_3WIRE	0x10				/* SI/SO signals shared */
	#define	SPI_LOOP	0x20				/* loopback mode */
	#define	SPI_NO_CS	0x40				/* 1 dev/bus, no chipselect */
	#define	SPI_READY	0x80				/* slave pulls low to pause */
	#define	SPI_TX_DUAL	0x100				/* transmit with 2 wires */
	#define	SPI_TX_QUAD	0x200				/* transmit with 4 wires */
	#define	SPI_RX_DUAL	0x400				/* receive with 2 wires */
	#define	SPI_RX_QUAD	0x800				/* receive with 4 wires */
...
	
	char		modalias[SPI_NAME_SIZE];	// spi设备的名字,用于和spi_driver配对
...
}	// 此结构体表示一个spi设备的具体属性。

struct spi_driver {
	const struct 	spi_device_id *id_table;			// 记录这此driver支持的设备列表,用来和spi_device配对
	int				(*probe)(struct spi_device *spi);	// spi设备和spi驱动匹配后,回调该函数指针
	int				(*remove)(struct spi_device *spi);	// Unbinds this driver from the spi device
	void			(*shutdown)(struct spi_device *spi);
	
	// 继承,SPI device drivers should initialize the name and owner field of this structure.
	struct device_driver	driver;
};

相关API

        int spi_register_driver(struct spi_driver *sdrv):注册一个spi驱动。

        int spi_unregister_driver(struct spi_driver *sdrv):注销一个spi驱动。

spi总线注册:spi_init()

该函数存放于内核/drivers/spi/spi.c文件。在linux系统中上电自动运行。

// 开机自动运行
static int __init spi_init(void)
{
	int	status;
	...
	
	status = bus_register(&spi_bus_type);          // 注册spi总线,完成后在/sys目录下新增目录 /sys/bus/spi
	...
	
	status = class_register(&spi_master_class);    // 注册设备类,完成后在/sys目录下新增目录sys/class/spi_master
	...
}

spi总线定义:spi_bus_type

struct bus_type spi_bus_type = {
	.name		= "spi",
	.dev_groups	= spi_dev_groups,
	.match		= spi_match_device,    // 设备和驱动匹配规则
	.uevent		= spi_uevent,
};

static int spi_match_device(struct device *dev, struct device_driver *drv)
{
	const struct spi_device	*spi = to_spi_device(dev);
	const struct spi_driver	*sdrv = to_spi_driver(drv);

	/* Attempt an OF style match */
	if (of_driver_match_device(dev, drv))
		return 1;

	/* Then try ACPI */
	if (acpi_driver_match_device(dev, drv))
		return 1;

	if (sdrv->id_table)
		return !!spi_match_id(sdrv->id_table, spi);

	return strcmp(spi->modalias, drv->name) == 0;
}

spi控制器驱动

设备树节点

4个spi设备树节点存放在内核/arch/arm/boot/dts/imx6ull.dtsi。设备树文件中的4个spi控制器节点对应芯片的4个spi控制器。例如:

ecspi3: ecspi@2010000 {
					// 设置reg属性格式
					#address-cells = <1>;
					#size-cells = <0>;
					// 对应驱动文件为 spi-imx.c
					compatible = "fsl,imx6ul-ecspi", "fsl,imx51-ecspi";
					// 起始地址 寄存器组长度
					reg = <0x2010000 0x4000>;
					interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
					clocks = <&clks IMX6UL_CLK_ECSPI3>,
						     <&clks IMX6UL_CLK_ECSPI3>;
					clock-names = "ipg", "per";
					dmas = <&sdma 7 7 1>, <&sdma 8 7 2>;
					dma-names = "rx", "tx";
					status = "disabled";
				};

module_platform_driver()宏

该宏存放在内核/include/linux/platform_device.h文件。

// 参数2 3:注册,注销平台驱动
#define module_platform_driver(__platform_driver) \
	module_driver(__platform_driver, platform_driver_register, platform_driver_unregister)

//该宏定义在内核/include/linux/device.h文件
#define module_driver(__driver, __register, __unregister, ...) \
		static int __init __driver##_init(void) \
		{ \
			return __register(&(__driver) , ##__VA_ARGS__); \
		} \
		module_init(__driver##_init); \

//上诉等价于下方
static int __init spi_imx_driver_init(void) 
{ 
	return platform_driver_register(&(spi_imx_driver) , ##__VA_ARGS__); 
} 
module_init(spi_imx_driver_init); 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【LeetCode-中等题】210. 课程表 II

文章目录 题目方法一&#xff1a;bfs方法二&#xff1a;dfs 题目 这一题是在207题的基础上&#xff0c;要统计拓扑排序的顺序集合&#xff0c;所以只需要在207的基础上加入一个将拓扑排序的节点输出即可&#xff08;有环无拓扑排序&#xff09; 【LeetCode-中等题】207. 课程表…

LeetCode--HOT100题(47)

目录 题目描述&#xff1a;105. 从前序与中序遍历序列构造二叉树&#xff08;中等&#xff09;题目接口解题思路代码 PS: 题目描述&#xff1a;105. 从前序与中序遍历序列构造二叉树&#xff08;中等&#xff09; 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preo…

本地缓存、Redis数据缓存策略

目录 需求看似简单&#xff0c;一取一传但是&#xff0c;又出现了一个新的问题&#xff0c;数据丢了。 一、缓存缓存有哪些分类&#xff1a; 二、分析一下本地缓存的优势三、本地缓存解决方案&#xff1f;1、基于Guava Cache实现本地缓存2、基于Caffeine实现本地缓存3、基于Enc…

华为OD机试-机器人走迷宫

题目描述 机器人走一个迷宫,给出迷宫的x和y(x*y的迷宫)并且迷宫中有障碍物,输入k表示障碍物有k个,并且会将障碍物的坐标挨个输入. 机器人从0,0的位置走到x,y的位置并且只能向x,y增加的方向走,不能回退. 如代码类注释展示的样子,#表示可以走的方格,0代表障碍,机器人从0,0的位置…

【传输层】TCP -- 三次握手四次挥手 | 可靠性与提高性能策略

超时重传机制连接管理机制三次握手四次挥手滑动窗口拥塞控制延迟应答捎带应答面向字节流粘包问题TCP异常情况TCP小结基于TCP应用层协议理解 listen 的第二个参数 超时重传机制 主机A发送数据给B之后&#xff0c;可能因为网络拥堵等原因&#xff0c;数据无法到达主机B&#xff1…

日志规范整改

日志框架 日志级别 日志级别从高到低&#xff1a;TRACE < DEBUG < INFO < WARN < ERROR < FATAL 获取应用名字 <springProperty scop"context" name"spring.application.name" source"spring.application.name" defaultVal…

电子行业数字化工厂管理系统规划方案

电子行业作为现代社会的重要产业之一&#xff0c;具有十分广泛的应用前景和市场前景。随着科技的不断进步和消费者需求的不断升级&#xff0c;电子行业面临着不断提升产品品质、提高生产效率、降低成本等挑战。为了应对这些挑战&#xff0c;数字化工厂管理系统成为了电子行业不…

(10)(10.8) 固件下载

文章目录 ​​​​​​​前言 10.8.1 固件 10.8.2 Bootloader 10.8.3 APM2.x Autopilot 10.8.4 许可证 10.8.5 安全 前言 固件服务器(firmware server)可提供所有飞行器的最新固件。其中包括&#xff1a; CopterPlaneRoverAntennaTrackerSub 本页提供了一些被视为&quo…

考研408 | 【计算机组成原理】计算机系统的概述

计算机的发展 硬件的发展&#xff1a; 摩尔定律&#xff1a; 微处理机的发展&#xff1a; 软件的发展&#xff1a; 发展趋势&#xff1a; 总结&#xff1a; 计算机硬件的基本组成 早期的冯诺依曼机&#xff1a; 现代计算机的结构&#xff1a; 总结&#xff1a; 各个硬件的工作…

Flutter 完美的验证码输入框 转载

刚开始看到这个功能的时候一定觉得so easy&#xff0c;开始的时候我也是这么觉得的&#xff0c;这还不简单&#xff0c;然而真正写的时候才发现并没有想象的那么简单。 先上图&#xff0c;不上图你们都不想看&#xff0c;我难啊&#xff0c;到Github&#xff1a; https://gith…

macOS通过钥匙串访问找回WiFi密码

如果您忘记了Mac电脑上的WiFi密码&#xff0c;可以通过钥匙串访问来找回它。具体步骤如下&#xff1a; 1.打开Mac电脑的“启动台”&#xff0c;然后在其他文件中找到“钥匙串访问”。 2.运行“钥匙串访问”应用程序&#xff0c;点击左侧的“系统”&#xff0c;然后在右侧找到…

R语言+Meta分析;论文新方向

Meta分析是针对某一科研问题&#xff0c;根据明确的搜索策略、选择筛选文献标准、采用严格的评价方法&#xff0c;对来源不同的研究成果进行收集、合并及定量统计分析的方法&#xff0c;最早出现于“循证医学”&#xff0c;现已广泛应用于农林生态&#xff0c;资源环境等方面。…

【HTML5高级第一篇】Web存储 - cookie、localStorage、sessionStorage

文章目录 一、数据存储1.1 cookie1.1.1 概念介绍1.1.2 存储与获取1.1.3 方法的封装1.1.4 总结 1.2 localstorage 与 sessionstorage1.2.1 概述1.2.2 操作数据的属性或方法1.2.3 案例-提交问卷1.2.4 Web Storage带来的好处 附录&#xff1a;1. HTML5提供的数据持久化技术&#x…

无代码集成铱云(易订货)连接更多应用

场景描述&#xff1a; 基于铱云开放API能力&#xff0c;无代码集成铱云连接多个应用&#xff0c;实现客户管理、电商数智化、供应链生态管理等。通过Aboter搭建业务自动化流程&#xff0c;实现多个应用的数据集成。 接口能力&#xff1a; 基础数据客户接口商品接口订单接口退…

ASP.NET Core IOC容器

//IOC容器支持依赖注入{ServiceCollection serviceDescriptors new ServiceCollection();serviceDescriptors.AddTransient<IMicrophone, Microphone>();serviceDescriptors.AddTransient<IPower, Power>();serviceDescriptors.AddTransient<IHeadphone, Headp…

量化自定义PyTorch模型入门教程

在以前Pytorch只有一种量化的方法&#xff0c;叫做“eager mode qunatization”&#xff0c;在量化我们自定定义模型时经常会产生奇怪的错误&#xff0c;并且很难解决。但是最近&#xff0c;PyTorch发布了一种称为“fx-graph-mode-qunatization”的方方法。在本文中我们将研究这…

【JAVA】多态

作者主页&#xff1a;paper jie_的博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文录入于《JAVASE语法系列》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和…

【Sentinel】ProcessorSlotChain处理器插槽链与Node

文章目录 1、Sentinel的基本概念2、ProcessorSlotChain3、Node 1、Sentinel的基本概念 Sentinel实现限流、隔离、降级、熔断等功能&#xff0c;本质要做的就是两件事情&#xff1a; 统计数据&#xff1a;统计某个资源的访问数据&#xff08;QPS、RT等信息&#xff09;规则判断…

FPGA输出lvds信号点亮液晶屏

1 概述 该方案用于生成RGB信号&#xff0c;通过lvds接口驱动逻辑输出&#xff0c;点亮并驱动BP101WX-206液晶屏幕。 参考&#xff1a;下面为参考文章&#xff0c;内容非常详细。Xilinx LVDS Output——原语调用_vivado原语_ShareWow丶的博客http://t.csdn.cn/Zy37p 2 功能描述 …

从零开始学习 Java:简单易懂的入门指南之Collection集合及list集合(二十一)

Collection集合及list集合 1.Collection集合1.1数组和集合的区别1.2集合类体系结构1.3Collection 集合概述和使用1.4Collection集合的遍历1.4.1 迭代器遍历1.4.2 增强for1.4.3 lambda表达式 2.List集合2.1List集合的概述和特点2.2List集合的特有方法2.3List集合的五种遍历方式2…