上节写了对于IIC设备的面向对象写法面向对象编程思想--IIC设备(EEPROM AND MPU6050)-CSDN博客面向对象编程思想--IIC设备(EEPROM AND MPU6050)-CSDN博客
NorFlash、RC522、LCD屏幕,这些都是常见的SPI设备,但各自有不同的操作需求。例如,NorFlash通常需要读写数据块,RC522是RFID读卡器,涉及特定的命令和数据处理,而LCD屏幕可能需要发送大量的显示数据,可能涉及不同的传输模式(如DMA)。因此,SPI的驱动层需要足够的灵活性来处理不同的设备需求。
SPI是全双工、主从模式,通常有更高的传输速率,需要处理片选信号(CS)、时钟极性(CPOL)和相位(CPHA)等参数。因此,在驱动层结构体中,需要包含这些配置参数,以及可能的传输模式(轮询、中断、DMA)。包括SPI设备的片选信号管理,每个设备可能有不同的CS引脚,所以在设备结构体中需要包含GPIO的控制。另外,SPI的传输函数需要考虑不同的数据长度和传输模式,可能需要提供阻塞和非阻塞的接口。
事件驱动模型方面,SPI的传输完成可能通过中断或DMA回调触发,所以需要类似I2C的事件处理机制,比如传输完成事件,然后分发给各个设备的事件处理函数。
在具体设备实现部分,比如NorFlash可能需要实现扇区擦除、页写入等操作;RC522需要处理ISO14443协议相关的命令;LCD屏幕则需要初始化命令、设置显示区域等。这些设备特有的方法应该封装在各自的设备结构体中,并继承自SPI设备基类。
总结一下,所抽象的结构体应该包括:SPI驱动结构体、设备基类结构体、具体设备结构体(NorFlash、RC522、LCD)、驱动层实现、设备层实现、事件处理等等,注意SPI特有的配置和操作,比如片选控制和传输模式。
上代码:
#include "stm32f1xx_hal.h"
#include
/* 事件类型定义 */
typedef enum {
EVENT_SPI_TX_COMPLETE,
EVENT_SPI_RX_COMPLETE,
EVENT_SPI_ERROR,
EVENT_TIMER
} SPI_EventType;
/* SPI驱动结构体(抽象层) */
typedef struct {
SPI_HandleTypeDef *hspi; // HAL SPI句柄
GPIO_TypeDef *cs_port; // 公共CS端口(可选)
uint16_t cs_pin; // 公共CS引脚
uint32_t timeout; // 阻塞操作超时
// 方法抽象
int (*init)(struct SPIDriver *driver);
int (*transmit)(struct SPIDriver *driver, uint8_t *txData, uint16_t size);
int (*receive)(struct SPIDriver *driver, uint8_t *rxData, uint16_t size);
int (*transmitReceive)(struct SPIDriver *driver, uint8_t *txData,
uint8_t *rxData, uint16_t size);
} SPIDriver;
/* SPI设备基类 */
typedef struct SPI_Device {
char dev_name[16]; // 设备标识
SPIDriver *driver; // 关联的驱动
GPIO_TypeDef *cs_port; // 设备专用CS端口
uint16_t cs_pin; // 设备专用CS引脚
struct list_head list; // 链表节点
// 虚函数表
int (*probe)(struct SPI_Device *dev);
int (*remove)(struct SPI_Device *dev);
void (*eventHandler)(struct SPI_Device *dev, SPI_EventType event);
} SPI_Device;
/* 全局设备链表 */
LIST_HEAD(spi_dev_list);
/******************** 驱动层实现 ********************/
int SPI_Driver_Init(SPIDriver *driver) {
if(HAL_SPI_Init(driver->hspi) != HAL_OK) {
return -1;
}
return 0;
}
/* 带CS控制的传输函数 */
static void SPI_CS_Enable(SPI_Device *dev) {
HAL_GPIO_WritePin(dev->cs_port, dev->cs_pin, GPIO_PIN_RESET);
}
static void SPI_CS_Disable(SPI_Device *dev) {
HAL_GPIO_WritePin(dev->cs_port, dev->cs_pin, GPIO_PIN_SET);
}
int SPI_TransmitReceive(SPIDriver *driver, SPI_Device *dev,
uint8_t *txData, uint8_t *rxData, uint16_t size)
{
SPI_CS_Enable(dev);
HAL_StatusTypeDef status = HAL_SPI_TransmitReceive(driver->hspi, txData, rxData,
size, driver->timeout);
SPI_CS_Disable(dev);
return (status == HAL_OK) ? 0 : -1;
}
/******************** 具体设备实现 ********************/
/* NorFlash设备结构体 */
typedef struct {
SPI_Device parent; // 继承基类
uint32_t sector_size; // 设备属性
uint32_t total_size;
// 设备方法
int (*sectorErase)(struct NorFlash_Device *dev, uint32_t addr);
int (*pageProgram)(struct NorFlash_Device *dev, uint32_t addr,
uint8_t *data, uint16_t len);
} NorFlash_Device;
/* RC522 RFID设备结构体 */
typedef struct {
SPI_Device parent;
uint8_t firmware_version;
// 设备方法
int (*antennaOn)(struct RC522_Device *dev);
int (*requestTag)(struct RC522_Device *dev, uint8_t *type);
} RC522_Device;
/* LCD设备结构体 */
typedef struct {
SPI_Device parent;
uint16_t width;
uint16_t height;
// 设备方法
void (*setAddress)(struct LCD_Device *dev, uint16_t x1, uint16_t y1,
uint16_t x2, uint16_t y2);
void (*fillColor)(struct LCD_Device *dev, uint16_t color, uint32_t pixelCount);
} LCD_Device;
/******************** NorFlash具体实现 ********************/
#define NORFLASH_CMD_WRITE_ENABLE 0x06
#define NORFLASH_CMD_SECTOR_ERASE 0x20
static int NorFlash_Probe(SPI_Device *dev) {
NorFlash_Device *flash = (NorFlash_Device*)dev;
uint8_t cmd = 0x9F; // 读ID命令
uint8_t id[3];
SPI_TransmitReceive(dev->driver, dev, &cmd, id, sizeof(id));
if(id[0] != 0xEF) { // 检查厂商ID
return -1;
}
return 0;
}
static int NorFlash_SectorErase(NorFlash_Device *dev, uint32_t addr) {
uint8_t cmd[4] = {
NORFLASH_CMD_WRITE_ENABLE,
NORFLASH_CMD_SECTOR_ERASE,
(addr >> 16) & 0xFF,
(addr >> 8) & 0xFF
};
return SPI_TransmitReceive(dev->parent.driver, &dev->parent, cmd, NULL, 4);
}
/******************** RC522具体实现 ********************/
#define RC522_CMD_IDLE 0x00
#define RC522_CMD_TRANSCEIVE 0x0C
static int RC522_AntennaOn(RC522_Device *dev) {
uint8_t txData[] = {0x01, 0x3D, 0x03}; // 设置天线增益
return SPI_TransmitReceive(dev->parent.driver, &dev->parent,
txData, NULL, sizeof(txData));
}
static void RC522_EventHandler(SPI_Device *dev, SPI_EventType event) {
if(event == EVENT_TIMER) {
// 定期检测标签
uint8_t reqCmd[] = {0x26}; // REQA命令
uint8_t response[2];
SPI_TransmitReceive(dev->driver, dev, reqCmd, response, sizeof(reqCmd));
}
}
/******************** LCD具体实现 ********************/
#define LCD_CMD_SET_ADDRESS 0x2A
#define LCD_CMD_WRITE_RAM 0x2C
static void LCD_SetAddress(LCD_Device *dev, uint16_t x1, uint16_t y1,
uint16_t x2, uint16_t y2)
{
uint8_t cmd[] = {
LCD_CMD_SET_ADDRESS,
(x1 >> 8) & 0xFF, x1 & 0xFF,
(x2 >> 8) & 0xFF, x2 & 0xFF
};
SPI_TransmitReceive(dev->parent.driver, &dev->parent, cmd, NULL, sizeof(cmd));
}
static void LCD_FillColor(LCD_Device *dev, uint16_t color, uint32_t count) {
uint8_t cmd = LCD_CMD_WRITE_RAM;
SPI_TransmitReceive(dev->parent.driver, &dev->parent, &cmd, NULL, 1);
// 批量发送颜色数据
uint8_t colorData[2] = {color >> 8, color & 0xFF};
while(count--) {
SPI_TransmitReceive(dev->parent.driver, &dev->parent,
colorData, NULL, 2);
}
}
/******************** 设备管理与事件分发 ********************/
void SPI_Device_Register(SPI_Device *dev) {
list_add_tail(&dev->list, &spi_dev_list);
}
void SPI_Process_Events(SPI_EventType event) {
struct list_head *pos;
SPI_Device *dev;
list_for_each(pos, &spi_dev_list) {
dev = list_entry(pos, SPI_Device, list);
if(dev->eventHandler) {
dev->eventHandler(dev, event);
}
}
}
/******************** 主程序示例 ********************/
int main(void) {
// 初始化HAL库、时钟、GPIO等
/* 初始化SPI驱动 */
SPIDriver spi1_driver = {
.hspi = &hspi1,
.timeout = 100,
.init = SPI_Driver_Init,
.transmitReceive = SPI_TransmitReceive
};
spi1_driver.init(&spi1_driver);
/* 注册NorFlash设备 */
NorFlash_Device w25q128 = {
.parent = {
.dev_name = "W25Q128",
.driver = &spi1_driver,
.cs_port = FLASH_CS_GPIO_Port,
.cs_pin = FLASH_CS_Pin,
.probe = NorFlash_Probe,
.eventHandler = NULL
},
.sector_size = 4096,
.total_size = 16*1024*1024,
.sectorErase = NorFlash_SectorErase
};
SPI_Device_Register(&w25q128.parent);
/* 注册LCD设备 */
LCD_Device st7789 = {
.parent = {
.dev_name = "ST7789",
.driver = &spi1_driver,
.cs_port = LCD_CS_GPIO_Port,
.cs_pin = LCD_CS_Pin,
.eventHandler = NULL
},
.setAddress = LCD_SetAddress,
.fillColor = LCD_FillColor
};
SPI_Device_Register(&st7789.parent);
/* 主事件循环 */
while(1) {
SPI_Process_Events(EVENT_TIMER);
HAL_Delay(50);
}
}
/******************** 中断回调处理 ********************/
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
if(hspi == spi1_driver.hspi) {
SPI_Process_Events(EVENT_SPI_TX_COMPLETE);
}
}
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) {
SPI_Process_Events(EVENT_SPI_ERROR);
}
关键设计说明
1. SPI 特有的功能
/* SPI模式配置结构体 */
typedef struct {
uint32_t mode; // CPOL/CPHA
uint32_t dataSize; // 数据位宽
uint32_t baudRatePrescaler;
} SPIConfig;
/* 扩展后的SPI设备基类 */
typedef struct SPI_Device {
// ...原有成员
SPIConfig config; // 设备特有配置
void (*reconfig)(struct SPI_Device *dev); // 配置更新方法
} SPI_Device;
2. DMA扩展
/* 扩展SPI驱动结构体 */
typedef struct SPIDriver {
// ...原有成员
DMA_HandleTypeDef *hdma_tx;
DMA_HandleTypeDef *hdma_rx;
volatile uint8_t transferBusy;
// 异步传输接口
int (*asyncTransmit)(struct SPIDriver *driver, SPI_Device *dev,
uint8_t *txData, uint16_t size);
} SPIDriver;
/* DMA传输完成回调 */
void SPI_DMA_Complete(SPIDriver *driver) {
driver->transferBusy = 0;
SPI_Process_Events(EVENT_SPI_TX_COMPLETE);
}
3. 设备配置管理
/* 设备配置存储结构 */
typedef struct {
SPI_Device *dev;
SPIConfig savedConfig;
} DeviceContext;
/* 多设备配置切换 */
void SPI_Switch_Device(SPI_Device *target) {
static DeviceContext currentCtx;
if(currentCtx.dev != NULL) {
// 保存当前设备配置
currentCtx.savedConfig = currentCtx.dev->config;
}
// 应用新设备配置
if(memcmp(&target->config, ¤tCtx.savedConfig, sizeof(SPIConfig)) != 0) {
target->reconfig(target);
}
currentCtx.dev = target;
}
4. Norflash 专有操作优化:
/* 批量写入优化结构 */
typedef struct {
uint32_t address;
uint8_t *data;
uint16_t length;
uint8_t status;
} FlashWriteOperation;
/* DMA传输描述符 */
typedef struct {
uint8_t cmdBuffer[4];
uint8_t *dataBuffer;
uint16_t dataSize;
} SPITransferDesc;
针对不同设备类型的优化策略:
1. NOR Flash设备:
实现页编程和扇区擦除算法
添加写保护控制
支持状态寄存器轮询
int NorFlash_WaitReady(NorFlash_Device *dev) {
uint8_t status;
do {
uint8_t cmd = 0x05; // 读状态寄存器命令
SPI_TransmitReceive(dev->parent.driver, &dev->parent,
&cmd, &status, 1);
} while(status & 0x01); // 检查BUSY位
return 0;
}
2. RC522 RFID设备:
实现ISO14443协议栈
添加CRC校验计算
支持防碰撞算法
int RC522_SelectTag(RC522_Device *dev, uint8_t *uid) {
uint8_t cmd[] = {0x93, 0x70, uid[0], uid[1], uid[2], uid[3], 0x00};
uint8_t response[1];
SPI_TransmitReceive(dev->parent.driver, &dev->parent, cmd, response, sizeof(cmd));
return (response[0] == 0x08) ? 0 : -1; // 检查ACK
}
3. LCD设备:
优化显存传输机制
实现双缓冲支持
添加图形绘制原语
void LCD_DrawRect(LCD_Device *dev, uint16_t x, uint16_t y,
uint16_t w, uint16_t h, uint16_t color)
{
dev->setAddress(dev, x, y, x+w-1, y+h-1);
dev->fillColor(dev, color, w*h);
}
错误处理实现:
typedef enum {
SPI_ERR_TIMEOUT = 0x01,
SPI_ERR_CRC = 0x02,
SPI_ERR_DMA = 0x04,
SPI_ERR_HARDWARE = 0x08
} SPI_ErrorCode;
typedef struct {
SPI_Device *sourceDev;
SPI_ErrorCode errCode;
uint32_t timestamp;
} SPI_ErrorEvent;
void SPI_Error_Handler(SPI_ErrorEvent *err) {
// 错误处理策略:
// 1. 重试机制
// 2. 设备复位
// 3. 系统日志记录
// 4. 安全模式切换
}
性能优化 :
使用内存池管理传输缓冲区:
#define SPI_BUFFER_POOL_SIZE 8
typedef struct {
uint8_t *buffer;
uint16_t size;
uint8_t inUse;
} SPIBuffer;
SPIBuffer bufferPool[SPI_BUFFER_POOL_SIZE];
uint8_t* SPI_Alloc_Buffer(uint16_t size) {
for(int i=0; i= size) {
bufferPool[i].inUse = 1;
return bufferPool[i].buffer;
}
}
return NULL; // 分配失败
}
2. 实现零拷贝传输接口
int SPI_Transmit_Direct(SPIDriver *driver, SPI_Device *dev,
uint8_t *txData, uint8_t *rxData,
uint16_t size, void (*completeCallback)(void))
{
SPI_CS_Enable(dev);
HAL_SPI_TransmitReceive_IT(driver->hspi, txData, rxData, size);
// 注册回调函数到驱动层
driver->currentCallback = completeCallback;
return 0;
}