手边有一个项目需要通过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.c
void 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);
}
}
