/** * @brief Prepares for a transmit operation. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * * @notapi */ void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep) { size_t n; USBInEndpointState *isp = usbp->epc[ep]->in_state; uint32_t epr = STM32_USB->EPR[ep]; /* Transfer initialization.*/ n = isp->txsize; if (n > (size_t)usbp->epc[ep]->in_maxsize) n = (size_t)usbp->epc[ep]->in_maxsize; /* Double buffering is always enabled for isochronous endpoints, and although we overlap the two buffers for simplicity, we still need to write to the right counter. The DTOG_TX bit indicates the buffer 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.*/ USB_GET_DESCRIPTOR(ep)->TXCOUNT0 = (stm32_usb_pma_t)n; if (EPR_EP_TYPE_IS_ISO(epr) && (epr & EPR_DTOG_TX)) USB_GET_DESCRIPTOR(ep)->TXCOUNT1 = (stm32_usb_pma_t)n; if (isp->txqueued) usb_packet_write_from_queue(USB_GET_DESCRIPTOR(ep), isp->mode.queue.txqueue, n); else usb_packet_write_from_buffer(USB_GET_DESCRIPTOR(ep), isp->mode.linear.txbuf, n); }
/** * @brief Writes to a dedicated packet buffer. * * @param[in] ep endpoint number * @param[in] buf buffer where to fetch the packet data * @param[in] n maximum number of bytes to copy. This value must * not exceed the maximum packet size for this endpoint. * * @notapi */ static void usb_packet_write_from_buffer(usbep_t ep, const uint8_t *buf, size_t n) { stm32_usb_descriptor_t *udp = USB_GET_DESCRIPTOR(ep); stm32_usb_pma_t *pmap = USB_ADDR2PTR(udp->TXADDR0); int i = (int)n; #if STM32_USB_USE_ISOCHRONOUS uint32_t epr = STM32_USB->EPR[ep]; /* Double buffering is always enabled for isochronous endpoints, and although we overlap the two buffers for simplicity, we still need to write to the right counter. The DTOG_TX bit indicates the buffer 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.*/ 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; #else udp->TXCOUNT0 = (stm32_usb_pma_t)n; #endif #if STM32_USB_USE_FAST_COPY while (i >= 16) { uint32_t w; w = *(buf + 0); w |= *(buf + 1) << 8; *(pmap + 0) = (stm32_usb_pma_t)w; w = *(buf + 2); w |= *(buf + 3) << 8; *(pmap + 1) = (stm32_usb_pma_t)w; w = *(buf + 4); w |= *(buf + 5) << 8; *(pmap + 2) = (stm32_usb_pma_t)w; w = *(buf + 6); w |= *(buf + 7) << 8; *(pmap + 3) = (stm32_usb_pma_t)w; w = *(buf + 8); w |= *(buf + 9) << 8; *(pmap + 4) = (stm32_usb_pma_t)w; w = *(buf + 10); w |= *(buf + 11) << 8; *(pmap + 5) = (stm32_usb_pma_t)w; w = *(buf + 12); w |= *(buf + 13) << 8; *(pmap + 6) = (stm32_usb_pma_t)w; w = *(buf + 14); w |= *(buf + 15) << 8; *(pmap + 7) = (stm32_usb_pma_t)w; i -= 16; buf += 16; pmap += 8; } #endif /* STM32_USB_USE_FAST_COPY */ while (i > 0) { uint32_t w; w = *buf++; w |= *buf++ << 8; *pmap++ = (stm32_usb_pma_t)w; i -= 2; } }
/** * @brief Reads from a dedicated packet buffer. * * @param[in] ep endpoint number * @param[out] buf buffer where to copy the packet data * @return The size of the receivee packet. * * @notapi */ 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); stm32_usb_pma_t *pmap = USB_ADDR2PTR(udp->RXADDR0); #if STM32_USB_USE_ISOCHRONOUS uint32_t epr = STM32_USB->EPR[ep]; /* Double buffering is always enabled for isochronous endpoints, and although we overlap the two buffers for simplicity, we still need to read from the right counter. The DTOG_RX bit indicates the buffer that is currently in use by the USB peripheral, that is, the buffer 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.*/ 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; #else n = (size_t)udp->RXCOUNT0 & RXCOUNT_COUNT_MASK; #endif i = n; #if STM32_USB_USE_FAST_COPY while (i >= 16) { uint32_t w; w = *(pmap + 0); *(buf + 0) = (uint8_t)w; *(buf + 1) = (uint8_t)(w >> 8); w = *(pmap + 1); *(buf + 2) = (uint8_t)w; *(buf + 3) = (uint8_t)(w >> 8); w = *(pmap + 2); *(buf + 4) = (uint8_t)w; *(buf + 5) = (uint8_t)(w >> 8); w = *(pmap + 3); *(buf + 6) = (uint8_t)w; *(buf + 7) = (uint8_t)(w >> 8); w = *(pmap + 4); *(buf + 8) = (uint8_t)w; *(buf + 9) = (uint8_t)(w >> 8); w = *(pmap + 5); *(buf + 10) = (uint8_t)w; *(buf + 11) = (uint8_t)(w >> 8); w = *(pmap + 6); *(buf + 12) = (uint8_t)w; *(buf + 13) = (uint8_t)(w >> 8); w = *(pmap + 7); *(buf + 14) = (uint8_t)w; *(buf + 15) = (uint8_t)(w >> 8); i -= 16; buf += 16; pmap += 8; } #endif /* STM32_USB_USE_FAST_COPY */ while (i >= 2) { uint32_t w = *pmap++; *buf++ = (uint8_t)w; *buf++ = (uint8_t)(w >> 8); i -= 2; } if (i >= 1) { *buf = (uint8_t)*pmap; } return n; }