目录

  1. SPI总线介绍
  2. SPI通信原理详解
  3. SPI时序解析
  4. SPI + W25Qx存储驱动设计

1. SPI总线介绍

1.1 总线概述

SPI(Serial Peripheral Interface)是一种高速全双工的同步串行通信协议,由Motorola于1980年代提出。其典型特性包括:

  • 四线通信:SCLK/MOSI/MISO/CS ;
  • 主从架构:支持一主多从模式 ;
  • 无寻址机制:通过硬件片选(CS)选择设备;
  • 时钟驱动:传输速率可达50MHz+ ;

1.2 核心优势对比

特性 SPI I2C UART
通信模式 全双工 半双工 全双工
最高速率 50Mbps 3.4Mbps 1Mbps
硬件复杂度 中等
寻址方式 硬件片选 软件地址

2. SPI通信原理详解

2.1 信号线定义

信号线 名称 方向 作用描述
SCLK 串行时钟线 主→从 同步数据传输时钟
MOSI 主设备输出从设备输入 主→从 主设备数据发送通道
MISO 主设备输入从设备输出 从→主 从设备数据响应通道
CS/SS 片选信号 主→从 从设备使能控制(低电平有效)

2.2 数据传输机制

数据以 移位寄存器 方式传输,典型工作流程:

开始
拉低CS信号
生成SCLK时钟
MOSI发送数据
MISO接收数据
拉高CS信号
结束
// 典型数据交换伪代码
void SPI_Transfer(uint8_t* txData, uint8_t* rxData, uint32_t size) {
    CS_LOW();
    for(int i=0; i<size; i++){
        SCLK_TOGGLE();
        rxData[i] = ShiftByte(txData[i]); 
    }
    CS_HIGH();
}


2.3 SPI总线主从通信应用

在这里插入图片描述


3. SPI时序解析

3.1 时钟极性相位

SPI协议通过 CPOL(Clock Polarity)CPHA(Clock Phase) 组合定义四种工作模式:

模式 CPOL CPHA 时钟极性 采样边沿
0 0 0 低电平空闲 上升沿采样
1 0 1 低电平空闲 下降沿采样
2 1 0 高电平空闲 下降沿采样
3 1 1 高电平空闲 上升沿采样

3.2 通信时序

在这里插入图片描述

在这里插入图片描述



4. SPI + W25Qx存储驱动设计

4.1 W25Q128芯片简介

W25Q128 是华邦电子(Winbond)推出的一款高性能串行闪存芯片,主要参数:

参数 数值
容量 16MB (128M-bit)
页大小 256字节
扇区大小 4KB
块大小 64KB
接口电压 2.7V-3.6V
时钟频率 最高104MHz(Dual SPI)

4.2 驱动程序设计

4.2.1 驱动初始化


void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH; // 串行同步时钟的空闲状态为高电平
  hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */

}


4.2.2 写使能

static void w25QWriteEnable(void)
{
    // CS 拉低电平,开始通讯
    W25Q_CS_LOW();
    
    // 发送写使能命令
    W25QHardWriteReadByte( W25Q_CMD_WRITE_ENABLE);
    
    // CS 拉高电平,结束通讯
    W25Q_CS_HIGH();
}



4.2.3 页编程

static uint8_t W25QPageProgram(uint32_t writeAddr, uint8_t* data, uint32_t len)
{
    // 判断数据的有效性
    if((!data) || (len <= 0) || 
			 (len > 256)) return 1;
    
    w25QWriteEnable(); // 写使能
    
    // 若等待空闲状态超时,就返回 false
    if( !W25QWaitIdle()) return 1;
    
    // CS 拉低电平,开始通讯
    W25Q_CS_LOW();
    
    // 发送 页编程 命令
    W25QHardWriteReadByte( W25Q_CMD_PAGE_PROGRAM);
    
    // 发送地址
    w25QWriteAddr( writeAddr);
   
    W25QHardWriteReadMultByte(data, len);

    // CS 拉高电平,结束通讯
    W25Q_CS_HIGH();
    
    // 等待空闲
    W25QWaitIdle();
    
    return 0;
}



4.2.4 数据读取


static uint32_t w25QxRead(uint32_t readAddr, uint8_t* buf, uint32_t numByte)
{
    uint8_t len = numByte, i = 0;
    
    // 判断数据的有效性
    if((!buf) || (numByte <= 0)) return 0;
    
     // CS 拉低电平,开始通讯
    W25Q_CS_LOW();
    
    // 发送 读取 命令
    W25QHardWriteReadByte( W25Q_CMD_READ_DATA);
    
    // 发送地址
    w25QWriteAddr( readAddr);
    
    for(i = 0; i < numByte; i++) buf[i] = W25Q_DUMMY_VALUE;
    W25QHardWriteReadMultByte(buf, numByte);
    
    // CS 拉高电平,结束通讯
    W25Q_CS_HIGH();
    
    return len;
}




SPI+W25Qx驱动源程序 : https://download.csdn.net/download/weixin_43176196/90888095?spm=1011.2124.3001.6210




Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐