/** * @brief Initiate Do Ping protocol * @param USBx : Selected device * @param hc_num : Host Channel number * This parameter can be a value from 1 to 15 * @retval HAL state */ HAL_StatusTypeDef USB_DoPing(USB_OTG_GlobalTypeDef *USBx , uint8_t ch_num) { uint8_t num_packets = 1; USBx_HC(ch_num)->HCTSIZ = ((num_packets << 19) & USB_OTG_HCTSIZ_PKTCNT) |\ USB_OTG_HCTSIZ_DOPING; /* Set host channel enable */ USBx_HC(ch_num)->HCCHAR &= ~USB_OTG_HCCHAR_CHDIS; USBx_HC(ch_num)->HCCHAR |= USB_OTG_HCCHAR_CHENA; return HAL_OK; }
/** * @brief Stop Host Core * @param USBx : Selected device * @retval HAL state */ HAL_StatusTypeDef USB_StopHost(USB_OTG_GlobalTypeDef *USBx) { uint8_t i; uint32_t count = 0; uint32_t value; USB_DisableGlobalInt(USBx); /* Flush FIFO */ USB_FlushTxFifo(USBx, 0x10); USB_FlushRxFifo(USBx); /* Flush out any leftover queued requests. */ for (i = 0; i <= 15; i++) { value = USBx_HC(i)->HCCHAR ; value |= USB_OTG_HCCHAR_CHDIS; value &= ~USB_OTG_HCCHAR_CHENA; value &= ~USB_OTG_HCCHAR_EPDIR; USBx_HC(i)->HCCHAR = value; } /* Halt all channels to put them into a known state. */ for (i = 0; i <= 15; i++) { value = USBx_HC(i)->HCCHAR ; value |= USB_OTG_HCCHAR_CHDIS; value |= USB_OTG_HCCHAR_CHENA; value &= ~USB_OTG_HCCHAR_EPDIR; USBx_HC(i)->HCCHAR = value; do { if (++count > 1000) { break; } } while ((USBx_HC(i)->HCCHAR & USB_OTG_HCCHAR_CHENA) == USB_OTG_HCCHAR_CHENA); } /* Clear any pending Host interrups */ USBx_HOST->HAINT = 0xFFFFFFFF; USBx->GINTSTS = 0xFFFFFFFF; USB_EnableGlobalInt(USBx); return HAL_OK; }
/** * @brief This function handles Rx Queue Level interrupt requests. * @param hhcd: HCD handle * @retval None */ static void HCD_RXQLVL_IRQHandler(HCD_HandleTypeDef *hhcd) { USB_OTG_GlobalTypeDef *USBx = hhcd->Instance; uint8_t channelnum = 0; uint32_t pktsts; uint32_t pktcnt; uint32_t temp = 0; if (!HAL_HCD_ATTACHED(hhcd)) { USBH_PutMessage("RXQLVL Handler run after detached."); } temp = hhcd->Instance->GRXSTSP; channelnum = temp & USB_OTG_GRXSTSP_EPNUM; pktsts = (temp & USB_OTG_GRXSTSP_PKTSTS) >> 17; pktcnt = (temp & USB_OTG_GRXSTSP_BCNT) >> 4; switch (pktsts) { case GRXSTS_PKTSTS_IN: /* Read the data into the host buffer. */ if ((pktcnt > 0) && (hhcd->hc[channelnum].xfer_buff != (void *)0)) { USB_ReadPacket(hhcd->Instance, hhcd->hc[channelnum].xfer_buff, pktcnt); /*manage multiple Xfer */ hhcd->hc[channelnum].xfer_buff += pktcnt; hhcd->hc[channelnum].xfer_count += pktcnt; if((USBx_HC(channelnum)->HCTSIZ & USB_OTG_HCTSIZ_PKTCNT) > 0) { /* re-activate the channel when more packets are expected */ USBx_HC(channelnum)->HCCHAR &= ~USB_OTG_HCCHAR_CHDIS; USBx_HC(channelnum)->HCCHAR |= USB_OTG_HCCHAR_CHENA; hhcd->hc[channelnum].toggle_in ^= 1; } } break; case GRXSTS_PKTSTS_DATA_TOGGLE_ERR: break; case GRXSTS_PKTSTS_IN_XFER_COMP: case GRXSTS_PKTSTS_CH_HALTED: default: break; } }
/** * @brief This function handles Rx Queue Level interrupt requests. * @param hhcd: HCD handle * @retval none */ static void HCD_RXQLVL_IRQHandler (HCD_HandleTypeDef *hhcd) { USB_OTG_GlobalTypeDef *USBx = hhcd->Instance; uint8_t channelnum =0U; uint32_t pktsts; uint32_t pktcnt; uint32_t temp = 0U; uint32_t tmpreg = 0U; temp = hhcd->Instance->GRXSTSP; channelnum = temp & USB_OTG_GRXSTSP_EPNUM; pktsts = (temp & USB_OTG_GRXSTSP_PKTSTS) >> 17U; pktcnt = (temp & USB_OTG_GRXSTSP_BCNT) >> 4U; switch (pktsts) { case GRXSTS_PKTSTS_IN: /* Read the data into the host buffer. */ if ((pktcnt > 0U) && (hhcd->hc[channelnum].xfer_buff != (void *)0U)) { USB_ReadPacket(hhcd->Instance, hhcd->hc[channelnum].xfer_buff, pktcnt); /*manage multiple Xfer */ hhcd->hc[channelnum].xfer_buff += pktcnt; hhcd->hc[channelnum].xfer_count += pktcnt; if((USBx_HC(channelnum)->HCTSIZ & USB_OTG_HCTSIZ_PKTCNT) > 0U) { /* re-activate the channel when more packets are expected */ tmpreg = USBx_HC(channelnum)->HCCHAR; tmpreg &= ~USB_OTG_HCCHAR_CHDIS; tmpreg |= USB_OTG_HCCHAR_CHENA; USBx_HC(channelnum)->HCCHAR = tmpreg; hhcd->hc[channelnum].toggle_in ^= 1U; } } break; case GRXSTS_PKTSTS_DATA_TOGGLE_ERR: break; case GRXSTS_PKTSTS_IN_XFER_COMP: case GRXSTS_PKTSTS_CH_HALTED: default: break; } }
void hc_helper_report_channel_in(uint32_t i) { if (hc_report_channel[i]) { memset(&hcint[i], 0, sizeof(hcint[i])); hcint[i].interrupt = interrupt; hcint[i].hcint_reg = (USBx_HC(i)->HCINT); hcint[i].in_state = hhcd->hc[i].state; hcint[i].in_urbstate = hhcd->hc[i].urb_state; hcint[i].in_err_count = hhcd->hc[i].ErrCnt; hcint[i].uid = debug_hc_uid++; if ((USBx_HC(i)->HCCHAR) & USB_OTG_HCCHAR_EPDIR) { hcint[i].direction = 1; // IN } else { hcint[i].direction = 0; // OUT } } }
void hc_helper_prepare_reports(HCD_HandleTypeDef *_hhcd, uint32_t _interrupt) { int i; hhcd = _hhcd; interrupt = _interrupt; USBx = hhcd->Instance; for (i = 0; i < hhcd->Init.Host_channels ; i++) { if (interrupt & (1 << i)) { hc_report_channel[i] = (DebugConfig.channel_hcintx_mask[i] & (USBx_HC(i)->HCINT)); } else { hc_report_channel[i] = 0; } } }
/** * @brief Halt a host channel * @param USBx : Selected device * @param hc_num : Host Channel number * This parameter can be a value from 1 to 15 * @retval HAL state */ HAL_StatusTypeDef USB_HC_Halt(USB_OTG_GlobalTypeDef *USBx , uint8_t hc_num) { uint32_t count = 0; /* Check for space in the request queue to issue the halt. */ if (((USBx_HC(hc_num)->HCCHAR) & (HCCHAR_CTRL << 18)) || ((USBx_HC(hc_num)->HCCHAR) & (HCCHAR_BULK << 18))) { USBx_HC(hc_num)->HCCHAR |= USB_OTG_HCCHAR_CHDIS; if ((USBx->HNPTXSTS & 0xFFFF) == 0) { USBx_HC(hc_num)->HCCHAR &= ~USB_OTG_HCCHAR_CHENA; USBx_HC(hc_num)->HCCHAR |= USB_OTG_HCCHAR_CHENA; USBx_HC(hc_num)->HCCHAR &= ~USB_OTG_HCCHAR_EPDIR; do { if (++count > 1000) { break; } } while ((USBx_HC(hc_num)->HCCHAR & USB_OTG_HCCHAR_CHENA) == USB_OTG_HCCHAR_CHENA); } else { USBx_HC(hc_num)->HCCHAR |= USB_OTG_HCCHAR_CHENA; } } else { USBx_HC(hc_num)->HCCHAR |= USB_OTG_HCCHAR_CHDIS; if ((USBx_HOST->HPTXSTS & 0xFFFF) == 0) { USBx_HC(hc_num)->HCCHAR &= ~USB_OTG_HCCHAR_CHENA; USBx_HC(hc_num)->HCCHAR |= USB_OTG_HCCHAR_CHENA; USBx_HC(hc_num)->HCCHAR &= ~USB_OTG_HCCHAR_EPDIR; do { if (++count > 1000) { break; } } while ((USBx_HC(hc_num)->HCCHAR & USB_OTG_HCCHAR_CHENA) == USB_OTG_HCCHAR_CHENA); } else { USBx_HC(hc_num)->HCCHAR |= USB_OTG_HCCHAR_CHENA; } } return HAL_OK; }
/** * @brief Start a transfer over a host channel * @param USBx : Selected device * @param hc : pointer to host channel structure * @param dma: USB dma enabled or disabled * This parameter can be one of the these values: * 0 : DMA feature not used * 1 : DMA feature used * @retval HAL state */ #if defined (__CC_ARM) /*!< ARM Compiler */ #pragma O0 #elif defined (__GNUC__) /*!< GNU Compiler */ #pragma GCC optimize ("O0") #elif defined (__TASKING__) /*!< TASKING Compiler */ #pragma optimize=0 #endif /* __CC_ARM */ HAL_StatusTypeDef USB_HC_StartXfer(USB_OTG_GlobalTypeDef *USBx, USB_OTG_HCTypeDef *hc, uint8_t dma) { uint8_t is_oddframe = 0; uint16_t len_words = 0; uint16_t num_packets = 0; uint16_t max_hc_pkt_count = 256; if((USBx != USB_OTG_FS) && (hc->speed == USB_OTG_SPEED_HIGH)) { if((dma == 0) && (hc->do_ping == 1)) { USB_DoPing(USBx, hc->ch_num); return HAL_OK; } } /* Compute the expected number of packets associated to the transfer */ if (hc->xfer_len > 0) { num_packets = (hc->xfer_len + hc->max_packet - 1) / hc->max_packet; if (num_packets > max_hc_pkt_count) { num_packets = max_hc_pkt_count; hc->xfer_len = num_packets * hc->max_packet; } } else { num_packets = 1; } if (hc->ep_is_in) { hc->xfer_len = num_packets * hc->max_packet; } /* Initialize the HCTSIZn register */ USBx_HC(hc->ch_num)->HCTSIZ = (((hc->xfer_len) & USB_OTG_HCTSIZ_XFRSIZ)) |\ ((num_packets << 19) & USB_OTG_HCTSIZ_PKTCNT) |\ (((hc->data_pid) << 29) & USB_OTG_HCTSIZ_DPID); if (dma) { /* xfer_buff MUST be 32-bits aligned */ USBx_HC(hc->ch_num)->HCDMA = (uint32_t)hc->xfer_buff; } is_oddframe = (USBx_HOST->HFNUM & 0x01) ? 0 : 1; USBx_HC(hc->ch_num)->HCCHAR &= ~USB_OTG_HCCHAR_ODDFRM; USBx_HC(hc->ch_num)->HCCHAR |= (is_oddframe << 29); /* Set host channel enable */ USBx_HC(hc->ch_num)->HCCHAR &= ~USB_OTG_HCCHAR_CHDIS; USBx_HC(hc->ch_num)->HCCHAR |= USB_OTG_HCCHAR_CHENA; if (dma == 0) /* Slave mode */ { if((hc->ep_is_in == 0) && (hc->xfer_len > 0)) { switch(hc->ep_type) { /* Non periodic transfer */ case EP_TYPE_CTRL: case EP_TYPE_BULK: len_words = (hc->xfer_len + 3) / 4; /* check if there is enough space in FIFO space */ if(len_words > (USBx->HNPTXSTS & 0xFFFF)) { /* need to process data in nptxfempty interrupt */ USBx->GINTMSK |= USB_OTG_GINTMSK_NPTXFEM; } break; /* Periodic transfer */ case EP_TYPE_INTR: case EP_TYPE_ISOC: len_words = (hc->xfer_len + 3) / 4; /* check if there is enough space in FIFO space */ if(len_words > (USBx_HOST->HPTXSTS & 0xFFFF)) /* split the transfer */ { /* need to process data in ptxfempty interrupt */ USBx->GINTMSK |= USB_OTG_GINTMSK_PTXFEM; } break; default: break; } /* Write packet into the Tx FIFO. */ USB_WritePacket(USBx, hc->xfer_buff, hc->ch_num, hc->xfer_len, 0); } } return HAL_OK; }
/** * @brief Initialize a host channel * @param USBx : Selected device * @param ch_num : Channel number * This parameter can be a value from 1 to 15 * @param epnum : Endpoint number * This parameter can be a value from 1 to 15 * @param dev_address : Current device address * This parameter can be a value from 0 to 255 * @param speed : Current device speed * This parameter can be one of the these values: * @arg USB_OTG_SPEED_HIGH: High speed mode * @arg USB_OTG_SPEED_FULL: Full speed mode * @arg USB_OTG_SPEED_LOW: Low speed mode * @param ep_type : Endpoint Type * This parameter can be one of the these values: * @arg EP_TYPE_CTRL: Control type * @arg EP_TYPE_ISOC: Isochrounous type * @arg EP_TYPE_BULK: Bulk type * @arg EP_TYPE_INTR: Interrupt type * @param mps : Max Packet Size * This parameter can be a value from 0 to32K * @retval HAL state */ HAL_StatusTypeDef USB_HC_Init(USB_OTG_GlobalTypeDef *USBx, uint8_t ch_num, uint8_t epnum, uint8_t dev_address, uint8_t speed, uint8_t ep_type, uint16_t mps) { /* Clear old interrupt conditions for this host channel. */ USBx_HC(ch_num)->HCINT = 0xFFFFFFFF; /* Enable channel interrupts required for this transfer. */ switch (ep_type) { case EP_TYPE_CTRL: case EP_TYPE_BULK: USBx_HC(ch_num)->HCINTMSK = USB_OTG_HCINTMSK_XFRCM |\ USB_OTG_HCINTMSK_STALLM |\ USB_OTG_HCINTMSK_TXERRM |\ USB_OTG_HCINTMSK_DTERRM |\ USB_OTG_HCINTMSK_AHBERR |\ USB_OTG_HCINTMSK_NAKM ; if (epnum & 0x80) { USBx_HC(ch_num)->HCINTMSK |= USB_OTG_HCINTMSK_BBERRM; } else { if(USBx != USB_OTG_FS) { USBx_HC(ch_num)->HCINTMSK |= (USB_OTG_HCINTMSK_NYET | USB_OTG_HCINTMSK_ACKM); } } break; case EP_TYPE_INTR: USBx_HC(ch_num)->HCINTMSK = USB_OTG_HCINTMSK_XFRCM |\ USB_OTG_HCINTMSK_STALLM |\ USB_OTG_HCINTMSK_TXERRM |\ USB_OTG_HCINTMSK_DTERRM |\ USB_OTG_HCINTMSK_NAKM |\ USB_OTG_HCINTMSK_AHBERR |\ USB_OTG_HCINTMSK_FRMORM ; if (epnum & 0x80) { USBx_HC(ch_num)->HCINTMSK |= USB_OTG_HCINTMSK_BBERRM; } break; case EP_TYPE_ISOC: USBx_HC(ch_num)->HCINTMSK = USB_OTG_HCINTMSK_XFRCM |\ USB_OTG_HCINTMSK_ACKM |\ USB_OTG_HCINTMSK_AHBERR |\ USB_OTG_HCINTMSK_FRMORM ; if (epnum & 0x80) { USBx_HC(ch_num)->HCINTMSK |= (USB_OTG_HCINTMSK_TXERRM | USB_OTG_HCINTMSK_BBERRM); } break; } /* Enable the top level host channel interrupt. */ USBx_HOST->HAINTMSK |= (1 << ch_num); /* Make sure host channel interrupts are enabled. */ USBx->GINTMSK |= USB_OTG_GINTMSK_HCIM; /* Program the HCCHAR register */ USBx_HC(ch_num)->HCCHAR = (((dev_address << 22) & USB_OTG_HCCHAR_DAD) |\ (((epnum & 0x7F)<< 11) & USB_OTG_HCCHAR_EPNUM)|\ ((((epnum & 0x80) == 0x80)<< 15) & USB_OTG_HCCHAR_EPDIR)|\ (((speed == HPRT0_PRTSPD_LOW_SPEED)<< 17) & USB_OTG_HCCHAR_LSDEV)|\ ((ep_type << 18) & USB_OTG_HCCHAR_EPTYP)|\ (mps & USB_OTG_HCCHAR_MPSIZ)); if (ep_type == EP_TYPE_INTR) { USBx_HC(ch_num)->HCCHAR |= USB_OTG_HCCHAR_ODDFRM ; } return HAL_OK; }
/** * @brief USB_HostInit : Initializes the USB OTG controller registers * for Host mode * @param USBx : Selected device * @param cfg : pointer to a USB_OTG_CfgTypeDef structure that contains * the configuration information for the specified USBx peripheral. * @retval HAL status */ HAL_StatusTypeDef USB_HostInit (USB_OTG_GlobalTypeDef *USBx, USB_OTG_CfgTypeDef cfg) { uint32_t i; /* Restart the Phy Clock */ USBx_PCGCCTL = 0; /* no VBUS sensing*/ USBx->GCCFG &=~ (USB_OTG_GCCFG_VBUSASEN); USBx->GCCFG &=~ (USB_OTG_GCCFG_VBUSBSEN); USBx->GCCFG |= USB_OTG_GCCFG_NOVBUSSENS; /* Disable the FS/LS support mode only */ if((cfg.speed == USB_OTG_SPEED_FULL)&& (USBx != USB_OTG_FS)) { USBx_HOST->HCFG |= USB_OTG_HCFG_FSLSS; } else { USBx_HOST->HCFG &= ~(USB_OTG_HCFG_FSLSS); } /* Make sure the FIFOs are flushed. */ USB_FlushTxFifo(USBx, 0x10 ); /* all Tx FIFOs */ USB_FlushRxFifo(USBx); /* Clear all pending HC Interrupts */ for (i = 0; i < cfg.Host_channels; i++) { USBx_HC(i)->HCINT = 0xFFFFFFFF; USBx_HC(i)->HCINTMSK = 0; } /* Enable VBUS driving */ USB_DriveVbus(USBx, 1); HAL_Delay(200); /* Disable all interrupts. */ USBx->GINTMSK = 0; /* Clear any pending interrupts */ USBx->GINTSTS = 0xFFFFFFFF; if(USBx == USB_OTG_FS) { /* set Rx FIFO size */ USBx->GRXFSIZ = (uint32_t )0x80; USBx->DIEPTXF0_HNPTXFSIZ = (uint32_t )(((0x60 << 16)& USB_OTG_NPTXFD) | 0x80); USBx->HPTXFSIZ = (uint32_t )(((0x40 << 16)& USB_OTG_HPTXFSIZ_PTXFD) | 0xE0); } else { /* set Rx FIFO size */ USBx->GRXFSIZ = (uint32_t )0x200; USBx->DIEPTXF0_HNPTXFSIZ = (uint32_t )(((0x100 << 16)& USB_OTG_NPTXFD) | 0x200); USBx->HPTXFSIZ = (uint32_t )(((0xE0 << 16)& USB_OTG_HPTXFSIZ_PTXFD) | 0x300); } /* Enable the common interrupts */ if (cfg.dma_enable == DISABLE) { USBx->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM; } /* Enable interrupts matching to the Host mode ONLY */ USBx->GINTMSK |= (USB_OTG_GINTMSK_PRTIM | USB_OTG_GINTMSK_HCIM |\ USB_OTG_GINTMSK_SOFM |USB_OTG_GINTSTS_DISCINT|\ USB_OTG_GINTMSK_PXFRM_IISOOXFRM | USB_OTG_GINTMSK_WUIM); return HAL_OK; }
/** * @brief This function handles Host Channel OUT interrupt requests. * @param hhcd: HCD handle * @param chnum : Channel number * This parameter can be a value from 1 to 15 * @retval none */ static void HCD_HC_OUT_IRQHandler (HCD_HandleTypeDef *hhcd, uint8_t chnum) { USB_OTG_GlobalTypeDef *USBx = hhcd->Instance; if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_AHBERR) { __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_AHBERR); __HAL_HCD_UNMASK_HALT_HC_INT(chnum); } else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_ACK) { __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_ACK); if( hhcd->hc[chnum].do_ping == 1) { hhcd->hc[chnum].state = HC_NYET; __HAL_HCD_UNMASK_HALT_HC_INT(chnum); USB_HC_Halt(hhcd->Instance, chnum); hhcd->hc[chnum].urb_state = URB_NOTREADY; } } else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_NYET) { hhcd->hc[chnum].state = HC_NYET; hhcd->hc[chnum].ErrCnt= 0; __HAL_HCD_UNMASK_HALT_HC_INT(chnum); USB_HC_Halt(hhcd->Instance, chnum); __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NYET); } else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_FRMOR) { __HAL_HCD_UNMASK_HALT_HC_INT(chnum); USB_HC_Halt(hhcd->Instance, chnum); __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_FRMOR); } else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_XFRC) { hhcd->hc[chnum].ErrCnt = 0; __HAL_HCD_UNMASK_HALT_HC_INT(chnum); USB_HC_Halt(hhcd->Instance, chnum); __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_XFRC); hhcd->hc[chnum].state = HC_XFRC; } else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_STALL) { __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_STALL); __HAL_HCD_UNMASK_HALT_HC_INT(chnum); USB_HC_Halt(hhcd->Instance, chnum); hhcd->hc[chnum].state = HC_STALL; } else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_NAK) { hhcd->hc[chnum].ErrCnt = 0; __HAL_HCD_UNMASK_HALT_HC_INT(chnum); USB_HC_Halt(hhcd->Instance, chnum); hhcd->hc[chnum].state = HC_NAK; __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK); } else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_TXERR) { __HAL_HCD_UNMASK_HALT_HC_INT(chnum); USB_HC_Halt(hhcd->Instance, chnum); hhcd->hc[chnum].state = HC_XACTERR; __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_TXERR); } else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_DTERR) { __HAL_HCD_UNMASK_HALT_HC_INT(chnum); USB_HC_Halt(hhcd->Instance, chnum); __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK); __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_DTERR); hhcd->hc[chnum].state = HC_DATATGLERR; } else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_CHH) { __HAL_HCD_MASK_HALT_HC_INT(chnum); if(hhcd->hc[chnum].state == HC_XFRC) { hhcd->hc[chnum].urb_state = URB_DONE; if (hhcd->hc[chnum].ep_type == EP_TYPE_BULK) { hhcd->hc[chnum].toggle_out ^= 1; } } else if (hhcd->hc[chnum].state == HC_NAK) { hhcd->hc[chnum].urb_state = URB_NOTREADY; } else if (hhcd->hc[chnum].state == HC_NYET) { hhcd->hc[chnum].urb_state = URB_NOTREADY; hhcd->hc[chnum].do_ping = 0; } else if (hhcd->hc[chnum].state == HC_STALL) { hhcd->hc[chnum].urb_state = URB_STALL; } else if((hhcd->hc[chnum].state == HC_XACTERR) || (hhcd->hc[chnum].state == HC_DATATGLERR)) { if(hhcd->hc[chnum].ErrCnt++ > 3) { hhcd->hc[chnum].ErrCnt = 0; hhcd->hc[chnum].urb_state = URB_ERROR; } else { hhcd->hc[chnum].urb_state = URB_NOTREADY; } /* re-activate the channel */ USBx_HC(chnum)->HCCHAR &= ~USB_OTG_HCCHAR_CHDIS; USBx_HC(chnum)->HCCHAR |= USB_OTG_HCCHAR_CHENA; } __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_CHH); HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state); } }
/** * @brief This function handles Host Channel IN interrupt requests. * @param hhcd: HCD handle * @param chnum : Channel number * This parameter can be a value from 1 to 15 * @retval none */ static void HCD_HC_IN_IRQHandler (HCD_HandleTypeDef *hhcd, uint8_t chnum) { USB_OTG_GlobalTypeDef *USBx = hhcd->Instance; if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_AHBERR) { __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_AHBERR); __HAL_HCD_UNMASK_HALT_HC_INT(chnum); } else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_ACK) { __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_ACK); } else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_STALL) { __HAL_HCD_UNMASK_HALT_HC_INT(chnum); hhcd->hc[chnum].state = HC_STALL; __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK); __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_STALL); USB_HC_Halt(hhcd->Instance, chnum); } else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_DTERR) { __HAL_HCD_UNMASK_HALT_HC_INT(chnum); USB_HC_Halt(hhcd->Instance, chnum); __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK); hhcd->hc[chnum].state = HC_DATATGLERR; __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_DTERR); } if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_FRMOR) { __HAL_HCD_UNMASK_HALT_HC_INT(chnum); USB_HC_Halt(hhcd->Instance, chnum); __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_FRMOR); } else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_XFRC) { if (hhcd->Init.dma_enable) { hhcd->hc[chnum].xfer_count = hhcd->hc[chnum].xfer_len - \ (USBx_HC(chnum)->HCTSIZ & USB_OTG_HCTSIZ_XFRSIZ); } hhcd->hc[chnum].state = HC_XFRC; hhcd->hc[chnum].ErrCnt = 0; __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_XFRC); if ((hhcd->hc[chnum].ep_type == EP_TYPE_CTRL)|| (hhcd->hc[chnum].ep_type == EP_TYPE_BULK)) { __HAL_HCD_UNMASK_HALT_HC_INT(chnum); USB_HC_Halt(hhcd->Instance, chnum); __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK); } else if(hhcd->hc[chnum].ep_type == EP_TYPE_INTR) { USBx_HC(chnum)->HCCHAR |= USB_OTG_HCCHAR_ODDFRM; hhcd->hc[chnum].urb_state = URB_DONE; HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state); } hhcd->hc[chnum].toggle_in ^= 1; } else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_CHH) { __HAL_HCD_MASK_HALT_HC_INT(chnum); if(hhcd->hc[chnum].state == HC_XFRC) { hhcd->hc[chnum].urb_state = URB_DONE; } else if (hhcd->hc[chnum].state == HC_STALL) { hhcd->hc[chnum].urb_state = URB_STALL; } else if((hhcd->hc[chnum].state == HC_XACTERR) || (hhcd->hc[chnum].state == HC_DATATGLERR)) { if(hhcd->hc[chnum].ErrCnt++ > 3) { hhcd->hc[chnum].ErrCnt = 0; hhcd->hc[chnum].urb_state = URB_ERROR; } else { hhcd->hc[chnum].urb_state = URB_NOTREADY; } /* re-activate the channel */ USBx_HC(chnum)->HCCHAR &= ~USB_OTG_HCCHAR_CHDIS; USBx_HC(chnum)->HCCHAR |= USB_OTG_HCCHAR_CHENA; } __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_CHH); HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state); } else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_TXERR) { __HAL_HCD_UNMASK_HALT_HC_INT(chnum); hhcd->hc[chnum].ErrCnt++; hhcd->hc[chnum].state = HC_XACTERR; USB_HC_Halt(hhcd->Instance, chnum); __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_TXERR); } else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_NAK) { if(hhcd->hc[chnum].ep_type == EP_TYPE_INTR) { __HAL_HCD_UNMASK_HALT_HC_INT(chnum); USB_HC_Halt(hhcd->Instance, chnum); } else if ((hhcd->hc[chnum].ep_type == EP_TYPE_CTRL)|| (hhcd->hc[chnum].ep_type == EP_TYPE_BULK)) { /* re-activate the channel */ USBx_HC(chnum)->HCCHAR &= ~USB_OTG_HCCHAR_CHDIS; USBx_HC(chnum)->HCCHAR |= USB_OTG_HCCHAR_CHENA; } hhcd->hc[chnum].state = HC_NAK; __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK); } }
/** * @brief This function handles HCD interrupt request. * @param hhcd: HCD handle * @retval none */ void HAL_HCD_IRQHandler(HCD_HandleTypeDef *hhcd) { USB_OTG_GlobalTypeDef *USBx = hhcd->Instance; uint32_t i = 0 , interrupt = 0; /* ensure that we are in device mode */ if (USB_GetMode(hhcd->Instance) == USB_OTG_MODE_HOST) { /* avoid spurious interrupt */ if(__HAL_HCD_IS_INVALID_INTERRUPT(hhcd)) { return; } if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_PXFR_INCOMPISOOUT)) { /* incorrect mode, acknowledge the interrupt */ __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_PXFR_INCOMPISOOUT); } if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_IISOIXFR)) { /* incorrect mode, acknowledge the interrupt */ __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_IISOIXFR); } if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_PTXFE)) { /* incorrect mode, acknowledge the interrupt */ __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_PTXFE); } if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_MMIS)) { /* incorrect mode, acknowledge the interrupt */ __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_MMIS); } /* Handle Host Disconnect Interrupts */ if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_DISCINT)) { /* Cleanup HPRT */ USBx_HPRT0 &= ~(USB_OTG_HPRT_PENA | USB_OTG_HPRT_PCDET |\ USB_OTG_HPRT_PENCHNG | USB_OTG_HPRT_POCCHNG ); /* Handle Host Port Interrupts */ HAL_HCD_Disconnect_Callback(hhcd); USB_InitFSLSPClkSel(hhcd->Instance ,HCFG_48_MHZ ); __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_DISCINT); } /* Handle Host Port Interrupts */ if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_HPRTINT)) { HCD_Port_IRQHandler (hhcd); } /* Handle Host SOF Interrupts */ if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_SOF)) { HAL_HCD_SOF_Callback(hhcd); __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_SOF); } /* Handle Host channel Interrupts */ if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_HCINT)) { interrupt = USB_HC_ReadInterrupt(hhcd->Instance); for (i = 0; i < hhcd->Init.Host_channels ; i++) { if (interrupt & (1 << i)) { if ((USBx_HC(i)->HCCHAR) & USB_OTG_HCCHAR_EPDIR) { HCD_HC_IN_IRQHandler (hhcd, i); } else { HCD_HC_OUT_IRQHandler (hhcd, i); } } } __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_HCINT); } /* Handle Rx Queue Level Interrupts */ if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_RXFLVL)) { USB_MASK_INTERRUPT(hhcd->Instance, USB_OTG_GINTSTS_RXFLVL); HCD_RXQLVL_IRQHandler (hhcd); USB_UNMASK_INTERRUPT(hhcd->Instance, USB_OTG_GINTSTS_RXFLVL); } } }
/** * @brief This function handles HCD interrupt request. * @param hhcd: HCD handle * @retval None */ void HAL_HCD_IRQHandler(HCD_HandleTypeDef *hhcd) { USB_OTG_GlobalTypeDef *USBx = hhcd->Instance; uint32_t i = 0 , interrupt = 0; /* Ensure that we are in device mode */ if (USB_GetMode(hhcd->Instance) == USB_OTG_MODE_HOST) { /* Avoid spurious interrupt */ if(__HAL_HCD_IS_INVALID_INTERRUPT(hhcd)) { return; } if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_PXFR_INCOMPISOOUT)) { /* Incorrect mode, acknowledge the interrupt */ __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_PXFR_INCOMPISOOUT); } if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_IISOIXFR)) { /* Incorrect mode, acknowledge the interrupt */ __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_IISOIXFR); } if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_PTXFE)) { /* Incorrect mode, acknowledge the interrupt */ __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_PTXFE); } if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_MMIS)) { /* Incorrect mode, acknowledge the interrupt */ __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_MMIS); } /* Handle Host Disconnect Interrupts */ if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_DISCINT)) { if (DebugConfig.print_hcd_event) { USBH_PutMessage("DISCONNECT"); } /* Cleanup HPRT */ USBx_HPRT0 &= ~(USB_OTG_HPRT_PENA | USB_OTG_HPRT_PCDET |\ USB_OTG_HPRT_PENCHNG | USB_OTG_HPRT_POCCHNG ); /* Handle Host Port Interrupts */ /* Do this in port down handler, not disconnect handler */ // HAL_HCD_Disconnect_Callback(hhcd); // USB_InitFSLSPClkSel(hhcd->Instance ,HCFG_48_MHZ ); __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_DISCINT); } /* Handle Host Port Interrupts */ if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_HPRTINT)) { HCD_Port_IRQHandler (hhcd); /* If port down/global interrupt disabled, channel * process should not be processed further. */ if (!(hhcd->Instance->GAHBCFG & USB_OTG_GAHBCFG_GINT)) return; } /* Handle Host SOF Interrupts */ if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_SOF)) { HAL_HCD_SOF_Callback(hhcd); __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_SOF); } /* Handle Host channel Interrupts */ if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_HCINT)) { interrupt = USB_HC_ReadInterrupt(hhcd->Instance); hc_helper_prepare_reports(hhcd, interrupt); for (i = 0; i < hhcd->Init.Host_channels; i++) { if (interrupt & (1 << i)) { hc_helper_report_channel_in(i); if ((USBx_HC(i)->HCCHAR) & USB_OTG_HCCHAR_EPDIR) { HCD_HC_IN_IRQHandler(hhcd, i); } else { HCD_HC_OUT_IRQHandler (hhcd, i); } hc_helper_report_channel_out(i); } } __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_HCINT); hc_helper_send_reports(); } /* Handle Rx Queue Level Interrupts */ if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_RXFLVL)) { USB_MASK_INTERRUPT(hhcd->Instance, USB_OTG_GINTSTS_RXFLVL); HCD_RXQLVL_IRQHandler (hhcd); USB_UNMASK_INTERRUPT(hhcd->Instance, USB_OTG_GINTSTS_RXFLVL); } } }
/** * @brief Submit a new URB for processing. * @param hhcd: HCD handle * @param ch_num: Channel number. * This parameter can be a value from 1 to 15 * @param direction: Channel number. * This parameter can be one of these values: * 0 : Output / 1 : Input * @param ep_type: Endpoint Type. * This parameter can be one of these values: * EP_TYPE_CTRL: Control type/ * EP_TYPE_ISOC: Isochronous type/ * EP_TYPE_BULK: Bulk type/ * EP_TYPE_INTR: Interrupt type/ * @param token: Endpoint Type. * This parameter can be one of these values: * 0: HC_PID_SETUP / 1: HC_PID_DATA1 * @param pbuff: pointer to URB data * @param length: Length of URB data * @param do_ping: activate do ping protocol (for high speed only). * This parameter can be one of these values: * 0 : do ping inactive / 1 : do ping active * @retval HAL status */ HAL_StatusTypeDef HAL_HCD_HC_SubmitRequest(HCD_HandleTypeDef *hhcd, uint8_t ch_num, uint8_t direction , uint8_t ep_type, uint8_t token, uint8_t* pbuff, uint16_t length, uint8_t do_ping) { if ((hhcd->hc[ch_num].ep_is_in != direction)) { if ((hhcd->hc[ch_num].ep_type == EP_TYPE_CTRL)){ /* reconfigure the endpoint !!! from tx -> rx, and rx ->tx */ USB_OTG_GlobalTypeDef *USBx = hhcd->Instance; if (direction) { USBx_HC(ch_num)->HCINTMSK |= USB_OTG_HCINTMSK_BBERRM; USBx_HC(ch_num)->HCCHAR |= 1 << 15; } else { USBx_HC(ch_num)->HCINTMSK &= ~USB_OTG_HCINTMSK_BBERRM; USBx_HC(ch_num)->HCCHAR &= ~(1 << 15); } hhcd->hc[ch_num].ep_is_in = direction; /* if reception put toggle_in to 1 */ if (direction == 1) hhcd->hc[ch_num].toggle_in=1; } } hhcd->hc[ch_num].ep_type = ep_type; if(token == 0) { hhcd->hc[ch_num].data_pid = HC_PID_SETUP; } else { hhcd->hc[ch_num].data_pid = HC_PID_DATA1; } /* Manage Data Toggle */ switch(ep_type) { case EP_TYPE_CTRL: if((token == 1) && (direction == 0)) /*send data */ { if ( length == 0 ) { /* For Status OUT stage, Length==0, Status Out PID = 1 */ hhcd->hc[ch_num].toggle_out = 1; } /* Set the Data Toggle bit as per the Flag */ if ( hhcd->hc[ch_num].toggle_out == 0) { /* Put the PID 0 */ hhcd->hc[ch_num].data_pid = HC_PID_DATA0; } else { /* Put the PID 1 */ hhcd->hc[ch_num].data_pid = HC_PID_DATA1 ; } if(hhcd->hc[ch_num].urb_state != URB_NOTREADY) { hhcd->hc[ch_num].do_ping = do_ping; } } else if ((token == 1) && (direction == 1)) { if( hhcd->hc[ch_num].toggle_in == 0) { hhcd->hc[ch_num].data_pid = HC_PID_DATA0; } else { hhcd->hc[ch_num].data_pid = HC_PID_DATA1; } } break; case EP_TYPE_BULK: if(direction == 0) { /* Set the Data Toggle bit as per the Flag */ if ( hhcd->hc[ch_num].toggle_out == 0) { /* Put the PID 0 */ hhcd->hc[ch_num].data_pid = HC_PID_DATA0; } else { /* Put the PID 1 */ hhcd->hc[ch_num].data_pid = HC_PID_DATA1 ; } if(hhcd->hc[ch_num].urb_state != URB_NOTREADY) { hhcd->hc[ch_num].do_ping = do_ping; } } else { if( hhcd->hc[ch_num].toggle_in == 0) { hhcd->hc[ch_num].data_pid = HC_PID_DATA0; } else { hhcd->hc[ch_num].data_pid = HC_PID_DATA1; } } break; case EP_TYPE_INTR: if(direction == 0) { /* Set the Data Toggle bit as per the Flag */ if ( hhcd->hc[ch_num].toggle_out == 0) { /* Put the PID 0 */ hhcd->hc[ch_num].data_pid = HC_PID_DATA0; } else { /* Put the PID 1 */ hhcd->hc[ch_num].data_pid = HC_PID_DATA1 ; } } else { if( hhcd->hc[ch_num].toggle_in == 0) { hhcd->hc[ch_num].data_pid = HC_PID_DATA0; } else { hhcd->hc[ch_num].data_pid = HC_PID_DATA1; } } break; case EP_TYPE_ISOC: hhcd->hc[ch_num].data_pid = HC_PID_DATA0; break; } hhcd->hc[ch_num].xfer_buff = pbuff; hhcd->hc[ch_num].xfer_len = length; hhcd->hc[ch_num].urb_state = URB_IDLE; hhcd->hc[ch_num].xfer_count = 0 ; hhcd->hc[ch_num].ch_num = ch_num; hhcd->hc[ch_num].state = HC_IDLE; return USB_HC_StartXfer(hhcd->Instance, &(hhcd->hc[ch_num]), hhcd->Init.dma_enable); }