面向对象编程思想--SPI设备(Norflash、RFID、LCD屏幕)

上节写了对于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. 安全模式切换
}

性能优化 :

  1. 使用内存池管理传输缓冲区:

#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;
}

    你可能感兴趣的:(面向对象编程,单片机,嵌入式硬件,stm32,linux,物联网,mcu,iot)