STM32L072CZ与MFRC522 SPI通信故障排查求助
我正在将MFRC522模块与STM32L072CZ MCU连接以实现RFID卡读写功能,参考GitHub项目、Arduino MFRC522库及RC522 datasheet编写了基础驱动,但读写模块寄存器全部失败。调试发现初始化函数无法写入寄存器,读取版本寄存器(手册说明应返回0x90或0x91)、DivIrqReg和TestBusReg均返回0,确定SPI通信存在问题,模块未正确初始化。已排查硬件连接、更换模块,SPI时钟预分频设为8(低于手册要求的10MHz),时钟相位极性配置为CPOL=LOW、CPHA=1EDGE,仍未解决问题,请求帮忙排查。
寄存器读写及初始化代码
寄存器写入函数
void Write_MFRC522(uint8_t addr, uint8_t val) { uint8_t addr_bits = (((addr<<1) & 0x7E)); /* CS LOW */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); //The address is located:0XXXXXX0 HAL_SPI_Transmit(&hspi1, &addr_bits, 1, 500); HAL_SPI_Transmit(&hspi1, &val, 1, 500); /* CS HIGH */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); }
寄存器读取函数
uint8_t Read_MFRC522(uint8_t addr) { uint8_t rx_bits; uint8_t addr_bits = (((addr<<1) & 0x7E) | 0x80); /* CS LOW */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); //The address is located:1XXXXXX0 HAL_SPI_Transmit(&hspi1, &addr_bits, 1, 500); HAL_SPI_Receive(&hspi1, &rx_bits, 1, 500); /* CS HIGH */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); return rx_bits; }
MFRC522初始化函数
void MFRC522_Init(void) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); // Set RST pin high for normal operation HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET); // Set NSS for SPI MFRC522_Reset(); Write_MFRC522(MifareREG_T_MODE, 0x80); //0x8D); Write_MFRC522(MifareREG_T_PRESCALER, 0xA9); Write_MFRC522(MifareREG_T_RELOAD_L, 0x03); Write_MFRC522(MifareREG_T_RELOAD_H, 0xE8); Write_MFRC522(MifareREG_TX_AUTO, 0x40); Write_MFRC522(MifareREG_MODE, 0x3D); AntennaOn(); }
SPI配置代码
void MX_SPI1_Init(void) { 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_8; 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(); } } void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(spiHandle->Instance==SPI1) { /* SPI1 clock enable */ __HAL_RCC_SPI1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**SPI1 GPIO Configuration PA4 ------> SPI1_NSS (Software Managed) PA5 ------> SPI1_SCK PA11 ------> SPI1_MISO PA12 ------> SPI1_MOSI */ GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; // GPIO_InitStruct.Alternate = GPIO_AF0_SPI1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USER CODE BEGIN SPI1_MspInit 1 */ // Configure the NSS pin (PA4) as a GPIO output. GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Pin = GPIO_PIN_4; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // Configure MISO to be input GPIO_InitStruct.Pin = GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); }
主函数代码
#include "main.h" #include "gpio.h" #include "mfrc_522.h" #include <stdio.h> #include <string.h> char str1[17]={'\0'}; char str2[17]={'\0'}; int main(void) { unsigned char status; /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_SPI1_Init(); /* USER CODE BEGIN 2 */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); // RST pin HAL_Delay(100); MFRC522_Init(); //HAL_Delay(1000); status = Read_MFRC522(MifareREG_DIV_IRQ); status = Read_MFRC522(MifareREG_TEST_BUS); status = Read_MFRC522(MifareREG_VERSION); while (1) { } }
排查建议
补全GPIO复用配置:在
HAL_SPI_MspInit中,PA5(SCK)和PA12(MOSI)的复用功能被注释,STM32L072的SPI1引脚复用为AF0,必须启用这行代码:GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;未设置复用功能时,引脚仅为普通GPIO,无法传输SPI信号。
优化MISO引脚配置:MISO引脚建议设置上拉电阻,避免模块未通信时引脚处于高阻态导致读取随机电平:
GPIO_InitStruct.Pull = GPIO_PULLUP;尝试修改SPI时序模式:部分MFRC522模块可能需要SPI_MODE3(CPOL=HIGH、CPHA=2EDGE),修改配置测试:
hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH; hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;调整CS信号时序:在拉低/拉高CS前后添加短暂延时,保证信号建立/保持时间:
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); HAL_Delay(1); // 增加建立时间 // SPI传输代码 HAL_Delay(1); // 增加保持时间 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);检查SPI传输返回值:添加
HAL_SPI_Transmit/HAL_SPI_Receive的返回值判断,确认SPI硬件是否正常工作:if(HAL_SPI_Transmit(&hspi1, &addr_bits, 1, 500) != HAL_OK) { Error_Handler(); }验证复位流程:确认RST引脚配置为推挽输出,初始化后读取引脚电平,确保复位操作生效。
内容的提问来源于stack exchange,提问作者Shahab

