STM32L452启用FreeRTOS后SDMMC通信异常问题求助
问题原因与解决办法
核心问题分析
- FatFS未适配RTOS环境:默认FatFS配置未开启线程安全选项,多任务下文件操作会触发资源竞争,导致SD卡写入失败。
- HAL_Delay在FreeRTOS下的行为冲突:开启FreeRTOS后,SysTick被接管用于任务调度,原代码中的
HAL_Delay会导致任务阻塞逻辑异常,可能打断SDMMC的通信时序。 - 外设资源无互斥保护:SDMMC与SPI若共享总线或GPIO资源,多任务并行访问会引发冲突,干扰SD卡通信。
具体修复步骤
1. 开启FatFS的RTOS支持
在CubeIDE的Middleware > FATFS配置界面,找到USE_FREERTOS选项并设置为Enabled,让FatFS自动用FreeRTOS互斥量保护文件操作,避免资源竞争。
2. 重构为FreeRTOS任务结构
将SD卡写入和SPI采集拆分为独立任务,示例代码如下:
/* 任务句柄定义 */ TaskHandle_t xSDWriteTaskHandle = NULL; TaskHandle_t xSPICollectTaskHandle = NULL; /* SD卡写入任务 */ void vSDWriteTask(void *pvParameters) { FRESULT res; FIL fil; UINT bytesWritten; uint8_t writeBuf[128] = "Test data from SD task\r\n"; // 仅初始化时挂载一次文件系统 res = f_mount(&SDFatFS, SDPath, 1); if(res != FR_OK) { // 挂载失败处理,进入死循环 for(;;); } for(;;) { // 打开文件(不存在则创建) res = f_open(&fil, "test.txt", FA_OPEN_ALWAYS | FA_WRITE); if(res == FR_OK) { f_lseek(&fil, f_size(&fil)); // 移动到文件末尾 res = f_write(&fil, writeBuf, sizeof(writeBuf)-1, &bytesWritten); f_close(&fil); } vTaskDelay(pdMS_TO_TICKS(1000)); // 主动让出CPU } } /* SPI数据采集任务 */ void vSPICollectTask(void *pvParameters) { uint8_t spiData[32]; for(;;) { // SPI数据采集逻辑 HAL_SPI_Receive(&hspi1, spiData, sizeof(spiData), HAL_MAX_DELAY); // 数据处理逻辑 // ... vTaskDelay(pdMS_TO_TICKS(100)); // 主动让出CPU } } /* main函数初始化任务 */ int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_SDMMC1_SD_Init(); MX_SPI1_Init(); MX_FATFS_Init(); // 创建SD写入任务(栈大小1024,优先级2) xTaskCreate(vSDWriteTask, "SD_Write_Task", 1024, NULL, 2, &xSDWriteTaskHandle); // 创建SPI采集任务(栈大小512,优先级2) xTaskCreate(vSPICollectTask, "SPI_Collect_Task", 512, NULL, 2, &xSPICollectTaskHandle); vTaskStartScheduler(); // 启动RTOS调度器 // 调度器启动失败则进入死循环 for(;;); }
3. 优化任务调度逻辑
- 用
vTaskDelay替代HAL_Delay:vTaskDelay是FreeRTOS原生延时函数,会主动让出CPU,避免任务独占资源。 - 调整任务优先级:SD卡写入任务涉及磁盘IO,优先级不宜过高,避免长时间占用CPU影响SPI采集;两个任务优先级可设为相同,让调度器公平分配时间片。
4. 外设资源互斥保护(可选)
如果SPI与SDMMC共享总线或GPIO资源,需用FreeRTOS互斥量保护访问:
// 定义互斥量 SemaphoreHandle_t xPeriphMutex = NULL; // main函数中创建互斥量 xPeriphMutex = xSemaphoreCreateMutex(); // SD任务中访问外设前获取互斥量 if(xSemaphoreTake(xPeriphMutex, portMAX_DELAY) == pdTRUE) { // SD卡操作代码 xSemaphoreGive(xPeriphMutex); } // SPI任务中访问外设前获取互斥量 if(xSemaphoreTake(xPeriphMutex, portMAX_DELAY) == pdTRUE) { // SPI操作代码 xSemaphoreGive(xPeriphMutex); }
内容的提问来源于stack exchange,提问作者Hakob
相关产品推荐
相关产品推荐

