手边有一个项目需要通过TF卡存储日志，同时不方便频繁插拔TF卡使用读卡器浏览。因而想出通过USB插入的事件以动态热切换“本机读写”和“暴露LUN给USBMSC”两个模式。两个模式本身的实现方法本文不再赘述。具体实现思路为：两个模式属于竞争关系，使用FreeRTOS的锁绑定TF卡资源，一个Task进行本机读写，一个Task模拟USBMSC的占用，在模式切换时，根据需求配置锁的归属。使用OTG_FS_IRQHandler获取USB状态，hUsbDeviceFS.dev_state表示当前USB设备的状态，当其改变时通过消息队列发布。USB任务捕获队列信息，切换状态，申请或者释放TF卡设备锁。日志任务判断当前状态，申请或者释放TF卡设备锁。申请后/释放前需重新挂载或卸载文件系统。相关代码：void storage_usb_state_check(void) { static uint8_t last_state = 0xFF; uint8_t state = hUsbDeviceFS.dev_state; if ((last_state != state) && (usbStateQueueHandle != NULL)) { if (osMessagePut(usbStateQueueHandle, (uint32_t)state, 0) == osOK) { last_state = state; } } }stm32h7xx_it.cvoid OTG_FS_IRQHandler(void) { /* USER CODE BEGIN OTG_FS_IRQn 0 */ /* USER CODE END OTG_FS_IRQn 0 */ HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS); /* USER CODE BEGIN OTG_FS_IRQn 1 */ storage_usb_state_check(); /* USER CODE END OTG_FS_IRQn 1 */ }usb_mgr_task.c// ... extern osMessageQId usbStateQueueHandle; extern osMutexId sdCardMutexHandle; void StartUSBMgrTask(void const * argument) { osEvent event; uint8_t sd_mutex = 0; storage_usb_on = 0; storage_sd_on = 1; for (;;) { event = osMessageGet(usbStateQueueHandle, osWaitForever); if (event.status == osEventMessage) { uint8_t usb_dev_state = (uint8_t)event.value.v; switch (usb_dev_state) { case USBD_STATE_ADDRESSED: // case USBD_STATE_CONFIGURED: if(!sd_mutex) { storage_sd_on = 0; osMutexWait(sdCardMutexHandle, osWaitForever); sd_mutex = 1; storage_usb_on = 1; } break; case USBD_STATE_DEFAULT: case USBD_STATE_SUSPENDED: if (sd_mutex){ storage_usb_on = 0; osMutexRelease(sdCardMutexHandle); sd_mutex = 0; storage_sd_on = 1; } break; } } } }logger_task.c// ... void StartLoggerTask(void const *argument) { uint8_t sd_mutex = 0; vTaskDelay(pdMS_TO_TICKS(1000)); TickType_t xLastWakeTime = xTaskGetTickCount(); TickType_t xPeriod = pdMS_TO_TICKS(10); for (;;) { if (storage_sd_on) { if (!sd_mutex){ if(osMutexWait(sdCardMutexHandle, 0) != osOK){ continue; } sd_mutex = 1; } storage_mount(); // ... } else { if (sd_mutex){ storage_unmount(); osMutexRelease(sdCardMutexHandle); sd_mutex = 0; } } vTaskDelayUntil(&xLastWakeTime, xPeriod); } }