一、硬件接口配置
1. SPI接口配置(模式3)
c
// SPI参数定义
#define SPI_MODE SPI_MODE_3 // CPOL=1, CPHA=1
#define SPI_BAUDRATE_PRESCALER 256 // 72MHz/(256+1)=281.25kHz
#define SPI_DATA_SIZE SPI_DATASIZE_8BIT
#define SPI_TIMEOUT_MS 1000
// GPIO引脚映射
#define QCA7000_SPI_SCK GPIO_PIN_5
#define QCA7000_SPI_MISO GPIO_PIN_6
#define QCA7000_SPI_MOSI GPIO_PIN_7
#define QCA7000_SPI_CS GPIO_PIN_4
2. UART接口配置
c
// UART参数定义
#define UART_BAUDRATE 115200
#define UART_WORD_LENGTH UART_WORDLENGTH_8D
#define UART_STOP_BITS UART_STOPBITS_1
#define UART_PARITY UART_PARITY_NO
#define UART_FLOW_CONTROL UART_HWCONTROL_NONE
// 硬件流控制引脚
#define UART_CTS_PIN GPIO_PIN_0
#define UART_RTS_PIN GPIO_PIN_1
二、驱动核心代码实现
1. SPI驱动模块
c
#include "stm32f1xx_hal.h"
SPI_HandleTypeDef hspi1;
void QCA7000_SPI_Init() {
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; // CPOL=1
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE; // CPHA=1
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATE_PRESCALER;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
HAL_SPI_Init(&hspi1);
}
// SPI读写函数
HAL_StatusTypeDef QCA7000_SPI_Transceive(uint8_t *txData, uint8_t *rxData, uint16_t Size) {
return HAL_SPI_TransmitReceive(&hspi1, txData, rxData, Size, SPI_TIMEOUT_MS);
}
// 寄存器读操作
uint8_t QCA7000_SPI_ReadReg(uint8_t regAddr) {
uint8_t txBuf[2] = {0x03, regAddr}; // 读命令格式:03 + 寄存器地址
uint8_t rxBuf[2] = {0};
HAL_GPIO_WritePin(QCA7000_SPI_CS_GPIO_Port, QCA7000_SPI_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi1, txBuf, rxBuf, 2, SPI_TIMEOUT_MS);
HAL_GPIO_WritePin(QCA7000_SPI_CS_GPIO_Port, QCA7000_SPI_CS_Pin, GPIO_PIN_SET);
return rxBuf[1];
}
// 寄存器写操作
HAL_StatusTypeDef QCA7000_SPI_WriteReg(uint8_t regAddr, uint8_t value) {
uint8_t txBuf[2] = {0x02, regAddr}; // 写命令格式:02 + 寄存器地址
return HAL_SPI_Transmit(&hspi1, txBuf, 2, SPI_TIMEOUT_MS);
}
2. UART驱动模块
c
UART_HandleTypeDef huart2;
void QCA7000_UART_Init() {
huart2.Instance = USART2;
huart2.Init.BaudRate = UART_BAUDRATE;
huart2.Init.WordLength = UART_WORD_LENGTH;
huart2.Init.StopBits = UART_STOP_BITS;
huart2.Init.Parity = UART_PARITY;
huart2.Init.HwFlowCtl = UART_FLOW_CONTROL;
HAL_UART_Init(&huart2);
}
// 带硬件流控制的发送函数
HAL_StatusTypeDef QCA7000_UART_SendWithFlowCtrl(uint8_t *pData, uint16_t Size) {
return HAL_UART_Transmit(&huart2, pData, Size, 1000);
}
// 中断接收处理
void USART2_IRQHandler() {
HAL_UART_IRQHandler(&huart2);
if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE)) {
uint8_t data = HAL_UART_Receive(&huart2, &rxBuffer, 1, 0);
// 处理接收数据
}
}
三、协议解析与数据交互
1. SPI命令结构
c
// 命令格式示例(参考QCA7000_SPI_UART_Protocol_v5.pdf)
typedef struct {
uint8_t cmd; // 命令字(如0x01读寄存器)
uint8_t addr; // 寄存器地址
uint8_t data[4]; // 数据字段
uint8_t crc; // CRC校验
} QCA7000_SPI_Cmd;
// CRC16计算函数
uint16_t QCA7000_CalculateCRC(uint8_t *data, uint16_t len) {
uint16_t crc = 0xFFFF;
for (int i=0; i<len; i++) {
crc ^= (uint16_t)data[i] << 8;
for (int j=0; j<8; j++) {
if (crc & 0x8000) crc = (crc << 1) ^ 0x1021;
else crc <<= 1;
}
}
return crc;
}
2. 数据帧解析流程
c
sequenceDiagram
participant MCU
participant QCA7000
MCU->>QCA7000: 发送命令帧(0x01 + 地址 + 数据)
QCA7000->>MCU: 返回状态字(0x00表示成功)
MCU->>QCA7000: 读取数据帧(0x03 + 地址 + 数据 + CRC)
QCA7000-->>MCU: 硬件流控制确认(RTS/CTS)
四、中断处理与DMA优化
1. SPI DMA配置
c
void QCA7000_SPI_DMA_Init() {
DMA_HandleTypeDef hdma_spi1_tx;
DMA_HandleTypeDef hdma_spi1_rx;
__HAL_RCC_DMA1_CLK_ENABLE();
hdma_spi1_tx.Instance = DMA1_Channel2;
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;
HAL_DMA_Init(&hdma_spi1_tx);
HAL_SPI_Transmit_DMA(&hspi1, txBuffer, dataSize);
}
2. UART流控制管理
c
void QCA7000_UART_FlowControl(bool enable) {
if (enable) {
HAL_GPIO_WritePin(UART_CTS_GPIO_Port, UART_CTS_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(UART_RTS_GPIO_Port, UART_RTS_Pin, GPIO_PIN_RESET);
} else {
HAL_GPIO_WritePin(UART_CTS_GPIO_Port, UART_CTS_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(UART_RTS_GPIO_Port, UART_RTS_Pin, GPIO_PIN_SET);
}
}
五、调试与测试方案
1. 逻辑分析仪捕获示例
c
Time | SPI信号 | UART信号
-------------------------------------
0μs | SCK:0 → MOSI:0x02
1μs | SCK:1 → MOSI:0x03
2μs | SCK:0 → MISO:0x01
3μs | SCK:1 → MISO:0xA5
2. 自动化测试脚本
c
import serial
import spidev
spi = spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz = 281250
uart = serial.Serial('/dev/ttyUSB0', 115200, timeout=1)
def test_spi_write_read():
spi.xfer2([0x02, 0x10, 0x55]) # 写入0x10寄存器0x55
response = spi.xfer2([0x03, 0x10, 0x00])
assert response[2] == 0x55
def test_uart_handshake():
uart.write(b'AT+STATUS\r\n')
response = uart.read_until(b'\r\n')
assert response == b'OK\r\n'
参考代码 用于QCA7000串行到电力线芯片的SPI/UART驱动程序 www.youwenfan.com/contentcsr/103365.html
六、性能优化
-
SPI时钟优化
-
根据线缆长度调整时钟频率(最长1米建议≤1MHz)
-
启用SPI CRC校验(需配置CRC多项式0x1021)
-
-
UART缓冲管理
c#define UART_RX_BUFFER_SIZE 256 volatile uint8_t uart_rx_buffer[UART_RX_BUFFER_SIZE]; volatile uint16_t uart_rx_index = 0; void USART2_IRQHandler() { if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE)) { uart_rx_buffer[uart_rx_index++] = HAL_UART_Receive(&huart2, &data, 1, 0); if (uart_rx_index >= UART_RX_BUFFER_SIZE) uart_rx_index = 0; } } -
低功耗模式
c// 进入SPI低功耗模式 HAL_SPI_Disable(&hspi1); HAL_GPIO_WritePin(QCA7000_SPI_CS_GPIO_Port, QCA7000_SPI_CS_Pin, GPIO_PIN_SET); // 唤醒操作 HAL_GPIO_WritePin(QCA7000_SPI_CS_GPIO_Port, QCA7000_SPI_CS_Pin, GPIO_PIN_RESET); HAL_SPI_Enable(&hspi1);
七、完整工程配置
-
STM32CubeMX配置
-
启用SPI1和USART2外设
-
配置NVIC中断优先级(SPI中断>UART中断)
-
使能DMA控制器(通道2用于SPI传输)
-
-
Makefile编译选项
cCC = arm-none-eabi-gcc CFLAGS = -mcpu=cortex-m3 -mthumb -O2 -Iinc -Isrc LDFLAGS = -TSTM32F103C8Tx_FLASH.ld -specs=nosys.specs all: main.elf main.elf: main.o spi_driver.o uart_driver.o $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
八、常见问题解决方案
| 现象 | 诊断方法 | 解决方案 |
|---|---|---|
| SPI通信失败 | 逻辑分析仪显示时钟频率异常 | 检查SPI预分频配置 |
| UART数据丢失 | 接收缓冲区溢出标志置位 | 增加DMA双缓冲机制 |
| CRC校验错误 | 对比主机/从机计算结果 | 验证多项式0x1021实现 |