Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

STM32 USB OTG HOST Library hangs trying to create file with FatFs

I am trying to create a file with FatFs on USB flash, but my f_open call trying to read boot sector for first time file system mount hangs on this function.

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;
  
}

The main problem is the loop which creates hanging state

while(status == USBH_MSC_BUSY );

So I do not know what to do to avoid this. Using debugger I discover that state is caused by parameter CmdStateMachine of structure USBH_MSC_BOTXferParam, type USBH_BOTXfer_TypeDef is equal CMD_UNINITIALIZED_STATE which actually cause miss up of switch statement of USBH_MSC_Read10 function.

/**
  * @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;
}

Here is USBH_BOTXfer_TypeDef type declaration;

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;

During the debug I discover that all fields of it is 0x00.

Here are my FatFs calls

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 function is:

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);
}

And device states are:

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;

The value of g_USB_MSC_HostStatus is received by standard USB HOST user callbacks.

like image 606
Mykola Avatar asked Jan 15 '16 22:01

Mykola


1 Answers

I think it is a bug in ST host library. I've hunted it down, as my usb host was unable to pass enumeration stage. After a fix the stack is Ok.

There is union _USB_Setup in usbh_def.h file in "STM32Cube/Repository/STM32Cube_FW_F7_V1.13.0/Middlewares/ST/STM32_USB_Host_Library/Core/Inc" (any chip, not only F7, any version, not only V1.13.0). It has uint16_t bmRequestType and uint16_t bRequest. These two fileds must be uint8_t as of USB specs. Fixing this issue made usb host go as needed. Enumeration stage passes ok, and all other stages as well.

like image 75
elephant Avatar answered Oct 18 '22 10:10

elephant