diff --git a/os/hal/include/serial_usb.h b/os/hal/include/serial_usb.h index 03c075f62..3cfa1441b 100644 --- a/os/hal/include/serial_usb.h +++ b/os/hal/include/serial_usb.h @@ -115,14 +115,10 @@ typedef struct { InputQueue iqueue; \ /* Output queue.*/ \ OutputQueue oqueue; \ - /* Input buffer 1.*/ \ - uint8_t ib1[SERIAL_USB_BUFFERS_SIZE]; \ - /* Input buffer 2.*/ \ - uint8_t ib2[SERIAL_USB_BUFFERS_SIZE]; \ - /* Output buffer 1.*/ \ - uint8_t ob1[SERIAL_USB_BUFFERS_SIZE]; \ - /* Output buffer 2.*/ \ - uint8_t ob2[SERIAL_USB_BUFFERS_SIZE]; \ + /* Input buffer.*/ \ + uint8_t ib[SERIAL_USB_BUFFERS_SIZE]; \ + /* Output buffer.*/ \ + uint8_t ob[SERIAL_USB_BUFFERS_SIZE]; \ /* End of the mandatory fields.*/ \ /* Current configuration data.*/ \ const SerialUSBConfig *config; diff --git a/os/hal/platforms/STM32/usb_lld.c b/os/hal/platforms/STM32/usb_lld.c index e1ba15de5..a95baf45f 100644 --- a/os/hal/platforms/STM32/usb_lld.c +++ b/os/hal/platforms/STM32/usb_lld.c @@ -58,11 +58,12 @@ static USBEndpointState ep0state; * @brief EP0 initialization structure. */ static const USBEndpointConfig ep0config = { + EP_TYPE_CTRL, _usb_ep0in, _usb_ep0out, 0x40, 0x40, - EPR_EP_TYPE_CONTROL | EPR_STAT_TX_NAK | EPR_STAT_RX_VALID, + 0, 0x40, 0x80 }; @@ -178,50 +179,63 @@ CH_IRQ_HANDLER(USB_LP_IRQHandler) { if (epr & EPR_CTR_TX) { /* IN endpoint, transmission.*/ EPR_CLEAR_CTR_TX(ep); - n = USB_GET_DESCRIPTOR(ep)->TXCOUNT; - usbp->ep[ep]->txbuf += n; - usbp->ep[ep]->txcnt += n; - usbp->ep[ep]->txsize -= n; - if (usbp->ep[ep]->txsize > 0) { - /* Transfer not completed, there are more packets to send.*/ - if (usbp->ep[ep]->txsize > epcp->in_maxsize) - n = epcp->in_maxsize; - else - n = usbp->ep[ep]->txsize; - write_packet(ep, usbp->ep[ep]->txbuf, n); + if (epcp->flags & USB_EP_FLAGS_IN_PACKET_MODE) { + /* Packet mode, just invokes the callback.*/ + (usbp)->ep[ep]->transmitting = FALSE; + epcp->in_cb(usbp, ep); } else { - /* Transfer completed, invoking the callback, if defined.*/ - (usbp)->ep[ep]->transmitting = FALSE; - if (epcp->in_cb) + /* Transaction mode.*/ + n = USB_GET_DESCRIPTOR(ep)->TXCOUNT; + usbp->ep[ep]->txbuf += n; + usbp->ep[ep]->txcnt += n; + usbp->ep[ep]->txsize -= n; + if (usbp->ep[ep]->txsize > 0) { + /* Transfer not completed, there are more packets to send.*/ + if (usbp->ep[ep]->txsize > epcp->in_maxsize) + n = epcp->in_maxsize; + else + n = usbp->ep[ep]->txsize; + write_packet(ep, usbp->ep[ep]->txbuf, n); + } + else { + /* Transfer completed, invokes the callback.*/ + (usbp)->ep[ep]->transmitting = FALSE; epcp->in_cb(usbp, ep); + } } } if (epr & EPR_CTR_RX) { EPR_CLEAR_CTR_RX(ep); /* OUT endpoint, receive.*/ - if ((epr & EPR_SETUP) && (ep == 0)) { - /* Special case, setup packet for EP0, enforcing a reset of the - EP0 state machine for robustness.*/ - usbp->ep0state = USB_EP0_WAITING_SETUP; - read_packet(0, usbp->setup, 8); + if (epcp->flags & USB_EP_FLAGS_IN_PACKET_MODE) { + /* Packet mode, just invokes the callback.*/ + (usbp)->ep[ep]->receiving = FALSE; epcp->out_cb(usbp, ep); } else { - n = read_packet(ep, usbp->ep[ep]->rxbuf, usbp->ep[ep]->rxsize); - usbp->ep[ep]->rxbuf += n; - usbp->ep[ep]->rxcnt += n; - usbp->ep[ep]->rxsize -= n; - usbp->ep[ep]->rxpkts -= 1; - if (usbp->ep[ep]->rxpkts > 0) { - /* Transfer not completed, there are more packets to receive.*/ - EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID); + if ((epr & EPR_SETUP) && (ep == 0)) { + /* Special case, setup packet for EP0, enforcing a reset of the + EP0 state machine for robustness.*/ + usbp->ep0state = USB_EP0_WAITING_SETUP; + read_packet(0, usbp->setup, 8); + epcp->out_cb(usbp, ep); } else { - /* Transfer completed, invoking the callback, if defined.*/ - (usbp)->ep[ep]->receiving = FALSE; - if (epcp->out_cb) + n = read_packet(ep, usbp->ep[ep]->rxbuf, usbp->ep[ep]->rxsize); + usbp->ep[ep]->rxbuf += n; + usbp->ep[ep]->rxcnt += n; + usbp->ep[ep]->rxsize -= n; + usbp->ep[ep]->rxpkts -= 1; + if (usbp->ep[ep]->rxpkts > 0) { + /* Transfer not completed, there are more packets to receive.*/ + EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID); + } + else { + /* Transfer completed, invokes the callback.*/ + (usbp)->ep[ep]->receiving = FALSE; epcp->out_cb(usbp, ep); + } } } } @@ -357,13 +371,43 @@ void usb_lld_set_address(USBDriver *usbp) { * @notapi */ void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) { - uint16_t nblocks; + uint16_t nblocks, epr; stm32_usb_descriptor_t *dp; const USBEndpointConfig *epcp = usbp->ep[ep]->config; + /* Setting the endpoint type.*/ + switch (epcp->ep_type) { + case EP_TYPE_ISOC: + epr = EPR_EP_TYPE_ISO; + break; + case EP_TYPE_BULK: + epr = EPR_EP_TYPE_BULK; + break; + case EP_TYPE_INTR: + epr = EPR_EP_TYPE_INTERRUPT; + break; + default: + epr = EPR_EP_TYPE_CONTROL; + } + + /* IN endpoint settings, always in NAK mode initially.*/ + if (epcp->in_cb) + epr |= EPR_STAT_TX_NAK; + + /* OUT endpoint settings. If the endpoint is in packet mode then it must + start ready to accept data else it must start in NAK mode.*/ + if (epcp->out_cb) { + if (epcp->flags & USB_EP_FLAGS_IN_PACKET_MODE) { + usbp->ep[ep]->receiving = TRUE; + epr |= EPR_STAT_RX_VALID; + } + else + epr |= EPR_STAT_RX_NAK; + } + /* EPxR register setup.*/ - EPR_SET(ep, epcp->epr | ep); - EPR_TOGGLE(ep, epcp->epr); + EPR_SET(ep, epr | ep); + EPR_TOGGLE(ep, epr); /* Endpoint size and address initialization.*/ if (epcp->out_maxsize > 62) diff --git a/os/hal/platforms/STM32/usb_lld.h b/os/hal/platforms/STM32/usb_lld.h index d365521ee..d1e3169c2 100644 --- a/os/hal/platforms/STM32/usb_lld.h +++ b/os/hal/platforms/STM32/usb_lld.h @@ -46,6 +46,16 @@ */ #define USB_SET_ADDRESS_MODE USB_LATE_SET_ADDRESS +/** + * @brief Enables the packet mode for an IN endpoint. + */ +#define USB_EP_FLAGS_IN_PACKET_MODE 1 + +/** + * @brief Enables the packet mode for an OUT endpoint. + */ +#define USB_EP_FLAGS_OUT_PACKET_MODE 2 + /*===========================================================================*/ /* Driver pre-compile time settings. */ /*===========================================================================*/ @@ -98,28 +108,39 @@ * @note Platform specific restrictions may apply to endpoints. */ typedef struct { + /** + * @brief Type of the endpoint. + */ + usbeptype_t ep_type; /** * @brief IN endpoint notification callback. + * @details This field must be set to @p NULL if the IN endpoint is not + * used. */ usbepcallback_t in_cb; /** * @brief OUT endpoint notification callback. + * @details This field must be set to @p NULL if the OUT endpoint is not + * used. */ usbepcallback_t out_cb; /** * @brief IN endpoint maximum packet size. + * @details This field must be set to zero if the IN endpoint is not + * used. */ uint16_t in_maxsize; /** * @brief OUT endpoint maximum packet size. + * @details This field must be set to zero if the OUT endpoint is not + * used. */ uint16_t out_maxsize; /* End of the mandatory fields.*/ /** - * @brief EPxR register initialization value. - * @note Do not specify the EA field, leave it to zero. + * @bief Endpoint mode flags. */ - uint16_t epr; + uint16_t flags; /** * @brief Endpoint IN buffer address as offset in the PMA. */ diff --git a/testhal/STM32/USB_CDC/main.c b/testhal/STM32/USB_CDC/main.c index b55b24892..04fd4d615 100644 --- a/testhal/STM32/USB_CDC/main.c +++ b/testhal/STM32/USB_CDC/main.c @@ -251,11 +251,12 @@ USBEndpointState ep3state; * @brief EP1 initialization structure (IN only). */ static const USBEndpointConfig ep1config = { + EP_TYPE_BULK, sduDataTransmitted, NULL, 0x0040, 0x0000, - EPR_EP_TYPE_BULK | EPR_STAT_TX_NAK | EPR_STAT_RX_DIS, + USB_EP_FLAGS_IN_PACKET_MODE, 0x00C0, 0x0000 }; @@ -264,11 +265,12 @@ static const USBEndpointConfig ep1config = { * @brief EP2 initialization structure (IN only). */ static const USBEndpointConfig ep2config = { + EP_TYPE_INTR, sduInterruptTransmitted, NULL, 0x0010, 0x0000, - EPR_EP_TYPE_INTERRUPT | EPR_STAT_TX_NAK | EPR_STAT_RX_DIS, + 0, 0x0100, 0x0000 }; @@ -277,11 +279,12 @@ static const USBEndpointConfig ep2config = { * @brief EP3 initialization structure (OUT only). */ static const USBEndpointConfig ep3config = { + EP_TYPE_BULK, NULL, sduDataReceived, 0x0000, 0x0040, - EPR_EP_TYPE_BULK | EPR_STAT_TX_DIS | EPR_STAT_RX_VALID, + USB_EP_FLAGS_OUT_PACKET_MODE, 0x0000, 0x0110 };