基于硬件 SPI 的数据抽象实例(附代码)

💡 原文中文,约10600字,阅读约需26分钟。
📝

内容提要

SPI(Serial Peripheral Interface)是一种串行外围接口,常用于嵌入式开发中的外设通信总线。SPI总线抽象的外部接口包括spi_send_then_recv、spi_send_then_send、spi_send_recv和spi_send等函数。spi_send_then_recv函数用于发送完一帧数据后再接收一帧数据,spi_send_then_send函数用于发送完一帧数据后再发送一帧数据,spi_send_recv函数用于同时发送和接收数据,spi_send函数用于只发送数据。SPI总线抽象的底层实现需要初始化spi总线和相关硬件配置。文章还介绍了如何使用SPI抽象驱动25aa256 EEPROM设备。

🔎

延伸解读

分层设计的关键:结构体与函数指针

文章通过 struct spi_dev_device 和 struct spi_bus_device 两个结构体,将 SPI 设备与总线分离。设备层包含片选函数指针和总线指针,总线层包含收发函数指针、物理 SPI 指针和数据宽度。这种设计使得更换 MCU 或改用模拟 SPI 时,只需修改总线层的函数实体,上层设备驱动和 API 调用无需变动,体现了硬件抽象层的基本思路。

四个 API 覆盖常见 SPI 时序

spi_send_then_recv 用于先发后收(如读寄存器),spi_send_then_send 用于连续发送(如写寄存器),spi_send_recv 用于全双工同时收发或只收(发送仅提供时钟),spi_send 用于只发不收。文章指出,非标准 SPI 大多也能用这四个接口实现,作者称目前用过的器件均可覆盖。这为驱动不同外设提供了统一的调用方式。

底层实现与配置注意事项

以 STM32 为例,spi_bus_xfer 函数负责片选控制和数据收发,支持 8 位或 16 位模式。初始化时需注意:SPI 模式根据器件时序图选择,常用模式 0 或 3;片选必须配置为软件控制(SPI_NSS_Soft);设置为全双工模式以兼容标准和非标准 SPI。这些细节直接影响通信可靠性,是移植时容易忽略的地方。

驱动外设的流程与移植性

以 25aa256 EEPROM 为例,驱动步骤包括:定义设备与总线结构体、实现片选函数、初始化总线并注册设备,然后调用四个 API 完成读写。移植到新平台时,器件驱动几乎无需修改,只需替换底层总线函数。文章还演示了同一总线挂载多个外设的方法:共用已初始化的总线指针,但每个设备需独立定义片选函数。

❓

Q&A

SPI总线抽象的主要目的是什么?

SPI总线抽象的主要目的是将SPI总线与SPI设备分离,快速使用新的硬件SPI或模拟SPI,并方便将SPI总线设备和外设程序移植到不同的MCU平台。

SPI总线抽象提供了哪些外部接口函数?

提供了四个函数:spi_send_then_recv(发送完一帧再接收)、spi_send_then_send(发送完一帧再发送)、spi_send_recv(同时发送和接收)、spi_send(只发送)。

spi_send_then_recv函数是如何工作的?

该函数先发送一帧数据(此时片选拉低,不释放),然后接收一帧数据(发送空数据以产生时钟,接收完成后释放片选)。

struct spi_dev_device结构体包含哪些成员?

包含两个成员:spi_cs函数指针(用于片选控制)和spi_bus指针(指向spi_bus_device结构体,用于底层收发)。

如何以STM32为例实现SPI总线的底层收发?

实现spi_bus_xfer函数指针,在函数中根据msg的cs_take和cs_release控制片选,根据data_width进行8位或16位数据收发,使用SPI_I2S_SendData和SPI_I2S_ReceiveData等函数。

使用SPI抽象驱动25aa256 EEPROM的步骤是什么?

首先定义spi_dev_device和spi_bus_device结构体,实现片选函数,初始化IO和SPI总线,然后通过spi_send、spi_send_then_send、spi_send_then_recv等API进行读写操作。

SPI总线抽象分层是如何实现的?

通过结构体和函数指针实现:spi_dev_device包含片选函数指针和总线指针,spi_bus_device包含底层收发函数指针和物理SPI指针,上层API调用这些指针完成操作。

🏷️

标签

➡️

继续阅读