Configuração das Interfaces de Hardware
Interface SPI (Modo 3)
// Parâmetros da comunicação SPI
#define CONFIG_SPI_CPOL SPI_POLARITY_HIGH
#define CONFIG_SPI_CPHA SPI_PHASE_2EDGE
#define CONFIG_SPI_DIVISOR 256
#define CONFIG_SPI_WORD_SIZE SPI_DATASIZE_8BIT
#define CONFIG_SPI_WAIT_MS 1000
// Mapeamento dos pinos GPIO
#define QCA_SPI_CLK_PIN GPIO_PIN_5
#define QCA_SPI_DATA_IN_PIN GPIO_PIN_6
#define QCA_SPI_DATA_OUT_PIN GPIO_PIN_7
#define QCA_SPI_CHIP_SEL_PIN GPIO_PIN_4
Interface UART
// Parâmetros da comunicação UART
#define CONFIG_UART_SPEED 115200
#define CONFIG_UART_DATA_BITS UART_WORDLENGTH_8D
#define CONFIG_UART_STOP_BITS UART_STOPBITS_1
#define CONFIG_UART_PARITY_MODE UART_PARITY_NO
#define CONFIG_UART_HW_FLOW UART_HWCONTROL_NONE
// Pinos de controle de fluxo
#define QCA_UART_CTS_PIN GPIO_PIN_0
#define QCA_UART_RTS_PIN GPIO_PIN_1
Módulo de Driver SPI
#include "stm32f1xx_hal.h"
static SPI_HandleTypeDef spi_handle;
void InicializaSPI_QCA7000(void) {
spi_handle.Instance = SPI1;
spi_handle.Init.Mode = SPI_MODE_MASTER;
spi_handle.Init.Direction = SPI_DIRECTION_2LINES;
spi_handle.Init.DataSize = CONFIG_SPI_WORD_SIZE;
spi_handle.Init.CLKPolarity = CONFIG_SPI_CPOL;
spi_handle.Init.CLKPhase = CONFIG_SPI_CPHA;
spi_handle.Init.NSS = SPI_NSS_SOFT;
spi_handle.Init.BaudRatePrescaler = CONFIG_SPI_DIVISOR;
spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;
HAL_SPI_Init(&spi_handle);
}
HAL_StatusTypeDef EnviaRecebeSPI_QCA7000(uint8_t *saida, uint8_t *entrada, uint16_t tamanho) {
return HAL_SPI_TransmitReceive(&spi_handle, saida, entrada, tamanho, CONFIG_SPI_WAIT_MS);
}
uint8_t LeRegistrador_QCA7000(uint8_t endereco) {
uint8_t pacote_envio[2] = {0x03, endereco};
uint8_t pacote_recebe[2] = {0};
HAL_GPIO_WritePin(QCA_SPI_CS_GPIO_Port, QCA_SPI_CHIP_SEL_PIN, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&spi_handle, pacote_envio, pacote_recebe, 2, CONFIG_SPI_WAIT_MS);
HAL_GPIO_WritePin(QCA_SPI_CS_GPIO_Port, QCA_SPI_CHIP_SEL_PIN, GPIO_PIN_SET);
return pacote_recebe[1];
}
HAL_StatusTypeDef EscreveRegistrador_QCA7000(uint8_t endereco, uint8_t valor) {
uint8_t pacote_envio[2] = {0x02, endereco};
return HAL_SPI_Transmit(&spi_handle, pacote_envio, 2, CONFIG_SPI_WAIT_MS);
}
Módullo de Driver UART
static UART_HandleTypeDef uart_handle;
void InicializaUART_QCA7000(void) {
uart_handle.Instance = USART2;
uart_handle.Init.BaudRate = CONFIG_UART_SPEED;
uart_handle.Init.WordLength = CONFIG_UART_DATA_BITS;
uart_handle.Init.StopBits = CONFIG_UART_STOP_BITS;
uart_handle.Init.Parity = CONFIG_UART_PARITY_MODE;
uart_handle.Init.HwFlowCtl = CONFIG_UART_HW_FLOW;
HAL_UART_Init(&uart_handle);
}
HAL_StatusTypeDef TransmiteUART_QCA7000(uint8_t *dados, uint16_t tamanho) {
return HAL_UART_Transmit(&uart_handle, dados, tamanho, CONFIG_SPI_WAIT_MS);
}
void USART2_IRQHandler(void) {
HAL_UART_IRQHandler(&uart_handle);
if (__HAL_UART_GET_FLAG(&uart_handle, UART_FLAG_RXNE)) {
uint8_t byte_recebido;
HAL_UART_Receive(&uart_handle, &byte_recebido, 1, 0);
// Processamento do byte recebido
}
}
Estrutura de Comandos SPI e Cálculo de CRC
typedef struct {
uint8_t comando;
uint8_t endereco;
uint8_t payload[4];
uint8_t checksum;
} ComandoQCA7000_t;
uint16_t CalculaCRC16(uint8_t *buffer, uint16_t tamanho) {
uint16_t acumulador = 0xFFFF;
for (uint16_t i = 0; i < tamanho; i++) {
acumulador ^= (uint16_t)buffer[i] << 8;
for (uint8_t bit = 0; bit < 8; bit++) {
if (acumulador & 0x8000)
acumulador = (acumulador << 1) ^ 0x1021;
else
acumulador <<= 1;
}
}
return acumulador;
}
Fluxo de Troca de Dados entre MCU e QCA7000
sequenceDiagram
participant Microcontrolador
participant Chip_QCA7000
Microcontrolador->>Chip_QCA7000: Quadro de comando (0x01 + endereço + dados)
Chip_QCA7000->>Microcontrolador: Byte de status (0x00 = sucesso)
Microcontrolador->>Chip_QCA7000: Solicitação de leitura (0x03 + endereço + CRC)
Chip_QCA7000-->>Microcontrolador: Confirmação via RTS/CTS
Configuração de DMA para SPI
void ConfiguraDMA_SPI_QCA7000(void) {
DMA_HandleTypeDef dma_tx_spi, dma_rx_spi;
__HAL_RCC_DMA1_CLK_ENABLE();
dma_tx_spi.Instance = DMA1_Channel2;
dma_tx_spi.Init.Direction = DMA_MEMORY_TO_PERIPH;
dma_tx_spi.Init.PeriphInc = DMA_PINC_DISABLE;
dma_tx_spi.Init.MemInc = DMA_MINC_ENABLE;
dma_tx_spi.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
dma_tx_spi.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
dma_tx_spi.Init.Mode = DMA_NORMAL;
HAL_DMA_Init(&dma_tx_spi);
HAL_SPI_Transmit_DMA(&spi_handle, buffer_tx, len_dados);
}
Gerenciamento de Controle de Fluxo UART
void HabilitaFluxoUART_QCA7000(bool ativar) {
if (ativar) {
HAL_GPIO_WritePin(QCA_UART_CTS_GPIO_Port, QCA_UART_CTS_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(QCA_UART_RTS_GPIO_Port, QCA_UART_RTS_PIN, GPIO_PIN_RESET);
} else {
HAL_GPIO_WritePin(QCA_UART_CTS_GPIO_Port, QCA_UART_CTS_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(QCA_UART_RTS_GPIO_Port, QCA_UART_RTS_PIN, GPIO_PIN_SET);
}
}
Captura com Analisador Lógico
Tempo | Sinal SPI | Sinal UART
-----------------------------------------
0µs | CLK:0 → MOSI:0x02
1µs | CLK:1 → MOSI:0x03
2µs | CLK:0 → MISO:0x01
3µs | CLK:1 → MISO:0xA5
Script de Teste Automatizado
import serial
import spidev
conexao_spi = spidev.SpiDev()
conexao_spi.open(0, 0)
conexao_spi.max_speed_hz = 281250
conexao_uart = serial.Serial('/dev/ttyUSB0', 115200, timeout=1)
def teste_escrita_leitura_spi():
conexao_spi.xfer2([0x02, 0x10, 0x55])
resultado = conexao_spi.xfer2([0x03, 0x10, 0x00])
assert resultado[2] == 0x55
def teste_handshake_uart():
conexao_uart.write(b'AT+STATUS\r\n')
resposta = conexao_uart.read_until(b'\r\n')
assert resposta == b'OK\r\n'
Otimização de Desempenho
Ajuste do clock SPI: Para cabos de até 1 metro, recomenda-se frequência máxima de 1 MHz. Ative a verificação CRC do SPI com polinômio 0x1021.
Buffer Circualr para Recepção UART
#define TAM_BUFFER_RX 256
volatile uint8_t buffer_rx_uart[TAM_BUFFER_RX];
volatile uint16_t posicao_rx = 0;
void USART2_IRQHandler(void) {
if (__HAL_UART_GET_FLAG(&uart_handle, UART_FLAG_RXNE)) {
uint8_t byte;
HAL_UART_Receive(&uart_handle, &byte, 1, 0);
buffer_rx_uart[posicao_rx++] = byte;
if (posicao_rx >= TAM_BUFFER_RX)
posicao_rx = 0;
}
}
Modo de Baixo Consumo
void EntraSleepSPI_QCA7000(void) {
HAL_SPI_Disable(&spi_handle);
HAL_GPIO_WritePin(QCA_SPI_CS_GPIO_Port, QCA_SPI_CHIP_SEL_PIN, GPIO_PIN_SET);
}
void AcordaSPI_QCA7000(void) {
HAL_GPIO_WritePin(QCA_SPI_CS_GPIO_Port, QCA_SPI_CHIP_SEL_PIN, GPIO_PIN_RESET);
HAL_SPI_Enable(&spi_handle);
}
Configuração do Projeto no STM32CubeMX
- Habiltiar periféricos SPI1 e USART2
- Configurar prioridades NVIC (SPI acima de UART)
- Ativar controlador DMA (Canal 2 para transferências SPI)
Makefile para Compilação
CC = arm-none-eabi-gcc
OPCOES_COMPILACAO = -mcpu=cortex-m3 -mthumb -O2 -Iinc -Isrc
OPCOES_LINK = -TSTM32F103C8Tx_FLASH.ld -specs=nosys.specs
alvo: firmware.elf
firmware.elf: main.o drv_spi.o drv_uart.o
$(CC) $(OPCOES_COMPILACAO) -o $@ $^ $(OPCOES_LINK)
Solução de Problemas Comuns
| Sintoma | Diagnóstico | Correção |
|---|---|---|
| Falha na comunicação SPI | Frequência de clock anômala no analisador | Revisar divisor de clock (BaudRatePrescaler) |
| Perda de dados UART | Flag de overflow no buffer de recepção | Implementar DMA com buffer duplo |
| Erro de verificação CRC | Divergência entre valores calculados | Validar implementação do polinômio 0x1021 |