昆明移动网站建设,网站开发怎么才能接到私活,东营网站seo顾问,app软件设计公司1.spi总线
spi总线分为硬件spi总线和软件模拟spi总线。 按照面向对象的思想#xff0c;要抽象出硬件spi总线和软件spi总线的相同点和不同点。相同点就变成了spi总线基类#xff0c;不同点就是各个子类的私有特性。
rtt就是这么干的#xff0c;共同点是什么#xff1f;方法…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方法。
缺图对象图 1bus—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.使用
官方文档说的就是如何使用的文档而上面学的是分析注册/初始化/构造流程。