基于STM32 SPI通信的驱动代码 ,包含DMA传输、中断处理、数据读写、错误处理,可以直接用于W25Qxx、SD卡、OLED屏、传感器等SPI设备。
一、STM32 SPI核心特性
| 模式 | CPOL | CPHA | 数据采样 | 适用设备 |
|---|---|---|---|---|
| 模式0 | 0 | 0 | 第一个边沿 | 大部分SPI设备 |
| 模式1 | 0 | 1 | 第二个边沿 | 特殊设备 |
| 模式2 | 1 | 0 | 第二个边沿 | 特殊设备 |
| 模式3 | 1 | 1 | 第一个边沿 | 特殊设备 |
推荐配置:
- 模式:Mode 0 (CPOL=0, CPHA=0)
- 数据位:8位
- 传输顺序:MSB First
- 时钟极性:Low
- 数据采样:1 Edge
二、硬件连接
1、SPI引脚定义
SPI1 (APB2总线,最高36MHz):
PA4 → NSS (片选)
PA5 → SCK (时钟)
PA6 → MISO (主入从出)
PA7 → MOSI (主出从入)
2、设备片选控制
设备1_CS → PB0
设备2_CS → PB1
设备3_CS → PB2
注意:NSS硬件管理通常关闭,用GPIO软件控制CS
三、CubeMX配置
1、SPI配置参数
Mode: Full-Duplex Master
Data Size: 8 bits
First Bit: MSB First
Baud Rate: 9MHz (APB2/4)
CPOL: Low
CPHA: 1 Edge
NSS: Soft
CRC: Disable
2、DMA配置
SPI_TX: DMA1 Channel3
SPI_RX: DMA1 Channel2
Mode: Normal
Increment: Memory
Data Width: Byte
四、SPI驱动头文件
// spi_driver.h
#ifndef __SPI_DRIVER_H
#define __SPI_DRIVER_H
#include "stm32f1xx_hal.h"
// SPI设备枚举
typedef enum {
SPI_DEVICE_FLASH = 0, // W25Q64
SPI_DEVICE_SDCARD, // SD卡
SPI_DEVICE_OLED, // OLED屏幕
SPI_DEVICE_MAX
} SPI_Device_t;
// SPI传输状态
typedef enum {
SPI_STATE_READY = 0,
SPI_STATE_BUSY,
SPI_STATE_ERROR
} SPI_State_t;
// SPI传输结构
typedef struct {
uint8_t *tx_buffer;
uint8_t *rx_buffer;
uint16_t tx_size;
uint16_t rx_size;
uint16_t tx_index;
uint16_t rx_index;
SPI_State_t state;
uint8_t dma_enabled;
} SPI_Transfer_t;
// SPI设备配置
typedef struct {
GPIO_TypeDef *cs_port;
uint16_t cs_pin;
uint32_t timeout;
uint8_t dummy_byte;
} SPI_Device_Config_t;
// 函数声明
void SPI_Init(void);
void SPI_Select_Device(SPI_Device_t device);
void SPI_Deselect_Device(SPI_Device_t device);
uint8_t SPI_Transmit_Receive(uint8_t *tx_data, uint8_t *rx_data, uint16_t size);
uint8_t SPI_Transmit(uint8_t *data, uint16_t size);
uint8_t SPI_Receive(uint8_t *data, uint16_t size);
void SPI_Transmit_IT(uint8_t *data, uint16_t size);
void SPI_Receive_IT(uint8_t *data, uint16_t size);
void SPI_Transmit_Receive_DMA(uint8_t *tx_data, uint8_t *rx_data, uint16_t size);
uint8_t SPI_Is_Busy(void);
void SPI_Wait_Ready(void);
// 设备特定函数
uint8_t W25Q64_Read_ID(void);
void W25Q64_Read_Data(uint32_t addr, uint8_t *data, uint32_t size);
void W25Q64_Write_Page(uint32_t addr, uint8_t *data, uint16_t size);
void W25Q64_Erase_Sector(uint32_t addr);
#endif
五、SPI驱动实现
1、SPI初始化
// spi_driver.c
#include "spi_driver.h"
#include <string.h>
// SPI句柄
SPI_HandleTypeDef hspi1;
DMA_HandleTypeDef hdma_spi1_tx;
DMA_HandleTypeDef hdma_spi1_rx;
// 传输控制结构
static SPI_Transfer_t spi_transfer = {
0};
// 设备配置
static SPI_Device_Config_t spi_devices[SPI_DEVICE_MAX] = {
// W25Q64 Flash
{
GPIOB, GPIO_PIN_0, 100, 0xFF},
// SD卡
{
GPIOB, GPIO_PIN_1, 1000, 0xFF},
// OLED
{
GPIOB, GPIO_PIN_2, 10, 0x00}
};
// SPI初始化
void SPI_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {
0};
// 1. 使能时钟
__HAL_RCC_SPI1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
// 2. 配置SPI引脚
// PA5: SCK, PA6: MISO, PA7: MOSI
GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 3. 配置CS引脚
for (int i = 0; i < SPI_DEVICE_MAX; i++) {
GPIO_InitStruct.Pin = spi_devices[i].cs_pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(spi_devices[i].cs_port, &GPIO_InitStruct);
// 默认取消选中
HAL_GPIO_WritePin(spi_devices[i].cs_port,
spi_devices[i].cs_pin, GPIO_PIN_SET);
}
// 4. 初始化SPI
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_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; // 9MHz
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLED;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
hspi1.Init.CRCPolynomial = 10;
HAL_SPI_Init(&hspi1);
// 5. 初始化DMA
// TX DMA (SPI1 -> 外设)
hdma_spi1_tx.Instance = DMA1_Channel3;
hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_tx.Init.Mode = DMA_NORMAL;
hdma_spi1_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hdma_spi1_tx);
// RX DMA (外设 -> SPI1)
hdma_spi1_rx.Instance = DMA1_Channel2;
hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_rx.Init.Mode = DMA_NORMAL;
hdma_spi1_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hdma_spi1_rx);
// 关联DMA到SPI
__HAL_LINKDMA(&hspi1, hdmatx, hdma_spi1_tx);
__HAL_LINKDMA(&hspi1, hdmarx, hdma_spi1_rx);
// 6. 启用DMA中断
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
// 7. 启用SPI
__HAL_SPI_ENABLE(&hspi1);
spi_transfer.state = SPI_STATE_READY;
}
2、设备选择函数
// 选择设备
void SPI_Select_Device(SPI_Device_t device)
{
if (device >= SPI_DEVICE_MAX) return;
HAL_GPIO_WritePin(spi_devices[device].cs_port,
spi_devices[device].cs_pin, GPIO_PIN_RESET);
// 短暂延时,确保设备准备好
__NOP(); __NOP(); __NOP(); __NOP();
}
// 取消选择设备
void SPI_Deselect_Device(SPI_Device_t device)
{
if (device >= SPI_DEVICE_MAX) return;
// 等待传输完成
SPI_Wait_Ready();
HAL_GPIO_WritePin(spi_devices[device].cs_port,
spi_devices[device].cs_pin, GPIO_PIN_SET);
// 短暂延时
__NOP(); __NOP(); __NOP(); __NOP();
}
3、阻塞式传输(最简单)
// 阻塞式发送接收
uint8_t SPI_Transmit_Receive(uint8_t *tx_data, uint8_t *rx_data, uint16_t size)
{
HAL_StatusTypeDef status;
if (spi_transfer.state != SPI_STATE_READY) {
return 0;
}
spi_transfer.state = SPI_STATE_BUSY;
// 使用HAL库的阻塞传输
status = HAL_SPI_TransmitReceive(&hspi1, tx_data, rx_data, size, 1000);
spi_transfer.state = SPI_STATE_READY;
return (status == HAL_OK);
}
// 阻塞式发送
uint8_t SPI_Transmit(uint8_t *data, uint16_t size)
{
return SPI_Transmit_Receive(data, NULL, size);
}
// 阻塞式接收
uint8_t SPI_Receive(uint8_t *data, uint16_t size)
{
// 接收需要发送虚拟数据
uint8_t dummy;
uint8_t *dummy_ptr = (data != NULL) ? data : &dummy;
return SPI_Transmit_Receive(NULL, dummy_ptr, size);
}
4、中断式传输(不阻塞)
// 中断发送
void SPI_Transmit_IT(uint8_t *data, uint16_t size)
{
if (spi_transfer.state != SPI_STATE_READY) {
return;
}
spi_transfer.state = SPI_STATE_BUSY;
spi_transfer.tx_buffer = data;
spi_transfer.tx_size = size;
spi_transfer.dma_enabled = 0;
HAL_SPI_Transmit_IT(&hspi1, data, size);
}
// 中断接收
void SPI_Receive_IT(uint8_t *data, uint16_t size)
{
if (spi_transfer.state != SPI_STATE_READY) {
return;
}
spi_transfer.state = SPI_STATE_BUSY;
spi_transfer.rx_buffer = data;
spi_transfer.rx_size = size;
spi_transfer.dma_enabled = 0;
HAL_SPI_Receive_IT(&hspi1, data, size);
}
5、DMA传输(最快)
// DMA发送接收
void SPI_Transmit_Receive_DMA(uint8_t *tx_data, uint8_t *rx_data, uint16_t size)
{
if (spi_transfer.state != SPI_STATE_READY) {
return;
}
spi_transfer.state = SPI_STATE_BUSY;
spi_transfer.tx_buffer = tx_data;
spi_transfer.rx_buffer = rx_data;
spi_transfer.tx_size = size;
spi_transfer.rx_size = size;
spi_transfer.dma_enabled = 1;
// 启动DMA传输
HAL_SPI_TransmitReceive_DMA(&hspi1, tx_data, rx_data, size);
}
// 检查SPI是否繁忙
uint8_t SPI_Is_Busy(void)
{
return (spi_transfer.state == SPI_STATE_BUSY);
}
// 等待SPI就绪
void SPI_Wait_Ready(void)
{
while (SPI_Is_Busy()) {
__NOP();
}
}
6、SPI中断处理
// SPI中断回调
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
if (hspi->Instance == SPI1) {
spi_transfer.state = SPI_STATE_READY;
// 可以在这里添加传输完成回调
if (spi_transfer.dma_enabled) {
// DMA传输完成处理
} else {
// 中断传输完成处理
}
}
}
// SPI错误回调
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
if (hspi->Instance == SPI1) {
spi_transfer.state = SPI_STATE_ERROR;
// 错误处理
uint32_t error = HAL_SPI_GetError(hspi);
if (error & HAL_SPI_ERROR_MODF) {
// 模式错误
}
if (error & HAL_SPI_ERROR_CRC) {
// CRC错误
}
if (error & HAL_SPI_ERROR_OVR) {
// 溢出错误
}
if (error & HAL_SPI_ERROR_FRE) {
// 帧格式错误
}
if (error & HAL_SPI_ERROR_DMA) {
// DMA错误
}
// 重置SPI
__HAL_SPI_DISABLE(hspi);
__HAL_SPI_ENABLE(hspi);
}
}
7、DMA中断处理
// DMA中断服务函数
void DMA1_Channel2_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_spi1_rx);
}
void DMA1_Channel3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_spi1_tx);
}
// DMA传输完成回调
void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi)
{
// 半传输完成
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
// 接收完成
}
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
// 发送完成
}
六、W25Q64 Flash驱动示例
// w25q64.c
#include "spi_driver.h"
#include <string.h>
// W25Q64命令定义
#define W25Q64_CMD_WRITE_ENABLE 0x06
#define W25Q64_CMD_WRITE_DISABLE 0x04
#define W25Q64_CMD_READ_STATUS_REG1 0x05
#define W25Q64_CMD_READ_STATUS_REG2 0x35
#define W25Q64_CMD_WRITE_STATUS_REG 0x01
#define W25Q64_CMD_PAGE_PROGRAM 0x02
#define W25Q64_CMD_QUAD_PAGE_PROGRAM 0x32
#define W25Q64_CMD_BLOCK_ERASE 0xD8
#define W25Q64_CMD_SECTOR_ERASE 0x20
#define W25Q64_CMD_CHIP_ERASE 0xC7
#define W25Q64_CMD_ERASE_SUSPEND 0x75
#define W25Q64_CMD_ERASE_RESUME 0x7A
#define W25Q64_CMD_POWER_DOWN 0xB9
#define W25Q64_CMD_HIGH_PERFORMANCE 0xA3
#define W25Q64_CMD_READ_DATA 0x03
#define W25Q64_CMD_FAST_READ 0x0B
#define W25Q64_CMD_READ_JEDEC_ID 0x9F
#define W25Q64_CMD_RELEASE_POWER_DOWN 0xAB
// 状态寄存器位
#define W25Q64_STATUS_BUSY 0x01
#define W25Q64_STATUS_WRITE_ENABLE 0x02
// 读取设备ID
uint8_t W25Q64_Read_ID(void)
{
uint8_t tx_buffer[4] = {
0};
uint8_t rx_buffer[4] = {
0};
tx_buffer[0] = W25Q64_CMD_READ_JEDEC_ID;
SPI_Select_Device(SPI_DEVICE_FLASH);
SPI_Transmit_Receive(tx_buffer, rx_buffer, 4);
SPI_Deselect_Device(SPI_DEVICE_FLASH);
// rx_buffer[1] = Manufacturer ID
// rx_buffer[2] = Memory Type
// rx_buffer[3] = Capacity
return rx_buffer[3];
}
// 读取状态寄存器
static uint8_t W25Q64_Read_Status_Reg1(void)
{
uint8_t tx_buffer[2] = {
W25Q64_CMD_READ_STATUS_REG1, 0x00};
uint8_t rx_buffer[2] = {
0};
SPI_Select_Device(SPI_DEVICE_FLASH);
SPI_Transmit_Receive(tx_buffer, rx_buffer, 2);
SPI_Deselect_Device(SPI_DEVICE_FLASH);
return rx_buffer[1];
}
// 等待Flash就绪
static void W25Q64_Wait_Busy(void)
{
while (W25Q64_Read_Status_Reg1() & W25Q64_STATUS_BUSY) {
// 等待
}
}
// 写使能
static void W25Q64_Write_Enable(void)
{
uint8_t cmd = W25Q64_CMD_WRITE_ENABLE;
SPI_Select_Device(SPI_DEVICE_FLASH);
SPI_Transmit(&cmd, 1);
SPI_Deselect_Device(SPI_DEVICE_FLASH);
}
// 读取数据
void W25Q64_Read_Data(uint32_t addr, uint8_t *data, uint32_t size)
{
uint8_t tx_buffer[5];
// 构建读取命令
tx_buffer[0] = W25Q64_CMD_READ_DATA;
tx_buffer[1] = (addr >> 16) & 0xFF; // 地址高字节
tx_buffer[2] = (addr >> 8) & 0xFF; // 地址中字节
tx_buffer[3] = addr & 0xFF; // 地址低字节
SPI_Select_Device(SPI_DEVICE_FLASH);
// 发送命令和地址
SPI_Transmit(tx_buffer, 4);
// 接收数据
if (data != NULL) {
SPI_Receive(data, size);
} else {
// 如果data为NULL,只接收不存储
uint8_t dummy;
for (uint32_t i = 0; i < size; i++) {
SPI_Receive(&dummy, 1);
}
}
SPI_Deselect_Device(SPI_DEVICE_FLASH);
}
// 写入一页数据(最大256字节)
void W25Q64_Write_Page(uint32_t addr, uint8_t *data, uint16_t size)
{
uint8_t tx_buffer[4];
if (size > 256) size = 256; // 限制页大小
// 等待Flash就绪
W25Q64_Wait_Busy();
// 写使能
W25Q64_Write_Enable();
// 构建页编程命令
tx_buffer[0] = W25Q64_CMD_PAGE_PROGRAM;
tx_buffer[1] = (addr >> 16) & 0xFF;
tx_buffer[2] = (addr >> 8) & 0xFF;
tx_buffer[3] = addr & 0xFF;
SPI_Select_Device(SPI_DEVICE_FLASH);
// 发送命令和地址
SPI_Transmit(tx_buffer, 4);
// 发送数据
SPI_Transmit(data, size);
SPI_Deselect_Device(SPI_DEVICE_FLASH);
// 等待写入完成
W25Q64_Wait_Busy();
}
// 擦除扇区(4KB)
void W25Q64_Erase_Sector(uint32_t addr)
{
uint8_t tx_buffer[4];
// 等待Flash就绪
W25Q64_Wait_Busy();
// 写使能
W25Q64_Write_Enable();
// 构建扇区擦除命令
tx_buffer[0] = W25Q64_CMD_SECTOR_ERASE;
tx_buffer[1] = (addr >> 16) & 0xFF;
tx_buffer[2] = (addr >> 8) & 0xFF;
tx_buffer[3] = addr & 0xFF;
SPI_Select_Device(SPI_DEVICE_FLASH);
SPI_Transmit(tx_buffer, 4);
SPI_Deselect_Device(SPI_DEVICE_FLASH);
// 等待擦除完成
W25Q64_Wait_Busy();
}
七、主程序示例
// main.c
#include "main.h"
#include "spi_driver.h"
#include <string.h>
int main(void)
{
HAL_Init();
SystemClock_Config();
// 初始化SPI
SPI_Init();
// 1. 测试Flash ID
uint8_t flash_id = W25Q64_Read_ID();
printf("Flash ID: 0x%02X\r\n", flash_id);
// 2. 测试数据读写
uint8_t write_buffer[256];
uint8_t read_buffer[256];
// 填充测试数据
for (int i = 0; i < 256; i++) {
write_buffer[i] = i;
}
// 擦除扇区
printf("Erasing sector...\r\n");
W25Q64_Erase_Sector(0x000000);
// 写入数据
printf("Writing data...\r\n");
W25Q64_Write_Page(0x000000, write_buffer, 256);
// 读取数据
printf("Reading data...\r\n");
W25Q64_Read_Data(0x000000, read_buffer, 256);
// 验证数据
if (memcmp(write_buffer, read_buffer, 256) == 0) {
printf("SPI Flash test PASS!\r\n");
} else {
printf("SPI Flash test FAIL!\r\n");
}
// 3. 测试DMA传输
uint8_t dma_tx_buffer[1024];
uint8_t dma_rx_buffer[1024];
for (int i = 0; i < 1024; i++) {
dma_tx_buffer[i] = 0xAA;
}
// 使用DMA传输
printf("Starting DMA transfer...\r\n");
SPI_Select_Device(SPI_DEVICE_FLASH);
SPI_Transmit_Receive_DMA(dma_tx_buffer, dma_rx_buffer, 1024);
// 等待DMA传输完成
while (SPI_Is_Busy()) {
// 可以在这里做其他事情
}
SPI_Deselect_Device(SPI_DEVICE_FLASH);
printf("DMA transfer complete!\r\n");
while (1) {
// 主循环
HAL_Delay(1000);
}
}
参考代码 STM32的SPI外设与之通信,进行数据的读写 www.youwenfan.com/contentali/70085.html
八、性能优化
1. 提高SPI时钟
// 根据APB2时钟设置
// 72MHz系统时钟,APB2=72MHz
// 分频设置:
// SPI_BAUDRATEPRESCALER_2 = 36MHz
// SPI_BAUDRATEPRESCALER_4 = 18MHz
// SPI_BAUDRATEPRESCALER_8 = 9MHz
2. 使用快速读取
// W25Q64支持快速读取
void W25Q64_Fast_Read(uint32_t addr, uint8_t *data, uint32_t size)
{
uint8_t tx_buffer[5] = {
W25Q64_CMD_FAST_READ,
(addr >> 16) & 0xFF,
(addr >> 8) & 0xFF,
addr & 0xFF,
0xFF}; // 虚拟字节
SPI_Select_Device(SPI_DEVICE_FLASH);
SPI_Transmit_Receive(tx_buffer, data, size + 5);
SPI_Deselect_Device(SPI_DEVICE_FLASH);
}
3. 批量传输优化
// 批量写入
void W25Q64_Write_Multi_Page(uint32_t addr, uint8_t *data, uint32_t size)
{
uint32_t offset = 0;
while (size > 0) {
uint16_t write_size = (size > 256) ? 256 : size;
W25Q64_Write_Page(addr + offset, data + offset, write_size);
offset += write_size;
size -= write_size;
// 延时避免Flash过热
if (offset % 4096 == 0) {
HAL_Delay(1);
}
}
}
九、调试技巧
1、逻辑分析仪调试
// 添加调试GPIO
#define DEBUG_PIN_SET() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET)
#define DEBUG_PIN_CLR() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET)
// 在关键位置添加
DEBUG_PIN_SET();
SPI_Transmit(data, size);
DEBUG_PIN_CLR();
2、错误检测
// 检查SPI错误
void SPI_Check_Error(void)
{
if (hspi1.ErrorCode != HAL_SPI_ERROR_NONE) {
printf("SPI Error: 0x%08lX\r\n", hspi1.ErrorCode);
// 重置SPI
__HAL_SPI_DISABLE(&hspi1);
HAL_SPI_DeInit(&hspi1);
HAL_SPI_Init(&hspi1);
}
}
十、常见问题
| 问题 | 原因 | 解决 |
|---|---|---|
| 无响应 | CS引脚错误 | 检查CS引脚电平和时序 |
| 数据错误 | 时钟相位不对 | 调整CPOL/CPHA |
| DMA卡死 | DMA未正确初始化 | 检查DMA配置和中断 |
| 速度慢 | SPI时钟太低 | 提高时钟频率 |
| 干扰大 | 未加滤波电容 | 靠近芯片加0.1uF电容 |