前缀
花了两天的时间整理了一下在使用STM32H743单片机开发usb相关功能时遇到的问题及解决方案,具体为以下2种情况:
1.USB插上单片机后,单片机卡死,导致长时间没有喂狗程序重启;
2.USB正常插拔后,使用FATFS挂载驱动,只要调用f_mount挂载接口就堵塞,线程无法调度,导致长时间没有喂狗程序重启;
具体方案:
STM32H743单片机通过STM32cubeMX加载FreeRTOS系统、USB_HOST和FATFS模块直接生成代码方式,在多线程下实现看门狗、USB检测、USB文件读写操作、其他功能。
STM32cubeMX配置
FREEETOS配置3个线程,SysInitTask线程用于USB_HOST相关初始化及喂狗,FileControlTask线程用于USB挂载及文件操作,CtrlTask用于其他控制功能。注意栈内存大小。
USB_OTG_FS配置Host_Only模式,全速模式。
USB_HOST配置由于只配置了USB_OTG_FS,因此此处只有Class for FS IP,这里选择MSC,表示只检测U盘,属性配置中USBH_MAX_DATA_BUFFER=512Byte表示磁盘分区大小,USBH_PROCESS_STACK_SIZE=512words,需要注意USBH_PROCESS_STACK_SIZE默认是128words,USB对应的栈内存大小不够,会导致程序运行中USB插上单片机后栈溢出,程序死机。相对应的,在FREEETOS配置SysInitTask线程时,其栈内存大小设置为1024words,否则也会导致栈内存溢出。
FATFS配置勾选USB Disk以及User-defined,对应的VOLUMES自动置2,相对应的,在FREEETOS配置FileControlTask线程时,其栈内存大小设置为512words,否则会导致栈内存溢出。FATFS生成的代码中需要使用到互斥锁,即USB_MUTEX置为Enabled。网上很多资料都是将f_mount挂载接口直接放在USBH_UserProcess回调中,一开始我也是这么处理,尝试了增加USB线程的栈内存大小没有起到用处,之后使用异步操作,在USBH_UserProcess回调中新建全局变量,触发对应状态后,在FileControlTask线程中进行单独处理。
STM32cubeMX自动生成的代码
USBH_UserProcess回调函数
static void USBH_UserProcess (USBH_HandleTypeDef *phost, uint8_t id)
{
/* USER CODE BEGIN CALL_BACK_1 */
switch (id) {
case HOST_USER_SELECT_CONFIGURATION:
printf("%s:%d\r\n", __func__, __LINE__);
break;
case HOST_USER_DISCONNECTION:
Appli_state = APPLICATION_DISCONNECT;
printf("%s:%d\r\n", __func__, __LINE__);
usb_ready = 2;
break;
case HOST_USER_CLASS_ACTIVE:
Appli_state = APPLICATION_READY;
printf("%s:%d USBHPath = %s\r\n", __func__, __LINE__, USBHPath);
usb_ready = 1;
break;
case HOST_USER_CONNECTION:
Appli_state = APPLICATION_START;
printf("%s:%d\r\n", __func__, __LINE__);
break;
default:
break;
}
/* USER CODE END CALL_BACK_1 */
}
SysInitTask线程用于USB_HOST相关初始化及喂狗
void SysInitTask(void *argument)
{
/* init code for USB_HOST */
MX_USB_HOST_Init();
/* USER CODE BEGIN SysInitTask */
printf("%s:%d\r\n", __func__, __LINE__);
/* Infinite loop */
for (;;) {
HAL_IWDG_Refresh(&hiwdg1);
// printf("%s:%d--watchDog\r\n", __func__, __LINE__);
// HAL_UART_Transmit(&huart1, "1", 1, HAL_MAX_DELAY);
osDelay(1000);
}
/* USER CODE END SysInitTask */
}
FileControlTask线程用于USB挂载及文件操作
void FileControlTask(void *argument)
{
/* USER CODE BEGIN FileControlTask*/
// printf("%s:%d\r\n", __func__, __LINE__);
FRESULT res;
/* Infinite loop */
for (;;) {
if (usb_ready == 1)
{
printf("%s:%d\r\n", __func__, __LINE__);
res = f_mount(&USBHFatFS, "0:", 1); // 挂载
if (res != FR_OK) {
printf("Mount failed: %d\n", res);
}
if (f_open(&USBHFile, "0:/LOG/log.txt", FA_OPEN_APPEND|FA_WRITE) == FR_OK)
{
uint8_t bytes_written;
f_write(&USBHFile, "\nNew line", 9, &bytes_written); // 追加内容
f_close(&USBHFile);
}
printf("test:%s\r\n", __func__);
usb_ready = 0;
}
else if (usb_ready == 2)
{
printf("%s:%d\r\n", __func__, __LINE__);
f_mount(NULL, "0:", 1); // 卸载FATFS
usb_ready = 0;
}
osDelay(10);
}
/* USER CODE END FileControlTask*/
}
共勉!