aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/ports/STM32/LLD/USBv1/usb_lld.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/hal/ports/STM32/LLD/USBv1/usb_lld.c')
-rw-r--r--os/hal/ports/STM32/LLD/USBv1/usb_lld.c78
1 files changed, 75 insertions, 3 deletions
diff --git a/os/hal/ports/STM32/LLD/USBv1/usb_lld.c b/os/hal/ports/STM32/LLD/USBv1/usb_lld.c
index d5a1c62d1..a4a8e4519 100644
--- a/os/hal/ports/STM32/LLD/USBv1/usb_lld.c
+++ b/os/hal/ports/STM32/LLD/USBv1/usb_lld.c
@@ -126,6 +126,7 @@ static uint32_t usb_pm_alloc(USBDriver *usbp, size_t size) {
*
* @notapi
*/
+__attribute__((noinline))
static size_t usb_packet_read_to_buffer(usbep_t ep, uint8_t *buf) {
size_t i, n;
stm32_usb_descriptor_t *udp = USB_GET_DESCRIPTOR(ep);
@@ -139,9 +140,10 @@ static size_t usb_packet_read_to_buffer(usbep_t ep, uint8_t *buf) {
in which the next received packet will be stored, so we need to
read the counter of the OTHER buffer, which is where the last
received packet was stored.*/
- n = (size_t)udp->RXCOUNT0 & RXCOUNT_COUNT_MASK;
if (EPR_EP_TYPE_IS_ISO(epr) && !(epr & EPR_DTOG_RX))
n = (size_t)udp->RXCOUNT1 & RXCOUNT_COUNT_MASK;
+ else
+ n = (size_t)udp->RXCOUNT0 & RXCOUNT_COUNT_MASK;
i = n;
while (i > 1) {
@@ -183,9 +185,10 @@ static void usb_packet_write_from_buffer(usbep_t ep,
that is currently in use by the USB peripheral, that is, the buffer
from which the next packet will be sent, so we need to write the
counter of that buffer.*/
- udp->TXCOUNT0 = (stm32_usb_pma_t)n;
if (EPR_EP_TYPE_IS_ISO(epr) && (epr & EPR_DTOG_TX))
udp->TXCOUNT1 = (stm32_usb_pma_t)n;
+ else
+ udp->TXCOUNT0 = (stm32_usb_pma_t)n;
while (i > 0) {
w = *buf++;
@@ -413,7 +416,17 @@ void usb_lld_start(USBDriver *usbp) {
/* Reset procedure enforced on driver start.*/
_usb_reset(usbp);
}
- /* Configuration.*/
+
+#if STM32_USB_USE_PUMP_THREAD && defined(_CHIBIOS_RT_)
+ /* Creates the data pump thread. Note, it is created only once.*/
+ if (usbp->tr == NULL) {
+ usbp->tr = chThdCreateI(usbp->wa_pump, sizeof usbp->wa_pump,
+ STM32_USB_PUMP_THREAD_PRIO,
+ usb_lld_pump, usbp);
+ chThdStartI(usbp->tr);
+ chSchRescheduleS();
+ }
+#endif
}
/**
@@ -765,6 +778,65 @@ void usb_lld_clear_in(USBDriver *usbp, usbep_t ep) {
EPR_SET_STAT_TX(ep, EPR_STAT_TX_NAK);
}
+#if STM32_USB_USE_PUMP_THREAD || defined(__DOXYGEN__)
+/**
+ * @brief USB data transfer loop.
+ * @details This function must be executed by a system thread in order to
+ * make the USB driver work.
+ * @note The data copy part of the driver is implemented in this thread
+ * in order to not perform heavy tasks within interrupt handlers.
+ *
+ * @param[in] p pointer to the @p USBDriver object
+ *
+ * @special
+ */
+void usb_lld_pump(void *p) {
+ USBDriver *usbp = (USBDriver *)p;
+
+#if defined(_CHIBIOS_RT_)
+ chRegSetThreadName("usb_lld_pump");
+#endif
+ while (true) {
+ usbep_t ep;
+
+ /* Checking if to go to sleep.*/
+ osalSysLock();
+ if ((usbp->state == USB_STOP) && (usbp->pending == 0U)) {
+ osalThreadSuspendS(&usbp->wait);
+ }
+ osalSysUnlock();
+
+ /* Scanning endpoints.*/
+ for (ep = 0; ep <= USB_ENDOPOINTS_NUMBER; ep++) {
+ uint32_t epmask;
+
+ /* Checking of active endpoints.*/
+ const USBEndpointConfig *epcp = usbp->epc[ep];
+ if (epcp != NULL) {
+ if (epcp->in_state != NULL) {
+ epmask = (1U << 16U) << ep;
+ if ((usbp->pending & epmask) != 0U) {
+ /* Handling transfer of this IN endpoint.*/
+
+ osalSysLock();
+ usbp->pending &= ~epmask;
+ osalSysUnlock();
+ }
+ epmask = 1U << ep;
+ if ((usbp->pending & epmask) != 0U) {
+ /* Handling transfer of this OUT endpoint.*/
+
+ osalSysLock();
+ usbp->pending &= ~epmask;
+ osalSysUnlock();
+ }
+ }
+ }
+ }
+ }
+}
+#endif /* STM32_USB_USE_PUMP_THREAD */
+
#endif /* HAL_USE_USB */
/** @} */