SPI总线抽象架构设计与实现
## 1. SPI总线抽象架构设计 ### 1.1 设计目标与架构分层 SPI总线抽象设计主要解决三个核心问题 1. 总线与设备解耦通过分层设计实现硬件无关性 2. 快速切换硬件/模拟SPI统一接口规范支持多种实现方式 3. 跨平台移植性核心逻辑与硬件驱动分离 系统采用三层架构 - 应用层外设驱动实现如EEPROM操作 - 中间层SPI抽象接口spi_core - 硬件层具体SPI实现spi_hw ### 1.2 关键数据结构 #### 1.2.1 设备描述结构体 c struct spi_dev_device { void (*spi_cs)(unsigned char state); struct spi_bus_device *spi_bus; };spi_cs片选控制函数指针spi_bus指向底层总线设备1.2.2 总线设备结构体struct spi_bus_device { int (*spi_bus_xfer)(struct spi_dev_device *, struct spi_dev_message *); void *spi_phy; unsigned char data_width; };spi_bus_xfer数据传输函数指针spi_phy物理SPI控制器实例如SPI1data_width数据位宽8/16bit1.2.3 消息帧结构体struct spi_dev_message { const void *send_buf; void *recv_buf; int length; unsigned char cs_take:1; unsigned char cs_release:1; };2. 核心API实现2.1 标准传输接口2.1.1 先发后收模式int spi_send_then_recv(struct spi_dev_device *spi_dev, const void *send_buff, unsigned short send_size, void *recv_buff, unsigned short recv_size) { struct spi_dev_message message; // 第一阶段发送命令帧 message.length send_size; message.send_buf send_buff; message.recv_buf 0; message.cs_take 1; message.cs_release 0; spi_dev-spi_bus-spi_bus_xfer(spi_dev, message); // 第二阶段接收数据帧 message.length recv_size; message.send_buf 0; message.recv_buf recv_buff; message.cs_take 0; message.cs_release 1; return spi_dev-spi_bus-spi_bus_xfer(spi_dev, message); }2.1.2 同步收发模式int spi_send_recv(struct spi_dev_device *spi_dev, const void *send_buff, void *recv_buff, unsigned short data_size) { struct spi_dev_message message { .length data_size, .send_buf send_buff, .recv_buf recv_buff, .cs_take 1, .cs_release 1 }; return spi_dev-spi_bus-spi_bus_xfer(spi_dev, message); }2.2 底层硬件实现STM32示例static int stm32_spi_bus_xfer(struct spi_dev_device *spi_dev, struct spi_dev_message *msg) { SPI_TypeDef *SPI_NO spi_dev-spi_bus-spi_phy; int size msg-length; if(msg-cs_take) { spi_dev-spi_cs(0); } if(spi_dev-spi_bus-data_width 8) { const unsigned short *send_ptr msg-send_buf; unsigned short *recv_ptr msg-recv_buf; while(size--) { unsigned short data 0xFF; if(send_ptr) data *send_ptr; while(!SPI_I2S_GetFlagStatus(SPI_NO, SPI_I2S_FLAG_TXE)); SPI_I2S_SendData(SPI_NO, data); while(!SPI_I2S_GetFlagStatus(SPI_NO, SPI_I2S_FLAG_RXNE)); data SPI_I2S_ReceiveData(SPI_NO); if(recv_ptr) *recv_ptr data; } } if(msg-cs_release) { spi_dev-spi_cs(1); } return msg-length; }3. 应用实例EEPROM驱动3.1 设备初始化struct spi_dev_device ee_25xx_spi_dev; struct spi_bus_device spi_bus1; static void spi1_cs(unsigned char state) { GPIO_WriteBit(GPIOB, GPIO_Pin_12, (BitAction)state); } void ee_25xx_init(void) { GPIO_InitTypeDef GPIO_InitStructure; // 片选引脚配置 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOB, GPIO_InitStructure); GPIO_SetBits(GPIOB, GPIO_Pin_12); // 设备注册 stm32f1xx_spi_init(0, spi_bus1); ee_25xx_spi_dev.spi_cs spi1_cs; ee_25xx_spi_dev.spi_bus spi_bus1; }3.2 读写操作实现3.2.1 写操作void ee_25xx_write_byte(uint16_t write_addr, uint8_t write_data) { uint8_t send_buff[3]; ee_25xx_write_enable(REG_WRITE_ENABLE); send_buff[0] REG_WRITE_COMMAND; send_buff[1] (write_addr 8) 0xFF; send_buff[2] write_addr 0xFF; spi_send_then_send(ee_25xx_spi_dev, send_buff, 3, write_data, 1); ee_25xx_write_enable(REG_WRITE_DISABLE); }3.2.2 读操作void ee_25xx_read_bytes(uint16_t read_addr, uint8_t *read_buff, uint16_t read_bytes) { uint8_t send_buff[3]; send_buff[0] REG_READ_COMMAND; send_buff[1] (read_addr 8) 0xFF; send_buff[2] read_addr 0xFF; spi_send_then_recv(ee_25xx_spi_dev, send_buff, 3, read_buff, read_bytes); }4. 设计优势分析4.1 移植性保障硬件层隔离更换MCU平台只需重写spi_bus_xfer实现统一接口上层应用代码无需修改多总线支持同一系统可混合使用硬件SPI和模拟SPI4.2 性能优化点零拷贝设计直接使用应用层缓冲区指针位域压缩消息帧使用位域节省内存条件编译支持8/16bit数据宽度4.3 扩展性设计多设备支持通过不同片选引脚管理多个外设非标SPI适配特殊时序可通过定制spi_bus_xfer实现DMA集成底层实现可扩展DMA传输支持
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2463461.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!