diff --git a/os/hal/ports/STM32/LLD/OTGv1/usb_lld.c b/os/hal/ports/STM32/LLD/OTGv1/usb_lld.c index fad1932b1..cf22ac91e 100644 --- a/os/hal/ports/STM32/LLD/OTGv1/usb_lld.c +++ b/os/hal/ports/STM32/LLD/OTGv1/usb_lld.c @@ -32,12 +32,13 @@ /* Driver local definitions. */ /*===========================================================================*/ -#define TRDT_VALUE 5 - -#define EP0_MAX_INSIZE 64 - -/*===========================================================================*/ -/* Driver exported variables. */ +#define TRDT_VALUE 5 + +#define EP0_MAX_INSIZE 64 +#define EP0_MAX_OUTSIZE 64 + +/*===========================================================================*/ +/* Driver exported variables. */ /*===========================================================================*/ /** @brief OTG_FS driver identifier.*/ @@ -589,13 +590,29 @@ static void otg_epout_handler(USBDriver *usbp, usbep_t ep) { specific callback.*/ _usb_isr_invoke_setup_cb(usbp, ep); - } - if ((epint & DOEPINT_XFRC) && (otgp->DOEPMSK & DOEPMSK_XFRCM)) { - /* Receive transfer complete.*/ - _usb_isr_invoke_out_cb(usbp, ep); - } -} - + } + if ((epint & DOEPINT_XFRC) && (otgp->DOEPMSK & DOEPMSK_XFRCM)) { + /* Receive transfer complete.*/ + USBOutEndpointState *osp = usbp->epc[ep]->out_state; + + if (osp->rxsize < osp->totsize) { + /* In case the transaction covered only part of the total transfer + then another transaction is immediately started in order to + cover the remaining.*/ + osp->rxsize = osp->totsize - osp->rxsize; + osp->rxcnt = 0; + usb_lld_prepare_receive(usbp, ep); + chSysLockFromIsr(); + usb_lld_start_out(usbp, ep); + chSysUnlockFromIsr(); + } + else { + /* End on OUT transfer.*/ + _usb_isr_invoke_out_cb(usbp, ep); + } + } +} + /** * @brief OTG shared ISR. * @@ -1140,12 +1157,16 @@ void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) { */ void usb_lld_prepare_receive(USBDriver *usbp, usbep_t ep) { uint32_t pcnt; - USBOutEndpointState *osp = usbp->epc[ep]->out_state; - - /* Transfer initialization.*/ - pcnt = (osp->rxsize + usbp->epc[ep]->out_maxsize - 1) / - usbp->epc[ep]->out_maxsize; - usbp->otg->oe[ep].DOEPTSIZ = DOEPTSIZ_STUPCNT(3) | DOEPTSIZ_PKTCNT(pcnt) | + USBOutEndpointState *osp = usbp->epc[ep]->out_state; + + /* Transfer initialization.*/ + osp->totsize = osp->rxsize; + if ((ep == 0) && (osp->rxsize > EP0_MAX_OUTSIZE)) + osp->rxsize = EP0_MAX_OUTSIZE; + + pcnt = (osp->rxsize + usbp->epc[ep]->out_maxsize - 1) / + usbp->epc[ep]->out_maxsize; + usbp->otg->oe[ep].DOEPTSIZ = DOEPTSIZ_STUPCNT(3) | DOEPTSIZ_PKTCNT(pcnt) | DOEPTSIZ_XFRSIZ(osp->rxsize); } diff --git a/os/hal/ports/STM32/LLD/OTGv1/usb_lld.h b/os/hal/ports/STM32/LLD/OTGv1/usb_lld.h index 334c1e1df..1b6bf6480 100644 --- a/os/hal/ports/STM32/LLD/OTGv1/usb_lld.h +++ b/os/hal/ports/STM32/LLD/OTGv1/usb_lld.h @@ -260,10 +260,14 @@ typedef struct { * @brief Pointer to the input queue. */ input_queue_t *rxqueue; - } queue; - } mode; -} USBOutEndpointState; - + } queue; + } mode; + /** + * @brief Total transmit transfer size. + */ + size_t totsize; +} USBOutEndpointState; + /** * @brief Type of an USB endpoint configuration structure. * @note Platform specific restrictions may apply to endpoints.