/** * @brief USB_OTG_HandleUSBSuspend_ISR * Indicates that SUSPEND state has been detected on the USB * @param pdev: device instance * @retval status */ static uint32_t DCD_HandleUSBSuspend_ISR(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_GINTSTS_TypeDef gintsts; USB_OTG_PCGCCTL_TypeDef power; USB_OTG_DSTS_TypeDef dsts; __IO uint8_t prev_status = 0; prev_status = pdev->dev.device_status; USBD_DCD_INT_fops->Suspend (pdev); dsts.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DSTS); /* Clear interrupt */ gintsts.d32 = 0; gintsts.b.usbsuspend = 1; USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTSTS, gintsts.d32); if((pdev->cfg.low_power) && (dsts.b.suspsts == 1) && (pdev->dev.connection_status == 1) && (prev_status == USB_OTG_CONFIGURED)) { /* switch-off the clocks */ power.d32 = 0; power.b.stoppclk = 1; USB_OTG_MODIFY_REG32(pdev->regs.PCGCCTL, 0, power.d32); power.b.gatehclk = 1; USB_OTG_MODIFY_REG32(pdev->regs.PCGCCTL, 0, power.d32); /* Request to enter Sleep mode after exit from current ISR */ SCB->SCR |= (SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk); } return 1; }
/** * @brief USB_OTG_USBH_handle_rx_qlvl_ISR * Handles the Rx Status Queue Level Interrupt * @param pdev: Selected device * @retval status */ #if defined ( __ICCARM__ ) /*!< IAR Compiler */ #pragma optimize = none #endif /* __CC_ARM */ static uint32_t USB_OTG_USBH_handle_rx_qlvl_ISR (USB_OTG_CORE_HANDLE *pdev) { USB_OTG_GRXFSTS_TypeDef grxsts; USB_OTG_GINTMSK_TypeDef intmsk; USB_OTG_HCTSIZn_TypeDef hctsiz; USB_OTG_HCCHAR_TypeDef hcchar; __IO uint8_t channelnum =0; uint32_t count; /* Disable the Rx Status Queue Level interrupt */ intmsk.d32 = 0; intmsk.b.rxstsqlvl = 1; USB_OTG_MODIFY_REG32( &pdev->regs.GREGS->GINTMSK, intmsk.d32, 0); grxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GRXSTSP); channelnum = grxsts.b.chnum; hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[channelnum]->HCCHAR); switch (grxsts.b.pktsts) { case GRXSTS_PKTSTS_IN: /* Read the data into the host buffer. */ #ifdef USE_HOST_MODE if ((grxsts.b.bcnt > 0) && (pdev->host.hc[channelnum].xfer_buff != (void *)0)) { USB_OTG_ReadPacket(pdev, pdev->host.hc[channelnum].xfer_buff, grxsts.b.bcnt); /*manage multiple Xfer */ pdev->host.hc[grxsts.b.chnum].xfer_buff += grxsts.b.bcnt; pdev->host.hc[grxsts.b.chnum].xfer_count += grxsts.b.bcnt; count = pdev->host.hc[channelnum].xfer_count; pdev->host.XferCnt[channelnum] = count; hctsiz.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[channelnum]->HCTSIZ); if(hctsiz.b.pktcnt > 0) { /* re-activate the channel when more packets are expected */ hcchar.b.chen = 1; hcchar.b.chdis = 0; USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[channelnum]->HCCHAR, hcchar.d32); } } #endif break; case GRXSTS_PKTSTS_IN_XFER_COMP: case GRXSTS_PKTSTS_DATA_TOGGLE_ERR: case GRXSTS_PKTSTS_CH_HALTED: default: break; } /* Enable the Rx Status Queue Level interrupt */ intmsk.b.rxstsqlvl = 1; USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, 0, intmsk.d32); return 1; }
//-------------------------------------------------------------- void USB_OTG_ActiveRemoteWakeup(USB_OTG_CORE_HANDLE * pdev) { USB_OTG_DCTL_TypeDef dctl; USB_OTG_DSTS_TypeDef dsts; USB_OTG_PCGCCTL_TypeDef power; if (pdev->dev.DevRemoteWakeup) { dsts.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DSTS); if (dsts.b.suspsts == 1) { if (pdev->cfg.low_power) { /* un-gate USB Core clock */ power.d32 = USB_OTG_READ_REG32(&pdev->regs.PCGCCTL); power.b.gatehclk = 0; power.b.stoppclk = 0; USB_OTG_WRITE_REG32(pdev->regs.PCGCCTL, power.d32); } /* active Remote wakeup signaling */ dctl.d32 = 0; dctl.b.rmtwkupsig = 1; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DCTL, 0, dctl.d32); USB_OTG_BSP_mDelay(5); USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DCTL, dctl.d32, 0); } } }
/** * @brief USB_OTG_HandleConnectorIDStatusChange_ISR * handles the Connector ID Status Change Interrupt * @param None * @retval : status */ static uint32_t USB_OTG_HandleConnectorIDStatusChange_ISR(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_GINTMSK_TypeDef gintmsk; USB_OTG_GOTGCTL_TypeDef gotgctl; USB_OTG_GINTSTS_TypeDef gintsts; gintsts.d32 = 0 ; gintmsk.d32 = 0 ; gotgctl.d32 = 0 ; gintmsk.b.sofintr = 1; USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, gintmsk.d32, 0); gotgctl.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GOTGCTL); /* B-Device connector (Device Mode) */ if (gotgctl.b.conidsts) { USB_OTG_DisableGlobalInt(pdev); USB_OTG_CoreInitDev(pdev); USB_OTG_EnableGlobalInt(pdev); pdev->otg.OTG_State = B_PERIPHERAL; } else { USB_OTG_DisableGlobalInt(pdev); USB_OTG_CoreInitHost(pdev); USB_OTG_EnableGlobalInt(pdev); pdev->otg.OTG_State = A_HOST; } /* Set flag and clear interrupt */ gintsts.b.conidstschng = 1; USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GINTSTS, gintsts.d32); return 1; }
/******************************************************************************* * Function Name : OTGD_FS_EPDeactivate * Description : Deactivates an EP * Input : ep * Output : None * Return : num_in_ep *******************************************************************************/ USB_OTG_Status OTGD_FS_EPDeactivate(USB_OTG_EP *ep) { USB_OTG_Status status = USB_OTG_OK; USB_OTG_DEPCTLx_TypeDef depctl; __IO uint32_t *addr; USB_OTG_DAINT_TypeDef daintmsk; depctl.d32 = 0; daintmsk.d32 = 0; /* Read DEPCTLn register */ if (ep->is_in == 1) { addr = &USB_OTG_FS_regs.DINEPS[ep->num]->DIEPCTLx; daintmsk.ep.in = 1 << ep->num; } else { addr = &USB_OTG_FS_regs.DOUTEPS[ep->num]->DOEPCTLx; daintmsk.ep.out = 1 << ep->num; } depctl.b.usbactep = 0; USB_OTG_WRITE_REG32(addr, depctl.d32); /* Disable the Interrupt for this EP */ USB_OTG_MODIFY_REG32(&USB_OTG_FS_regs.DEV->DAINTMSK, daintmsk.d32, 0); return status; }
//-------------------------------------------------------------- USB_OTG_STS USB_OTG_EPActivate(USB_OTG_CORE_HANDLE * pdev, USB_OTG_EP * ep) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_DEPCTL_TypeDef depctl; USB_OTG_DAINT_TypeDef daintmsk; __IO uint32_t *addr; depctl.d32 = 0; daintmsk.d32 = 0; /* Read DEPCTLn register */ if (ep->is_in == 1) { addr = &pdev->regs.INEP_REGS[ep->num]->DIEPCTL; daintmsk.ep.in = 1 << ep->num; } else { addr = &pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL; daintmsk.ep.out = 1 << ep->num; } /* If the EP is already active don't change the EP Control * register. */ depctl.d32 = USB_OTG_READ_REG32(addr); if (!depctl.b.usbactep) { depctl.b.mps = ep->maxpacket; depctl.b.eptype = ep->type; depctl.b.txfnum = ep->tx_fifo_num; depctl.b.setd0pid = 1; depctl.b.usbactep = 1; USB_OTG_WRITE_REG32(addr, depctl.d32); } /* Enable the Interrupt for this EP */ USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DAINTMSK, 0, daintmsk.d32); return status; }
//-------------------------------------------------------------- USB_OTG_STS USB_OTG_EPDeactivate(USB_OTG_CORE_HANDLE * pdev, USB_OTG_EP * ep) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_DEPCTL_TypeDef depctl; USB_OTG_DAINT_TypeDef daintmsk; __IO uint32_t *addr; depctl.d32 = 0; daintmsk.d32 = 0; /* Read DEPCTLn register */ if (ep->is_in == 1) { addr = &pdev->regs.INEP_REGS[ep->num]->DIEPCTL; daintmsk.ep.in = 1 << ep->num; } else { addr = &pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL; daintmsk.ep.out = 1 << ep->num; } depctl.b.usbactep = 0; USB_OTG_WRITE_REG32(addr, depctl.d32); /* Disable the Interrupt for this EP */ USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DAINTMSK, daintmsk.d32, 0); return status; }
//-------------------------------------------------------------- USB_OTG_STS USB_OTG_EnableDevInt(USB_OTG_CORE_HANDLE * pdev) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_GINTMSK_TypeDef intmsk; intmsk.d32 = 0; /* Disable all interrupts. */ USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTMSK, 0); /* Clear any pending interrupts */ USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTSTS, 0xFFFFFFFF); /* Enable the common interrupts */ USB_OTG_EnableCommonInt(pdev); if (pdev->cfg.dma_enable == 0) { intmsk.b.rxstsqlvl = 1; } /* Enable interrupts matching to the Device mode ONLY */ intmsk.b.usbsuspend = 1; intmsk.b.usbreset = 1; intmsk.b.enumdone = 1; intmsk.b.inepintr = 1; intmsk.b.outepintr = 1; intmsk.b.sofintr = 1; intmsk.b.incomplisoin = 1; intmsk.b.incomplisoout = 1; intmsk.b.sessreqintr = 1; intmsk.b.otgintr = 1; USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, intmsk.d32, intmsk.d32); return status; }
//-------------------------------------------------------------- USB_OTG_STS USB_OTG_EP0Activate(USB_OTG_CORE_HANDLE * pdev) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_DSTS_TypeDef dsts; USB_OTG_DEPCTL_TypeDef diepctl; USB_OTG_DCTL_TypeDef dctl; dctl.d32 = 0; /* Read the Device Status and Endpoint 0 Control registers */ dsts.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DSTS); diepctl.d32 = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[0]->DIEPCTL); /* Set the MPS of the IN EP based on the enumeration speed */ switch (dsts.b.enumspd) { case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: case DSTS_ENUMSPD_FS_PHY_48MHZ: diepctl.b.mps = DEP0CTL_MPS_64; break; case DSTS_ENUMSPD_LS_PHY_6MHZ: diepctl.b.mps = DEP0CTL_MPS_8; break; } USB_OTG_WRITE_REG32(&pdev->regs.INEP_REGS[0]->DIEPCTL, diepctl.d32); dctl.b.cgnpinnak = 1; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DCTL, dctl.d32, dctl.d32); return status; }
/** * @brief This Function set USB device address * @param pdev: device instance * @param address: new device address * @retval : status */ void DCD_EP_SetAddress (USB_OTG_CORE_HANDLE *pdev, uint8_t address) { USB_OTG_DCFG_TypeDef dcfg; dcfg.d32 = 0; dcfg.b.devaddr = address; USB_OTG_MODIFY_REG32( &pdev->regs.DREGS->DCFG, 0, dcfg.d32); }
/** * @brief DCD_HandleResume_ISR * Indicates that the USB_OTG controller has detected a resume or * remote Wake-up sequence * @param pdev: device instance * @retval status */ static uint32_t DCD_HandleResume_ISR(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_GINTSTS_TypeDef gintsts; USB_OTG_DCTL_TypeDef devctl; USB_OTG_PCGCCTL_TypeDef power; if(pdev->cfg.low_power) { /* un-gate USB Core clock */ power.d32 = USB_OTG_READ_REG32(&pdev->regs.PCGCCTL); power.b.gatehclk = 0; power.b.stoppclk = 0; USB_OTG_WRITE_REG32(pdev->regs.PCGCCTL, power.d32); } /* Clear the Remote Wake-up Signaling */ devctl.d32 = 0; devctl.b.rmtwkupsig = 1; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DCTL, devctl.d32, 0); /* Inform upper layer by the Resume Event */ USBD_DCD_INT_fops->Resume (pdev); /* Clear interrupt */ gintsts.d32 = 0; gintsts.b.wkupintr = 1; USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GINTSTS, gintsts.d32); return 1; }
//-------------------------------------------------------------- USB_OTG_STS USB_OTG_EnableHostInt(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_GINTMSK_TypeDef intmsk; intmsk.d32 = 0; /* Disable all interrupts. */ USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTMSK, 0); /* Clear any pending interrupts. */ USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTSTS, 0xFFFFFFFF); /* Enable the common interrupts */ USB_OTG_EnableCommonInt(pdev); if (pdev->cfg.dma_enable == 0) { intmsk.b.rxstsqlvl = 1; } intmsk.b.portintr = 1; intmsk.b.hcintr = 1; intmsk.b.disconnect = 1; intmsk.b.sofintr = 1; intmsk.b.incomplisoout = 1; USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, intmsk.d32, intmsk.d32); return status; }
/** * @brief DCD_HandleRxStatusQueueLevel_ISR * Handles the Rx Status Queue Level Interrupt * @param pdev: device instance * @retval status */ static uint32_t DCD_HandleRxStatusQueueLevel_ISR(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_GINTMSK_TypeDef int_mask; USB_OTG_DRXSTS_TypeDef status; USB_OTG_EP *ep; /* Disable the Rx Status Queue Level interrupt */ int_mask.d32 = 0; int_mask.b.rxstsqlvl = 1; USB_OTG_MODIFY_REG32( &pdev->regs.GREGS->GINTMSK, int_mask.d32, 0); /* Get the Status from the top of the FIFO */ status.d32 = USB_OTG_READ_REG32( &pdev->regs.GREGS->GRXSTSP ); ep = &pdev->dev.out_ep[status.b.epnum]; switch (status.b.pktsts) { case STS_GOUT_NAK: break; case STS_DATA_UPDT: if (status.b.bcnt) { USB_OTG_ReadPacket(pdev,ep->xfer_buff, status.b.bcnt); ep->xfer_buff += status.b.bcnt; ep->xfer_count += status.b.bcnt; } break; case STS_XFER_COMP: break; case STS_SETUP_COMP: break; case STS_SETUP_UPDT: /* Copy the setup packet received in FIFO into the setup buffer in RAM */ USB_OTG_ReadPacket(pdev , pdev->dev.setup_packet, 8); ep->xfer_count += status.b.bcnt; break; default: break; } /* Enable the Rx Status Queue Level interrupt */ USB_OTG_MODIFY_REG32( &pdev->regs.GREGS->GINTMSK, 0, int_mask.d32); return 1; }
/** * @brief USB_OTG_BSP_Suspend * Handles the Enter USB to Suspend Mode * @param pdev: Selected device * @retval Status */ void USB_OTG_BSP_Suspend(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_HPRT0_TypeDef hprt0; USB_OTG_PCGCCTL_TypeDef power; hprt0.d32 = 0; hprt0.d32 = USB_OTG_ReadHPRT0(pdev); hprt0.b.prtsusp = 1; USB_OTG_WRITE_REG32(pdev->regs.HPRT0, hprt0.d32); /* switch-off the clocks */ power.d32 = 0; power.b.stoppclk = 1; USB_OTG_MODIFY_REG32(pdev->regs.PCGCCTL, 0, power.d32); power.b.gatehclk = 1; USB_OTG_MODIFY_REG32(pdev->regs.PCGCCTL, 0, power.d32); }
//-------------------------------------------------------------- USB_OTG_STS USB_OTG_DisableGlobalInt(USB_OTG_CORE_HANDLE * pdev) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_GAHBCFG_TypeDef ahbcfg; ahbcfg.d32 = 0; ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GAHBCFG, ahbcfg.d32, 0); return status; }
/******************************************************************************* * Function Name : OTGD_FS_DisableGlobalInt * Description : Disables the controller's Global Int in the AHB Config reg * Input : None * Output : None * Return : Status *******************************************************************************/ USB_OTG_Status OTGD_FS_DisableGlobalInt(void) { USB_OTG_Status status = USB_OTG_OK; USB_OTG_GAHBCFG_TypeDef ahbcfg; ahbcfg.d32 = 0; ahbcfg.b.gintmsk = 1; /* Enable interrupts */ USB_OTG_MODIFY_REG32(&USB_OTG_FS_regs.GREGS->GAHBCFG, ahbcfg.d32, 0); return status; }
/******************************************************************************* * Function Name : PCD_EP_SetAddress * Description : This Function set USB device address * Input : The new device Address to be set. * Output : None * Return : status *******************************************************************************/ void PCD_EP_SetAddress (uint8_t address) { USB_OTG_DCFG_TypeDef dcfg; dcfg.d32 = 0; dcfg.b.devaddr = address; USB_OTG_MODIFY_REG32( &USB_OTG_FS_regs.DEV->DCFG, 0, dcfg.d32); }
/** * @brief DCD_WriteEmptyTxFifo * check FIFO for the next packet to be loaded * @param pdev: device instance * @retval status */ static uint32_t DCD_WriteEmptyTxFifo(USB_OTG_CORE_HANDLE *pdev, uint32_t epnum) { USB_OTG_DTXFSTSn_TypeDef txstatus; USB_OTG_EP *ep; uint32_t len = 0; uint32_t len32b; txstatus.d32 = 0; ep = &pdev->dev.in_ep[epnum]; len = ep->xfer_len - ep->xfer_count; if (len > ep->maxpacket) { len = ep->maxpacket; } len32b = (len + 3) / 4; txstatus.d32 = USB_OTG_READ_REG32( &pdev->regs.INEP_REGS[epnum]->DTXFSTS); while (txstatus.b.txfspcavail > len32b && ep->xfer_count < ep->xfer_len && ep->xfer_len != 0) { /* Write the FIFO */ len = ep->xfer_len - ep->xfer_count; if (len > ep->maxpacket) { len = ep->maxpacket; } len32b = (len + 3) / 4; USB_OTG_WritePacket (pdev , ep->xfer_buff, epnum, len); ep->xfer_buff += len; ep->xfer_count += len; txstatus.d32 = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[epnum]->DTXFSTS); // clear TXEmpty, to prevent endless stream of irq from hanging system. per: // https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a%2f%2fmy%2est%2ecom%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex%5fmx%5fstm32%2fYet%20another%20STM32F1057%20USB%20OTG%20driver%20issue%20%28VCP%20device%29&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=3190 if( ep->xfer_count >= ep->xfer_len){ uint32_t fifoemptymsk = 1 << ep->num; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0); break; } } return 1; }
/** * @brief DCD_WriteEmptyTxFifo * check FIFO for the next packet to be loaded * @param pdev: device instance * @retval status */ static uint32_t DCD_WriteEmptyTxFifo(USB_OTG_CORE_HANDLE *pdev, uint32_t epnum) { USB_OTG_DTXFSTSn_TypeDef txstatus; USB_OTG_EP *ep; uint32_t len = 0; uint32_t len32b; txstatus.d32 = 0; ep = &pdev->dev.in_ep[epnum]; len = ep->xfer_len - ep->xfer_count; if (len > ep->maxpacket) { len = ep->maxpacket; } len32b = (len + 3) / 4; txstatus.d32 = USB_OTG_READ_REG32( &pdev->regs.INEP_REGS[epnum]->DTXFSTS); while (txstatus.b.txfspcavail > len32b && ep->xfer_count < ep->xfer_len && ep->xfer_len != 0) { /* Write the FIFO */ len = ep->xfer_len - ep->xfer_count; if (len > ep->maxpacket) { len = ep->maxpacket; } len32b = (len + 3) / 4; USB_OTG_WritePacket (pdev , ep->xfer_buff, epnum, len); ep->xfer_buff += len; ep->xfer_count += len; // this code turns off the "empty interrupt" // without it the USB is subject to perpetual interrupts // see my.st.com, "Yet another STM32F105/7 USB OTG driver issue (VCP device)" // this code might also work if put in DCD_HandleInEP_ISR if (ep->xfer_count >= ep->xfer_len) { uint32_t fifoemptymsk = 1 << ep->num; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0); break; } txstatus.d32 = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[epnum]->DTXFSTS); } return 1; }
/** * @brief DCD_WriteEmptyTxFifo * check FIFO for the next packet to be loaded * @param pdev: device instance * @retval status */ static uint32_t DCD_WriteEmptyTxFifo(USB_OTG_CORE_HANDLE *pdev, uint32_t epnum) { USB_OTG_DTXFSTSn_TypeDef txstatus; USB_OTG_EP *ep; uint32_t len = 0; uint32_t len32b; txstatus.d32 = 0; uint32_t fifoemptymsk; // HJI Patch from STM Forum, Tags: usb vcp stm32_usb-s-device_lib ep = &pdev->dev.in_ep[epnum]; len = ep->xfer_len - ep->xfer_count; if (len > ep->maxpacket) { len = ep->maxpacket; } len32b = (len + 3) / 4; txstatus.d32 = USB_OTG_READ_REG32( &pdev->regs.INEP_REGS[epnum]->DTXFSTS); while (txstatus.b.txfspcavail > len32b && ep->xfer_count < ep->xfer_len && ep->xfer_len != 0) { /* Write the FIFO */ len = ep->xfer_len - ep->xfer_count; if (len > ep->maxpacket) { len = ep->maxpacket; } len32b = (len + 3) / 4; USB_OTG_WritePacket (pdev , ep->xfer_buff, epnum, len); ep->xfer_buff += len; ep->xfer_count += len; if( ep->xfer_count >= ep->xfer_len) // HJI Patch from STM Forum, Tags: usb vcp stm32_usb-s-device_lib { // HJI Patch from STM Forum, Tags: usb vcp stm32_usb-s-device_lib fifoemptymsk = 1 << ep->num; // HJI Patch from STM Forum, Tags: usb vcp stm32_usb-s-device_lib USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0); // HJI Patch from STM Forum, Tags: usb vcp stm32_usb-s-device_lib break; // HJI Patch from STM Forum, Tags: usb vcp stm32_usb-s-device_lib } // HJI Patch from STM Forum, Tags: usb vcp stm32_usb-s-device_lib txstatus.d32 = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[epnum]->DTXFSTS); } return 1; }
/** * @brief DCD_WriteEmptyTxFifo * check FIFO for the next packet to be loaded * @param pdev: device instance * @retval status */ static uint32_t DCD_WriteEmptyTxFifo(USB_OTG_CORE_HANDLE *pdev, uint32_t epnum) { USB_OTG_DTXFSTSn_TypeDef txstatus; USB_OTG_EP *ep; uint32_t len = 0; uint32_t len32b; txstatus.d32 = 0; ep = &pdev->dev.in_ep[epnum]; len = ep->xfer_len - ep->xfer_count; if (len > ep->maxpacket) { len = ep->maxpacket; } len32b = (len + 3) / 4; txstatus.d32 = USB_OTG_READ_REG32( &pdev->regs.INEP_REGS[epnum]->DTXFSTS); while (txstatus.b.txfspcavail > len32b && ep->xfer_count < ep->xfer_len && ep->xfer_len != 0) { /* Write the FIFO */ len = ep->xfer_len - ep->xfer_count; if (len > ep->maxpacket) { len = ep->maxpacket; } len32b = (len + 3) / 4; USB_OTG_WritePacket (pdev , ep->xfer_buff, epnum, len); ep->xfer_buff += len; ep->xfer_count += len; // FIXME THIS FOLLOWING FOUR LINES ARE A WORKAROUND FOR THE INFINITY EMPTY BUFFER INTERRUPT BUG if( ep->xfer_count >= ep->xfer_len) { uint32_t fifoemptymsk = 1 << ep->num; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0); break; } txstatus.d32 = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[epnum]->DTXFSTS); } return 1; }
/** * @brief USBD_OTG_EP1IN_ISR_Handler * handles all USB Interrupts * @param pdev: device instance * @retval status */ uint32_t USBD_OTG_EP1IN_ISR_Handler (USB_OTG_CORE_HANDLE *pdev) { USB_OTG_DIEPINTn_TypeDef diepint; uint32_t fifoemptymsk, msk, emp; msk = USB_OTG_READ_REG32(&pdev->regs.DREGS->DINEP1MSK); emp = USB_OTG_READ_REG32(&pdev->regs.DREGS->DIEPEMPMSK); msk |= ((emp >> 1 ) & 0x1) << 7; diepint.d32 = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[1]->DIEPINT) & msk; if ( diepint.b.xfercompl ) { fifoemptymsk = 0x1 << 1; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0); CLEAR_IN_EP_INTR(1, xfercompl); /* TX COMPLETE */ USBD_DCD_INT_fops->DataInStage(pdev , 1); } if ( diepint.b.ahberr ) { CLEAR_IN_EP_INTR(1, ahberr); } if ( diepint.b.epdisabled ) { CLEAR_IN_EP_INTR(1, epdisabled); } if ( diepint.b.timeout ) { CLEAR_IN_EP_INTR(1, timeout); } if (diepint.b.intktxfemp) { CLEAR_IN_EP_INTR(1, intktxfemp); } if (diepint.b.intknepmis) { CLEAR_IN_EP_INTR(1, intknepmis); } if (diepint.b.inepnakeff) { CLEAR_IN_EP_INTR(1, inepnakeff); } if (diepint.b.emptyintr) { DCD_WriteEmptyTxFifo(pdev , 1); // <--------- fix: from here fifoemptymsk = 0x1 << 1; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0) //CLEAR_IN_EP_INTR(1, emptyintr); // <--------- fix: to here }
static uint32_t USB_OTG_USBH_handle_nptxfempty_ISR(USB_OTG_CORE_HANDLE*pdev) { USB_OTG_GINTMSK_TypeDef intmsk; USB_OTG_HNPTXSTS_TypeDef hnptxsts; uint16_t len_words, len; hnptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->HNPTXSTS); #ifdef DEBUG if (hnptxsts.b.chnum > 0) p_err("nptxfempty:%d\n", hnptxsts.b.nptxfspcavail); if (pdev->host.hc[hnptxsts.b.chnum].xfer_len == 0) { p_err("%s xfer_len == 0, %d\n", __FUNCTION__, hnptxsts.b.chnum); USB_OTG_HC_Halt(pdev, hnptxsts.b.chnum); //test return 0; } #endif len_words = (pdev->host.hc[hnptxsts.b.chnum].xfer_len + 3) / 4; while ((hnptxsts.b.nptxfspcavail > len_words) && (pdev ->host.hc[hnptxsts.b.chnum].xfer_len != 0)) { len = hnptxsts.b.nptxfspcavail * 4; if (len > pdev->host.hc[hnptxsts.b.chnum].xfer_len) { /* Last packet */ len = pdev->host.hc[hnptxsts.b.chnum].xfer_len; intmsk.d32 = 0; intmsk.b.nptxfempty = 1; USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, intmsk.d32, 0); } len_words = (pdev->host.hc[hnptxsts.b.chnum].xfer_len + 3) / 4; USB_OTG_WritePacket(pdev, pdev->host.hc[hnptxsts.b.chnum].xfer_buff, hnptxsts.b.chnum, len); pdev->host.hc[hnptxsts.b.chnum].xfer_buff += len; pdev->host.hc[hnptxsts.b.chnum].xfer_len -= len; pdev->host.hc[hnptxsts.b.chnum].xfer_count += len; hnptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->HNPTXSTS); } return 1; }
/** * @brief DCD_WriteEmptyTxFifo * check FIFO for the next packet to be loaded * @param pdev: device instance * @retval status */ static uint32_t DCD_WriteEmptyTxFifo(USB_OTG_CORE_HANDLE *pdev, uint32_t epnum) { USB_OTG_DTXFSTSn_TypeDef txstatus; USB_OTG_EP *ep; uint32_t len = 0; uint32_t len32b; txstatus.d32 = 0; ep = &pdev->dev.in_ep[epnum]; len = ep->xfer_len - ep->xfer_count; if (len > ep->maxpacket) { len = ep->maxpacket; } len32b = (len + 3) / 4; txstatus.d32 = USB_OTG_READ_REG32( &pdev->regs.INEP_REGS[epnum]->DTXFSTS); while (txstatus.b.txfspcavail > len32b && ep->xfer_count < ep->xfer_len && ep->xfer_len != 0) { /* Write the FIFO */ len = ep->xfer_len - ep->xfer_count; if (len > ep->maxpacket) { len = ep->maxpacket; } len32b = (len + 3) / 4; USB_OTG_WritePacket (pdev , ep->xfer_buff, epnum, len); ep->xfer_buff += len; ep->xfer_count += len; //According to "bil.til" from ST E2E Community if( ep->xfer_count >= ep->xfer_len) { uint32_t fifoemptymsk = 1 << ep->num; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0); break; } txstatus.d32 = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[epnum]->DTXFSTS); } return 1; }
/******************************************************************************* * Function Name : PCD_WriteEmptyTxFifo * Description : Checks Fifo for the next packet to be loaded. * Input : None * Output : None * Return : Status *******************************************************************************/ static uint32_t PCD_WriteEmptyTxFifo(uint32_t epnum) { USB_OTG_DTXFSTS_TypeDef txstatus; USB_OTG_EP *ep; uint32_t len = 0; uint32_t dwords = 0; uint32_t fifoemptymsk = 0; txstatus.d32 = 0; ep = PCD_GetInEP(epnum); len = ep->xfer_len - ep->xfer_count; if (len > ep->maxpacket) { len = ep->maxpacket; } dwords = (len + 3) / 4; txstatus.d32 = USB_OTG_READ_REG32( &USB_OTG_FS_regs.DINEPS[epnum]->DTXFSTSx); while ((txstatus.b.txfspcavail > dwords) && (ep->xfer_count < ep->xfer_len) && (ep->xfer_len) != 0) { len = ep->xfer_len - ep->xfer_count; if (len > ep->maxpacket) { len = ep->maxpacket; } dwords = (len + 3) / 4; OTGD_FS_WritePacket(ep->xfer_buff, epnum, len); ep->xfer_count += len; ep->xfer_buff += len; txstatus.d32 = USB_OTG_READ_REG32(&USB_OTG_FS_regs.DINEPS[epnum]->DTXFSTSx); /* Mask the TxFIFOEmpty interrupt to prevent re-entring this routine */ if (ep->xfer_len == ep->xfer_count) { fifoemptymsk = 0x1 << ep->num; USB_OTG_MODIFY_REG32(&USB_OTG_FS_regs.DEV->DIEPEMPMSK, fifoemptymsk, 0); } } return 1; }
/** * @brief USBD_OTG_EP1IN_ISR_Handler * handles all USB Interrupts * @param pdev: device instance * @retval status */ uint32_t USBD_OTG_EP1IN_ISR_Handler (USB_OTG_CORE_HANDLE *pdev) { USB_OTG_DIEPINTn_TypeDef diepint; uint32_t fifoemptymsk, msk, emp; msk = USB_OTG_READ_REG32(&pdev->regs.DREGS->DINEP1MSK); emp = USB_OTG_READ_REG32(&pdev->regs.DREGS->DIEPEMPMSK); msk |= ((emp >> 1 ) & 0x1) << 7; diepint.d32 = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[1]->DIEPINT) & msk; if ( diepint.b.xfercompl ) { fifoemptymsk = 0x1 << 1; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0); CLEAR_IN_EP_INTR(1, xfercompl); /* TX COMPLETE */ USBD_DCD_INT_fops->DataInStage(pdev , 1); } if ( diepint.b.epdisabled ) { CLEAR_IN_EP_INTR(1, epdisabled); } if ( diepint.b.timeout ) { CLEAR_IN_EP_INTR(1, timeout); } if (diepint.b.intktxfemp) { CLEAR_IN_EP_INTR(1, intktxfemp); } if (diepint.b.inepnakeff) { CLEAR_IN_EP_INTR(1, inepnakeff); } if (diepint.b.emptyintr) { DCD_WriteEmptyTxFifo(pdev , 1); CLEAR_IN_EP_INTR(1, emptyintr); /* Notice: this probabbly needs the same fix as DCD_HandleInEP_ISR(), but leaving this out, we don't use this part of code fifoemptymsk = 0x1 << 1; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0); */ } return 1; }
/******************************************************************************* * Function Name : OTGD_FS_Handle_EOPF_ISR * Description : Handles the Expected End Of Periodic Frame interrupt. * Input : None * Output : None * Return : status *******************************************************************************/ uint32_t OTGD_FS_Handle_EOPF_ISR(void) { USB_OTG_GINTSTS_TypeDef gintsts; USB_OTG_GINTMSK_TypeDef gintmsk; gintsts.d32 = 0; gintmsk.d32 = 0; gintmsk.b.eopframe = 1; USB_OTG_MODIFY_REG32(&USB_OTG_FS_regs.GREGS->GINTMSK, gintmsk.d32, 0); /* Call user function */ INTR_EOPFRAME_Callback(); /* Clear interrupt */ gintsts.b.eopframe = 1; USB_OTG_WRITE_REG32(&USB_OTG_FS_regs.GREGS->GINTSTS, gintsts.d32); return 1; }
/******************************************************************************* * Function Name : OTGD_FS_EP0Activate * Description : enables EP0 OUT to receive SETUP packets and configures EP0 IN for transmitting packets * Input : None * Output : None * Return : status *******************************************************************************/ USB_OTG_Status OTGD_FS_EP0Activate(void) { USB_OTG_Status status = USB_OTG_OK; USB_OTG_DEPCTLx_TypeDef diepctl; USB_OTG_DCTL_TypeDef dctl; diepctl.d32 = 0; dctl.d32 = 0; diepctl.d32 = USB_OTG_READ_REG32(&USB_OTG_FS_regs.DINEPS[0]->DIEPCTLx); diepctl.b.mps = DEP0CTL_MPS_64; USB_OTG_WRITE_REG32(&USB_OTG_FS_regs.DINEPS[0]->DIEPCTLx, diepctl.d32); dctl.b.cgnpinnak = 1; USB_OTG_MODIFY_REG32(&USB_OTG_FS_regs.DEV->DCTL, dctl.d32, dctl.d32); return status; }
static uint32_t USB_OTG_USBH_handle_nptxfempty_ISR(USB_OTG_CORE_HANDLE*pdev) { int free_space; USB_OTG_HNPTXSTS_TypeDef hnptxsts; uint32_t write_len; char *write_buff; hnptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->HNPTXSTS); hnptxsts.b.chnum = pdev->cur_bulk_out_ch; write_len = (pdev->host.hc[hnptxsts.b.chnum].xfer_len + 3) / 4; free_space = hnptxsts.b.nptxfspcavail - 16; if (free_space < write_len) { write_len = free_space * 4; write_buff = (char*)pdev->host.hc[hnptxsts.b.chnum].xfer_buff; pdev->host.hc[hnptxsts.b.chnum].xfer_len -= write_len; pdev->host.hc[hnptxsts.b.chnum].xfer_buff += write_len; } else { USB_OTG_GINTMSK_TypeDef intmsk; intmsk.d32 = 0; intmsk.b.nptxfempty = 1; USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, intmsk.d32, 0); write_buff = (char*)pdev->host.hc[hnptxsts.b.chnum].xfer_buff; write_len = write_len * 4; pdev->host.hc[hnptxsts.b.chnum].xfer_len = 0; pdev->bulk_out_irq_pending = 0; } USB_OTG_WritePacket(pdev, (uint8_t*)write_buff, hnptxsts.b.chnum, write_len); if (pdev->host.hc[hnptxsts.b.chnum].xfer_len < 0) { pdev->host.hc[hnptxsts.b.chnum].xfer_len = 0; } return 1; }
static uint32_t USB_OTG_USBH_handle_ptxfempty_ISR(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_HPTXSTS_TypeDef hptxsts; uint32_t write_len; char *write_buff; hptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.HREGS->HPTXSTS); write_len = (pdev->host.hc[hptxsts.b.chnum].xfer_len + 3) / 4; if (hptxsts.b.ptxfspcavail <= write_len) { write_len = hptxsts.b.ptxfspcavail * 4; write_buff = (char*)pdev->host.hc[hptxsts.b.chnum].xfer_buff; pdev->host.hc[hptxsts.b.chnum].xfer_len -= write_len; pdev->host.hc[hptxsts.b.chnum].xfer_buff += write_len; } else { USB_OTG_GINTMSK_TypeDef intmsk; intmsk.d32 = 0; intmsk.b.ptxfempty = 1; USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, intmsk.d32, 0); write_buff = (char*)pdev->host.hc[hptxsts.b.chnum].xfer_buff; write_len = pdev->host.hc[hptxsts.b.chnum].xfer_len; pdev->host.hc[hptxsts.b.chnum].xfer_len = 0; pdev->host.hc[hptxsts.b.chnum].xfer_buff += write_len; } USB_OTG_WritePacket(pdev, (uint8_t*)write_buff, hptxsts.b.chnum, write_len); if (pdev->host.hc[hptxsts.b.chnum].xfer_len < 0) { pdev->host.hc[hptxsts.b.chnum].xfer_len = 0; } return 1; }