rtt设备io框架面向对象学习-spi总线和设备

1.spi总线

spi总线分为硬件spi总线和软件模拟spi总线。
按照面向对象的思想,要抽象出硬件spi总线和软件spi总线的相同点和不同点。相同点就变成了spi总线基类,不同点就是各个子类的私有特性。

rtt就是这么干的,共同点是什么?方法——都得有spi配置方法和数据传输方法等,于是抽象出了spi的方法
struct rt_spi_ops
{
rt_err_t (*configure)(struct rt_spi_device *device, struct rt_spi_configuration *configuration); rt_ssize_t (*xfer)(struct rt_spi_device *device, struct rt_spi_message *message);
};

然后作为成员组成rt_spi_bus类:
struct rt_spi_bus
{
struct rt_device parent;
rt_uint8_t mode;
const struct rt_spi_ops *ops;
struct rt_mutex lock;
struct rt_spi_device *owner;
};

缺图对象图,ops展开方法用纯虚方法表示或者指针,但ops展开后成为一个个纯虚方法更为贴切。

1.1硬件spi总线子类

对于硬件spi子类,则负责实现rt_spi_bus的ops操作方法。

缺图对象图,ops展开的一个个方法用虚方法表示或者普通方法即可,意味着重写父类方法。

1.1.1实例

bsp / stm32 / libraries / HAL_Drivers / drivers 下的
drv_spi.h
drv_spi.c
在drv_spi.h 中定义了可以实例化的硬件spi总线类:

struct stm32_spi
{
SPI_HandleTypeDef handle;
struct stm32_spi_config *config;
struct rt_spi_configuration *cfg;
struct
{
DMA_HandleTypeDef handle_rx; DMA_HandleTypeDef handle_tx;
} dma;
rt_uint8_t spi_dma_flag;
**struct rt_spi_bus spi_bus; **
struct rt_completion cpt;
};

其实把struct rt_spi_bus spi_bus; 放到倒数第二个位置我是不满的,如果把它放到第一个成员,和rtt的io框架更加具有一致性。如改成这样

struct stm32_spi
{
**struct rt_spi_bus spi_bus; **
SPI_HandleTypeDef handle;
struct stm32_spi_config *config;
struct rt_spi_configuration *cfg;
struct
{
DMA_HandleTypeDef handle_rx; DMA_HandleTypeDef handle_tx;
} dma;
rt_uint8_t spi_dma_flag;
struct rt_completion cpt;
};
这样看着更舒服。

drv_spi.c实现了spi总线基类的方法如下
static const struct rt_spi_ops stm_spi_ops =
{
.configure = spi_configure,
.xfer = spixfer,
};

drv_spi.c的rt_hw_spi_bus_init函数中通过调用rt_spi_bus_register函数从而开启了spi硬件总线子类对象的实例化或构造流程。最终结果是初始化了下spi硬件总线的实例化的结构体——包含spi总线基类的结构体,最终放到对象容器的链表里去管理。等待使用者拿出来使用。万事俱备只欠东风。

1.2 软件spi总线基类

对于软件spi总线基类,差异点就是要用gpio模拟硬件spi的4线或3线通信,那么软件gpio除了实现上面共同点ops操作方法外,还得抽象软件spi通信。
于是抽象出spi软总线基类——rt_spi_bit_obj。

/ components / drivers / spi / spi-bit-ops.h中定义

struct rt_spi_bit_obj
{
struct rt_spi_bus bus;
struct rt_spi_bit_ops *ops;
struct rt_spi_configuration config;
};

因为有共同点所以直接继承rt_spi_bus基类,它的差异点抽象出了rt_spi_bit_ops操作方法以实现gpio模拟spi通信。

struct rt_spi_bit_ops
{ void data; / private data for lowlevel routines */
void (*const tog_sclk)(void *data);
void (*const set_sclk)(void *data, rt_int32_t state); void (*const set_mosi)(void *data, rt_int32_t state);
void (*const set_miso)(void *data, rt_int32_t state);
rt_int32_t (*const get_sclk)(void *data); rt_int32_t (*const get_mosi)(void *data); rt_int32_t (*const get_miso)(void *data);
void (*const dir_mosi)(void *data, rt_int32_t state);
void (*const dir_miso)(void *data, rt_int32_t state); void (const udelay)(rt_uint32_t us);
rt_uint32_t delay_us; /
sclk, mosi and miso line delay */
};

这个抽象出的方法作为软件spi总线类rt_spi_bit_obj的成员,为何还要抽象出来?因为下面还有个子类——具体硬件厂家的软件spi总线——因为各个硬件操作gpio具体实现是不同的,但是这些方法是都一样,所以抽象出来——跨硬件平台,这个框架才叫框架,这个框架才有意义。

接着就是硬件spi软总线层次了,各个厂家bsp创建各自的软spi总线子类对象,实现软件spi基类的ops方法。

缺图对象图,
(1)bus—>ops展开的一个个方法用虚方法表示或者普通方法即可,意味着重写父类spi总线基类的方法。
(2)软spi总线子类的ops展开的一个个方法用纯虚方法表示或者指针,但ops展开后成为一个个纯虚方法更为贴切。

1.2.1实例

bsp / stm32 / libraries / HAL_Drivers / drivers 下的drv_soft_spi.h
drv_soft_spi.c

在drv_soft_spi.h 中定义了可以实例化的软件spi总线类:
struct stm32_soft_spi
{
struct rt_spi_bit_obj spi;
struct rt_spi_bit_ops ops;
struct stm32_soft_spi_config *cfg;
};

可以看到struct stm32_soft_spi类继承自spi软总线基类
struct rt_spi_bit_obj spi;
第二个成员是spi软总线基类中定义的方法,struct rt_spi_bit_ops ops; ,又在struct stm32_soft_spi
这里开个成员专门承载它,重复,但是为了给软总线基类的方法赋值。
第三个成员是配置。

在drv_soft_spi.c中重写了spi软总线基类定义的方法
rt_spi_bit_ops ops,如下:
stm32_tog_sclk
stm32_set_sclk
stm32_set_mosi
stm32_get_sclk
stm32_get_mosi
stm32_dir_mosi
stm32_dir_miso
stm32_udelay

static struct rt_spi_bit_ops stm32_soft_spi_ops =
{
.data = RT_NULL,
.tog_sclk = stm32_tog_sclk,
.set_sclk = stm32_set_sclk,
.set_mosi = stm32_set_mosi,
.set_miso = stm32_set_miso,
.get_sclk = stm32_get_sclk,
.get_mosi = stm32_get_mosi,
.get_miso = stm32_get_miso,
.dir_mosi = stm32_dir_mosi,
.dir_miso = stm32_dir_miso,
.udelay = stm32_udelay,
.delay_us = 1,
};

rt_hw_softspi_init函数调用rt_spi_bit_add_bus开启struct stm32_soft_spi类的实例化/构造流程。

2.spi设备

上面spi总线基类

struct rt_spi_bus
{
struct rt_device parent;
rt_uint8_t mode;
const struct rt_spi_ops *ops;
struct rt_mutex lock;
struct rt_spi_device *owner;
};

其中“struct rt_spi_device *owner”,这是spi设备对象指针,为何在spi总线里加个spi设备的指针成员,且还叫owner(字面意思:spi总线持有者或霸占者或拥有者)?
用面向对象的思想来分析下,spi总线和spi设备是啥关系?可以搜下面向对象思想中对象关系有哪些,有包含(拥有)关系,聚合关系,关联关系等等。而spi总线和spi设备就是关联关系吧。谁关联谁?我觉得是互相关联吧。你看,它们的关系特点:一个spi总线上可以挂载很多个spi设备,同一时刻,一个spi总线只能和一个spi设备通信,这样看来同一个spi总线上的spi设备是分时共享这个spi总线的,spi设备之间是有竞争关系的,spi总线就相当于共享资源,同一时刻只能有一个spi设备霸占。所以上面抽象出的spi总线基类里有一个owner标志,表示当前是哪个spi设备在使用/霸占/持有spi总线。那当然还得有把锁来处理这个竞争关系。
那么同样的,spi设备里肯定也有一个指针指向它挂载到那个spi总线上了——因为它们是关联关系。
于是看下rtt抽象出的spi设备类rt_spi_device定义:
struct rt_spi_device
{
struct rt_device parent;
struct rt_spi_bus *bus;
struct rt_spi_configuration config;
rt_base_t cs_pin;
void *user_data;
};

果然不出所料,有个spi总线基类指针来表明该spi设备挂载到哪个spi总线上了。

spi设备初始化/注册/构造:
spi_core.c 中的rt_spi_bus_attach_device_cspin函数,它会调用spi_dev.c中的rt_spidev_device_init函数。这样它会创建spi设备,然后根据name找到spi总线,把spi总线指针保存到上面bus成员里,其实就是绑定spi设备和spi总线,实现关联关系。

到bsp的驱动层,一般都会分别实现软硬总线的spi设备构造接口,但是其实spi设备的构造实现最终都是调用spi_core.c 中的rt_spi_bus_attach_device_cspin函数来开启的。因为spi设备其实不区分软硬,只是spi设备对象里的bus指向是软还是硬总线是不同的。。

缺对象图。

实例:
bsp / stm32 / libraries / HAL_Drivers / drivers 下的drv_spi.h
drv_spi.c
drv_soft_spi.h
drv_soft_spi.c

drv_spi.c定义了硬件spi总线类的设备构造函数rt_hw_spi_device_attach来实现挂载到硬件spi总线的spi设备实例化。
drv_soft_spi.c定义了软件spi总线类的设备构造函数rt_hw_softspi_device_attach来实现挂载到软件spi总线的spi设备实例化。
其实它们的实现都是对rt_spi_bus_attach_device_cspin的封装,直接用rt_spi_bus_attach_device_cspin来实例化挂载到软硬件spi总线上的设备没啥区别。
当然前提是对应的spi总线对象已经实例化了。

3.相关文件

/ components / drivers / spi 下
spi-bit-ops.c
spi-bit-ops.h
spi_core.c
spi_dev.c

spi_dev.c是spi总线基类和spi设备基类的注册地,
rt_spi_bus_device_init
rt_spidev_device_init
实现对rt_device基类的注册,核心是重写父类rt_device的init/read等方法。
从spi总线基类和spi设备基类的重写方法实现上看,它们都调用的是rt_spi_transfer函数。

rt_spi_transfer在哪里?在spi_core.c 里,看它的实现最终调用的是:
device->bus->ops->configure
device->bus->ops->xfer
也就是spi总线基类对子类定义(约束)的方法。
就是从这里出现了跳转,分支,岔路:
(1)对于spi软总线子类来说,调用的是spi-bit-ops.c中定义的方法:
static const struct rt_spi_ops spi_bit_bus_ops =
{
.configure = spi_bit_configure,
.xfer = spi_bit_xfer,
};
spi_bit_xfer函数中调用的软总线基类对其子类定义的struct rt_spi_bit_ops方法,这些方法就是操作4线或3线的引脚高低电平操作,还有us延时,这些由bsp驱动层来实现,我想可以参照软件i2c总线,利用pin设备来实现自洽。

(2)对于硬件spi子类(bsp驱动层实现)来说,走的是各个bsp实现的硬件spi传输。

另外在spi_core.c 中开启spi总线基类和spi设备初始化的接口:
rt_spi_bus_register
rt_spi_bus_attach_device_cspin

rt_spi_bus_register函数会调用spi_dev.c中的rt_spi_bus_device_init。

rt_spi_bus_attach_device_cspin函数会调用spi_dev.c中的rt_spidev_device_init函数。

从以上分析看,spi_core.c 是个中转站/中间人/跳板/跳转点/分发站。

4.使用

官方文档说的就是如何使用的文档,而上面学的是分析注册/初始化/构造流程。

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

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

相关文章

精品springboot疫苗发布和接种预约系统

《[含文档PPT源码等]精品基于springboot疫苗发布和接种预约系统[包运行成功]》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功! 软件开发环境及开发工具: Java——涉及技术: 前端使用技术:…

代码随想录算法训练营第四十九天(动态规划篇)| 474. 一和零, 完全背包理论基础

474. 一和零 题目链接:https://leetcode.cn/problems/ones-and-zeroes/submissions/501607337/ 思路 之前的背包问题中,我们对背包的限制是容量,即每个背包装的物品的重量和不超过给定容量,这道题的限制是0和1的个数&#xff0…

基于微信小程序的在线课堂的研究与实现,附源码

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…

fast.ai 机器学习笔记(四)

机器学习 1:第 11 课 原文:medium.com/hiromi_suenaga/machine-learning-1-lesson-11-7564c3c18bbb 译者:飞龙 协议:CC BY-NC-SA 4.0 来自机器学习课程的个人笔记。随着我继续复习课程以“真正”理解它,这些笔记将继续…

类与结构体(5)

上期我们提到了这一期讲“类该怎么用?(2)/(3)”。 类该怎么用?(2)—— 友元函数 类的友元函数不创建在类里,但他可以访问private,protected。友元函数要先在类里面声明&…

移动光猫gs3101超级密码及改桥接模式教程

文章目录 超级管理员账号改桥接模式路由器连接光猫,PPPOE拨号即可!附录:如果需要改桥接的话不知道拨号密码咋办打开光猫Telnet功能Telnet 登录 参考文章 移动光猫吉比特GS3101超级账号获取更改桥接 移动光猫gs3101超级密码及改桥接模式教程 …

(2)长距离

文章目录 2.1 Andruav Android Cellular 2.2 Blicube RLINK P900 2.3 ClearSky Airlink 4G LTE遥测技术 2.4 CRSF/ELRS Telemetry 2.5 CUAV P8 Radio 2.6 CUAV P9 Radio 2.7 DragonLink 2.8 Holybro 900Mhz XBP9X无线电遥测设备 2.9 Holybro Microhard P900无线电遥测…

Idea Git Review插件

idea git plugin 添加了一些常用的小插件 可以右键打开git bash窗口 可以右键选中文字点击baidu fanyi 可以通过搜索git用户名 指定开始时间查询某个版本自己提交的所有代码文件 可以通过点击蓝色行数,跳转到指定的改动代码块 资源地址: git-pl…

flask+python高校学生综合测评管理系统 phl8b

系统包括管理员、教师和学生三个角色; 。通过研究,以MySQL为后端数据库,以python为前端技术,以pycharm为开发平台,采用vue架构,建立一个提供个人中心、学生管理、教师管理、课程类型管理、课程信息管理、学…

【XR806开发板试用】轻松连上华为云实现物联网

本文为极术社区XR806试用活动文章。 一.开始 偶然的机会在网上看到了鸿蒙开发板的试用,作为一个"老鸿蒙"岂能放弃这个机会,报名之后不出意料地得到了使用名额,在此感谢极术社区. 收到开发板之后其实还有点失望了,就那么一个小小的核心板,其他啥也没有,连一根数据线…

AI跟踪报道第28期-新加坡内哥谈技术-本周AI新闻:Gemini Ultra 来了

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

(十)Java 之 Character 类

目录 一. 前言 二. 实例讲解 2.1. 内置数据类型(char) 2.2. 装箱/拆箱 2.3. 转义序列 2.4. Character 方法 2.5. Character 常量 三. 课后习题 一. 前言 Character 类用于对单个字符进行操作,Character 类在对象中包装一个基本类型 c…

C++ //练习 5.18 说明下列循环的含义并改正其中的错误。

C Primer&#xff08;第5版&#xff09; 练习 5.18 练习 5.18 说明下列循环的含义并改正其中的错误。 (a) doint v1, v2;cout<<"Please enter two numbers to sum: ";if(cin>>v1>>v2)cout<<"Sum is: "<<v1 v2<<end…

Vulnhub靶机:hacksudo-ProximaCentauri

一、介绍 运行环境&#xff1a;Virtualbox 攻击机&#xff1a;kali&#xff08;10.0.2.15&#xff09; 靶机&#xff1a;hacksudo-ProximaCentauri&#xff08;10.0.2.51&#xff09; 目标&#xff1a;获取靶机root权限和flag 靶机下载地址&#xff1a;https://www.vulnhu…

Java中 Iterator接口的作用

什么是Iterator接口&#xff1f;它有什么作用&#xff1f; Iterator接口是Java集合框架中的一个重要接口&#xff0c;它提供了一种遍历集合中元素的标准方式。这个接口隐藏了不同集合类的具体实现细节&#xff0c;使得我们能够在不同的集合类之间进行切换而不需要修改代码&…

STM32 7-8

目录 ADC AD单通道 AD多通道 DMA DMA转运数据 DMAAD多通道 ADC AD单通道 AD.c #include "stm32f10x.h" // Device header/*** brief 初始化AD所需要的所有设备* param 无* retval 无*/ void AD_Init(void) {RCC_APB2PeriphClockCmd(RCC_AP…

Java 集合、迭代器

Java 集合框架主要包括两种类型的容器&#xff0c;一种是集合&#xff08;Collection&#xff09;&#xff0c;存储一个元素集合&#xff0c;另一种是图&#xff08;Map&#xff09;&#xff0c;存储键/值对映射。Collection 接口又有 3 种子类型&#xff0c;List、Set 和 Queu…

使用Cargo创建、编译与运行Rust项目

在 Rust 开发中&#xff0c;Cargo 是一个非常重要的工具&#xff0c;它负责项目的构建、管理和依赖管理。以下是如何使用 Cargo 创建、编译和运行 Rust 项目的详细步骤。 1. 创建新项目 首先确保你已经在计算机上安装了 Rust 和 Cargo。然后&#xff0c;在命令行中输入以下命…

Github 2024-02-12 开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2024-02-12统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Rust项目3Python项目3JavaScript项目1TypeScript项目1C项目1C项目1PowerShell项目1非开发语言项目1 SubQuery…

未来游戏制作的创新趋势与发展方向

随着科技的发展和社会变迁&#xff0c;游戏制作行业正经历一场深刻的变革。从早期的像素图形到现代的高清视觉盛宴&#xff0c;从简单的2D玩法到复杂的3D虚拟世界&#xff0c;再到混合现实与人工智能的深度融合&#xff0c;未来的游戏制作将呈现出更加丰富多元和智能化的面貌。…