STM32 USB OTG主机库在使用FatFs创建文件时出现挂起的情况

11

我正在尝试使用FatFs在USB闪存上创建文件,但是我的f_open调用在第一次挂载文件系统时尝试读取引导扇区并卡住了。

DRESULT disk_read (
                   BYTE drv,            /* Physical drive number (0) */
                   BYTE *buff,          /* Pointer to the data buffer to store read data */
                   DWORD sector,        /* Start sector number (LBA) */
                   BYTE count           /* Sector count (1..255) */
                     )
{
  BYTE status = USBH_MSC_OK;
  
  if (drv || !count) return RES_PARERR;
  if (Stat & STA_NOINIT) return RES_NOTRDY;
  
  
  if(HCD_IsDeviceConnected(&USB_OTG_Core))
  {  
    
    do
    {
      status = USBH_MSC_Read10(&USB_OTG_Core, buff,sector,512 * count);
      USBH_MSC_HandleBOTXfer(&USB_OTG_Core ,&USB_Host);
      
      if(!HCD_IsDeviceConnected(&USB_OTG_Core))
      { 
        return RES_ERROR;
      }      
    }
    while(status == USBH_MSC_BUSY ); // Loop which create hanging state
  }
  
  if(status == USBH_MSC_OK)
    return RES_OK;
  return RES_ERROR;
  
}
主要问题是循环创建挂起状态。
while(status == USBH_MSC_BUSY );

所以我不知道该怎么做才能避免这个问题。使用调试器,我发现状态是由结构体USBH_MSC_BOTXferParam的参数CmdStateMachine引起的,类型为USBH_BOTXfer_TypeDef,它的值等于CMD_UNINITIALIZED_STATE,这实际上导致了USBH_MSC_Read10函数中switch语句的混乱。

/**
  * @brief  USBH_MSC_Read10 
  *         Issue the read command to the device. Once the response received, 
  *         it updates the status to upper layer
  * @param  dataBuffer : DataBuffer will contain the data to be read
  * @param  address : Address from which the data will be read
  * @param  nbOfbytes : NbOfbytes to be read
  * @retval Status
  */
uint8_t USBH_MSC_Read10(USB_OTG_CORE_HANDLE *pdev,
                        uint8_t *dataBuffer,
                        uint32_t address,
                        uint32_t nbOfbytes)
{
  uint8_t index;
  static USBH_MSC_Status_TypeDef status = USBH_MSC_BUSY;
  uint16_t nbOfPages;
  status = USBH_MSC_BUSY;
  
  if(HCD_IsDeviceConnected(pdev))
  {
    switch(USBH_MSC_BOTXferParam.CmdStateMachine)
    {
    case CMD_SEND_STATE:
      /*Prepare the CBW and relevant field*/
      USBH_MSC_CBWData.field.CBWTransferLength = nbOfbytes;
      USBH_MSC_CBWData.field.CBWFlags = USB_EP_DIR_IN;
      USBH_MSC_CBWData.field.CBWLength = CBW_LENGTH;
      
      USBH_MSC_BOTXferParam.pRxTxBuff = dataBuffer;
      
      for(index = CBW_CB_LENGTH; index != 0; index--)
      {
        USBH_MSC_CBWData.field.CBWCB[index] = 0x00;
      }
      
      USBH_MSC_CBWData.field.CBWCB[0]  = OPCODE_READ10; 
      
      /*logical block address*/
      
      USBH_MSC_CBWData.field.CBWCB[2]  = (((uint8_t*)&address)[3]);
      USBH_MSC_CBWData.field.CBWCB[3]  = (((uint8_t*)&address)[2]);
      USBH_MSC_CBWData.field.CBWCB[4]  = (((uint8_t*)&address)[1]);
      USBH_MSC_CBWData.field.CBWCB[5]  = (((uint8_t*)&address)[0]);
      
      /*USBH_MSC_PAGE_LENGTH = 512*/
      nbOfPages = nbOfbytes/ USBH_MSC_PAGE_LENGTH;  
      
      /*Tranfer length */
      USBH_MSC_CBWData.field.CBWCB[7]  = (((uint8_t *)&nbOfPages)[1]) ; 
      USBH_MSC_CBWData.field.CBWCB[8]  = (((uint8_t *)&nbOfPages)[0]) ; 
      
      
      USBH_MSC_BOTXferParam.BOTState = USBH_MSC_SEND_CBW;
      /* Start the transfer, then let the state machine 
      manage the other transactions */
      USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_USB_TRANSFERS;
      USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_BUSY;
      USBH_MSC_BOTXferParam.CmdStateMachine = CMD_WAIT_STATUS;
      
      status = USBH_MSC_BUSY;
      
      break;
      
    case CMD_WAIT_STATUS:
      
      if((USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_OK) && \
        (HCD_IsDeviceConnected(pdev)))
      { 
        /* Commands successfully sent and Response Received  */       
        USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
        status = USBH_MSC_OK;      
      }
      else if (( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_FAIL ) && \
        (HCD_IsDeviceConnected(pdev)))
      {
        /* Failure Mode */
        USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
      }
      
      else if ( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_PHASE_ERROR )
      {
        /* Failure Mode */
        USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
        status = USBH_MSC_PHASE_ERROR;    
      }
      else
      {
        /* Wait for the Commands to get Completed */
        /* NO Change in state Machine */
      }
      break;
      
    default:
      break;
    }
  }
  return status;
}

这里是USBH_BOTXfer_TypeDef类型声明;

typedef struct _BOTXfer
{
uint8_t MSCState;
uint8_t MSCStateBkp;
uint8_t MSCStateCurrent;
uint8_t CmdStateMachine;
uint8_t BOTState;
uint8_t BOTStateBkp;
uint8_t* pRxTxBuff;
uint16_t DataLength;
uint8_t BOTXferErrorCount;
uint8_t BOTXferStatus;
} USBH_BOTXfer_TypeDef;

在调试过程中,我发现它的所有字段都是0x00。

以下是我的FatFs调用。

int main(void)
{
    FATFS Fat;
    FIL file;
    FRESULT fr;
    
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
    
    /* Enable SWO output */
    DBGMCU->CR = 0x00000020;
    
    GPIOD->MODER=0x55000000;
    GPIOD->OTYPER = 0x00000000;
    GPIOD->OSPEEDR = 0x00000001;
    
    while(1)
    {   
        if (!USB_MSC_IsInitialized())
        {
            USB_MSC_Initialize();
        }
        
        if (USB_MSC_IsConnected())
        {
            GPIOD->ODR = (1 << 15);
            
            disk_initialize(0);
            
            fr = f_mount(0, &Fat);
            
            if(fr == FR_OK)
            {           
                fr = f_open(&file,"0:DP_lab8.pdf",(FA_CREATE_ALWAYS | FA_WRITE));
                
                if (fr == FR_OK)
                {
                    f_close(&file);
                }
                
                f_mount(0, NULL);
            }
        }
        else
        {
            GPIOD->ODR = (1 << 14);
        }
        
        USB_MSC_Main();
    }
}

USB_MSC_IsConnected 函数是:

int USB_MSC_IsConnected(void)
{
    if (g_USB_MSC_HostStatus == USB_DEV_NOT_SUPPORTED)
    {
        USB_MSC_Uninitialize();
    }
    
    return !(g_USB_MSC_HostStatus == USB_DEV_DETACHED ||
        g_USB_MSC_HostStatus == USB_HOST_NO_INIT ||
      g_USB_MSC_HostStatus == USB_DEV_NOT_SUPPORTED);
}

设备状态如下:

typedef enum
{
    USB_HOST_NO_INIT = 0,  /* USB interface not initialized */
    USB_DEV_DETACHED,      /* no device connected */
    USB_SPEED_ERROR,       /* unsupported USB speed */
    USB_DEV_NOT_SUPPORTED, /* unsupported device */
    USB_DEV_WRITE_PROTECT, /* device is write protected */
    USB_OVER_CURRENT,      /* overcurrent detected */
    USB_DEV_CONNECTED      /* device connected and ready */
} USB_HostStatus;

g_USB_MSC_HostStatus的值是通过标准USB HOST用户回调函数接收的。


1
提供一个 [mcve]。但这可能会太长了。ST库以臭名昭著的膨胀软件而闻名。如果它真的挂起来了,请检查标志位设置的位置以及为什么没有被清除。很可能是中断处理程序。使用断点和调试器。 - too honest for this site
我看不到你在哪里调用disk_read()。你能提供正在执行的代码示例吗? - Ivan Angelov
1
@Ivan Angelov: 它的HAL级别功能fatfs在disio.h中提供接口,然后在我们的情况下手动实现设备驱动程序使用文件(usbh_msc_fatfs.c)中的STM32F4 USB OTG HOST驱动程序。 FatFs调用此函数以从物理设备中执行读取,在我的情况下是FLASH DRIVE。 - Mykola
你正在运行哪个版本的STM固件?我有TM32Cube_FW_F4_V1.3.0,但我没有看到USBH_MSC_Read10(...)函数,我只有USBH_MSC_Read(...)。 - cleblanc
1
你的版本似乎比较旧。你可以尝试更新ST固件立方体;
  • 文件名 usbh_msc_scsi.h
  • 作者 MCD应用团队
  • 版本号 V3.1.0
  • 日期 2014年6月19日
- cleblanc
显示剩余6条评论
1个回答

1

我认为这是ST主机库中的一个错误。 我已经找到了它,因为我的USB主机无法通过枚举阶段。 修复后,堆栈正常。

在“STM32Cube / Repository / STM32Cube_FW_F7_V1.13.0 / Middlewares / ST / STM32_USB_Host_Library / Core / Inc”(任何芯片,不仅限于F7,任何版本,不仅限于V1.13.0)中有usbh_def.h文件中的union _USB_Setup。 它具有uint16_t bmRequestType和uint16_t bRequest。 根据USB规范,这两个字段必须是uint8_t。 修复此问题使USB主机正常工作。 枚举阶段通过,所有其他阶段也通过。


所有这些字段默认为uint8_t类型,但不起作用。 - Mykola
好的,您的闪存驱动器是否被USB主机枚举?然后,设备类是否已启动? - elephant
谢谢您的关注,但目前我无法访问微控制器,所以我会给您一些奖励。 - Mykola

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接