Merge pull request #2560 from hathach/fix-h5-errata-2.15.1

Follow up to h5 errata 2.15.1
This commit is contained in:
Ha Thach 2024-04-01 00:03:10 +07:00 committed by GitHub
commit 82dfe95655
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 106 additions and 137 deletions

View File

@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="stlink" type="com.jetbrains.cidr.embedded.customgdbserver.type" factoryName="com.jetbrains.cidr.embedded.customgdbserver.factory" folderName="stm32" PROGRAM_PARAMS="-p 28833 -cp &quot;/opt/st/stm32cubeide_1.12.1/plugins/com.st.stm32cube.ide.mcu.externaltools.cubeprogrammer.linux64_2.1.100.202311100844/tools/bin&quot; --frequency 8000 --swd" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="tinyusb_examples" TARGET_NAME="cdc_msc" CONFIG_NAME="stm32h563nucleo" version="1" RUN_TARGET_PROJECT_NAME="tinyusb_examples" RUN_TARGET_NAME="cdc_msc"> <configuration default="false" name="stlink" type="com.jetbrains.cidr.embedded.customgdbserver.type" factoryName="com.jetbrains.cidr.embedded.customgdbserver.factory" folderName="stm32" PROGRAM_PARAMS="-p 10458 -cp &quot;/opt/st/stm32cubeide_1.14.0/plugins/com.st.stm32cube.ide.mcu.externaltools.cubeprogrammer.linux64_2.1.100.202311100844/tools/bin&quot; --frequency 8000 --swd" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="tinyusb_device_examples" TARGET_NAME="cdc_msc" CONFIG_NAME="stm32h563nucleo" version="1" RUN_TARGET_PROJECT_NAME="tinyusb_device_examples" RUN_TARGET_NAME="cdc_msc">
<custom-gdb-server version="1" gdb-connect="tcp::28833" executable="/opt/st/stm32cubeide_1.12.1/plugins/com.st.stm32cube.ide.mcu.externaltools.stlink-gdb-server.linux64_2.1.100.202310302101/tools/bin/ST-LINK_gdbserver" warmup-ms="0" download-type="ALWAYS" reset-cmd="monitor reset" reset-type="AFTER_DOWNLOAD"> <custom-gdb-server version="1" gdb-connect="tcp::10458" executable="/opt/st/stm32cubeide_1.14.0/plugins/com.st.stm32cube.ide.mcu.externaltools.stlink-gdb-server.linux64_2.1.100.202310302101/tools/bin/ST-LINK_gdbserver" warmup-ms="0" download-type="ALWAYS" reset-cmd="monitor reset" reset-type="AFTER_DOWNLOAD">
<debugger kind="GDB" isBundled="true" /> <debugger kind="GDB" isBundled="true" />
</custom-gdb-server> </custom-gdb-server>
<method v="2"> <method v="2">

View File

@ -109,7 +109,7 @@
#ifdef TUP_USBIP_FSDEV_STM32 #ifdef TUP_USBIP_FSDEV_STM32
// Undefine to reduce the dependence on HAL // Undefine to reduce the dependence on HAL
#undef USE_HAL_DRIVER #undef USE_HAL_DRIVER
#include "portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h" #include "portable/st/stm32_fsdev/dcd_stm32_fsdev.h"
#endif #endif
/***************************************************** /*****************************************************
@ -200,8 +200,7 @@ static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNB
// Inline helper // Inline helper
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t ep_addr) TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t ep_addr) {
{
uint8_t epnum = tu_edpt_number(ep_addr); uint8_t epnum = tu_edpt_number(ep_addr);
uint8_t dir = tu_edpt_dir(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr);
// Fix -Werror=null-dereference // Fix -Werror=null-dereference
@ -524,7 +523,7 @@ static void dcd_ep_ctr_tx_handler(uint32_t wIstr)
xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr);
if((xfer->total_len != xfer->queued_len)) /* TX not complete */ if((xfer->total_len != xfer->queued_len)) /* TX not complete */
{ {
dcd_transmit_packet(xfer, EPindex); dcd_transmit_packet(xfer, EPindex);
} }
else /* TX Complete */ else /* TX Complete */
{ {
@ -533,10 +532,29 @@ static void dcd_ep_ctr_tx_handler(uint32_t wIstr)
} }
// Handle CTR interrupt for the RX/OUT direction // Handle CTR interrupt for the RX/OUT direction
//
// Upon call, (wIstr & USB_ISTR_DIR) == 0U // Upon call, (wIstr & USB_ISTR_DIR) == 0U
static void dcd_ep_ctr_rx_handler(uint32_t wIstr) static void dcd_ep_ctr_rx_handler(uint32_t wIstr) {
{ #ifdef FSDEV_BUS_32BIT
/* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf
* From STM32H503 errata 2.15.1: Buffer description table update completes after CTR interrupt triggers
* Description:
* - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses
* have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct.
* Workaround:
* - Software should ensure that a small delay is included before accessing the SRAM contents. This delay
* should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode
* - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code
* also takes time, so we'll wait 40 cycles (count = 20).
* - Since Low Speed mode is not supported/popular, we will ignore it for now.
*
* Note: this errata also seems to apply to G0, U5, H5 etc.
*/
volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver
while (cycle_count > 0U) {
cycle_count--; // each count take 2 cycle (1 cycle for sub, 1 cycle for compare/jump)
}
#endif
uint32_t EPindex = wIstr & USB_ISTR_EP_ID; uint32_t EPindex = wIstr & USB_ISTR_EP_ID;
uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex); uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex);
uint8_t ep_addr = wEPRegVal & USB_EPADDR_FIELD; uint8_t ep_addr = wEPRegVal & USB_EPADDR_FIELD;
@ -545,8 +563,7 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr)
// Verify the CTR_RX bit is set. This was in the ST Micro code, // Verify the CTR_RX bit is set. This was in the ST Micro code,
// but I'm not sure it's actually necessary? // but I'm not sure it's actually necessary?
if((wEPRegVal & USB_EP_CTR_RX) == 0U) if((wEPRegVal & USB_EP_CTR_RX) == 0U) {
{
return; return;
} }
@ -633,26 +650,22 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr)
// (Based on the docs, it seems SETUP will always be accepted after CTR is cleared) // (Based on the docs, it seems SETUP will always be accepted after CTR is cleared)
if(ep_addr == 0u) if(ep_addr == 0u)
{ {
// Always be prepared for a status packet... // Always be prepared for a status packet...
pcd_set_ep_rx_bufsize(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE); pcd_set_ep_rx_bufsize(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE);
pcd_clear_rx_ep_ctr(USB, EPindex); pcd_clear_rx_ep_ctr(USB, EPindex);
} }
} }
static void dcd_ep_ctr_handler(void) static void dcd_ep_ctr_handler(void) {
{
uint32_t wIstr; uint32_t wIstr;
/* stay in loop while pending interrupts */ /* stay in loop while pending interrupts */
while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U) while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U) {
{ if ((wIstr & USB_ISTR_DIR) == 0U) {
/* TX/IN */
if ((wIstr & USB_ISTR_DIR) == 0U) /* TX/IN */
{
dcd_ep_ctr_tx_handler(wIstr); dcd_ep_ctr_tx_handler(wIstr);
} } else {
else /* RX/OUT*/ /* RX/OUT*/
{
dcd_ep_ctr_rx_handler(wIstr); dcd_ep_ctr_rx_handler(wIstr);
} }
} }

View File

@ -1,30 +1,32 @@
/** /*
* Copyright(c) 2016 STMicroelectronics * Copyright(c) 2016 STMicroelectronics
* Copyright(c) N Conrad * Copyright(c) N Conrad
* * Copyright (c) 2019 Ha Thach (tinyusb.org)
* Redistribution and use in source and binary forms, with or without modification, *
* are permitted provided that the following conditions are met: * Redistribution and use in source and binary forms, with or without modification,
* 1. Redistributions of source code must retain the above copyright notice, * are permitted provided that the following conditions are met:
* this list of conditions and the following disclaimer. * 1. Redistributions of source code must retain the above copyright notice,
* 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer.
* this list of conditions and the following disclaimer in the documentation * 2. Redistributions in binary form must reproduce the above copyright notice,
* and/or other materials provided with the distribution. * this list of conditions and the following disclaimer in the documentation
* 3. Neither the name of STMicroelectronics nor the names of its contributors * and/or other materials provided with the distribution.
* may be used to endorse or promote products derived from this software * 3. Neither the name of STMicroelectronics nor the names of its contributors
* without specific prior written permission. * may be used to endorse or promote products derived from this software
* * without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" *
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ *
* This file is part of the TinyUSB stack.
*/
// This file contains source copied from ST's HAL, and thus should have their copyright statement. // This file contains source copied from ST's HAL, and thus should have their copyright statement.
@ -138,7 +140,6 @@
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
#define USB_CNTR_FSUSP USB_CNTR_SUSPEN #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
#elif CFG_TUSB_MCU == OPT_MCU_STM32WB #elif CFG_TUSB_MCU == OPT_MCU_STM32WB
#include "stm32wbxx.h" #include "stm32wbxx.h"
#define FSDEV_PMA_SIZE (1024u) #define FSDEV_PMA_SIZE (1024u)
@ -182,27 +183,23 @@ typedef uint16_t fsdev_bus_t;
// Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden) // Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden)
static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR; static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR;
TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) {
{
size_t total_word_offset = (((USBx)->BTABLE)>>1) + x; size_t total_word_offset = (((USBx)->BTABLE)>>1) + x;
total_word_offset *= FSDEV_PMA_STRIDE; total_word_offset *= FSDEV_PMA_STRIDE;
return &(pma[total_word_offset]); return &(pma[total_word_offset]);
} }
TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) {
{
return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 1u); return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 1u);
} }
TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) {
{
return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 3u); return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 3u);
} }
#endif #endif
/* Aligned buffer size according to hardware */ /* Aligned buffer size according to hardware */
TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t size) TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t size) {
{
/* The STM32 full speed USB peripheral supports only a limited set of /* The STM32 full speed USB peripheral supports only a limited set of
* buffer sizes given by the RX buffer entry format in the USB_BTABLE. */ * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */
uint16_t blocksize = (size > 62) ? 32 : 2; uint16_t blocksize = (size > 62) ? 32 : 2;
@ -213,9 +210,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t si
return numblocks * blocksize; return numblocks * blocksize;
} }
/* SetENDPOINT */ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue) {
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue)
{
#ifdef FSDEV_BUS_32BIT #ifdef FSDEV_BUS_32BIT
(void) USBx; (void) USBx;
__O uint32_t *reg = (__O uint32_t *)(USB_DRD_BASE + bEpIdx*4); __O uint32_t *reg = (__O uint32_t *)(USB_DRD_BASE + bEpIdx*4);
@ -226,7 +221,6 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, ui
#endif #endif
} }
/* GetENDPOINT */
TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) { TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) {
#ifdef FSDEV_BUS_32BIT #ifdef FSDEV_BUS_32BIT
(void) USBx; (void) USBx;
@ -237,8 +231,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_endpoint(USB_TypeDef * USBx
return *reg; return *reg;
} }
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wType) TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wType) {
{
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= (uint32_t)USB_EP_T_MASK; regVal &= (uint32_t)USB_EP_T_MASK;
regVal |= wType; regVal |= wType;
@ -246,20 +239,19 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint
pcd_set_endpoint(USBx, bEpIdx, regVal); pcd_set_endpoint(USBx, bEpIdx, regVal);
} }
TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpIdx) TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpIdx) {
{
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EP_T_FIELD; regVal &= USB_EP_T_FIELD;
return regVal; return regVal;
} }
/** /**
* @brief Clears bit CTR_RX / CTR_TX in the endpoint register. * @brief Clears bit CTR_RX / CTR_TX in the endpoint register.
* @param USBx USB peripheral instance register address. * @param USBx USB peripheral instance register address.
* @param bEpIdx Endpoint Number. * @param bEpIdx Endpoint Number.
* @retval None * @retval None
*/ */
TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) {
{
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPREG_MASK; regVal &= USB_EPREG_MASK;
regVal &= ~USB_EP_CTR_RX; regVal &= ~USB_EP_CTR_RX;
@ -267,22 +259,21 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx,
pcd_set_endpoint(USBx, bEpIdx, regVal); pcd_set_endpoint(USBx, bEpIdx, regVal);
} }
TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) {
{
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPREG_MASK; regVal &= USB_EPREG_MASK;
regVal &= ~USB_EP_CTR_TX; regVal &= ~USB_EP_CTR_TX;
regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0) regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0)
pcd_set_endpoint(USBx, bEpIdx,regVal); pcd_set_endpoint(USBx, bEpIdx,regVal);
} }
/** /**
* @brief gets counter of the tx buffer. * @brief gets counter of the tx buffer.
* @param USBx USB peripheral instance register address. * @param USBx USB peripheral instance register address.
* @param bEpIdx Endpoint Number. * @param bEpIdx Endpoint Number.
* @retval Counter value * @retval Counter value
*/ */
TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) {
{
#ifdef FSDEV_BUS_32BIT #ifdef FSDEV_BUS_32BIT
(void) USBx; (void) USBx;
return (pma32[2*bEpIdx] & 0x03FF0000) >> 16; return (pma32[2*bEpIdx] & 0x03FF0000) >> 16;
@ -292,20 +283,9 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USB
#endif #endif
} }
TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) {
{
#ifdef FSDEV_BUS_32BIT #ifdef FSDEV_BUS_32BIT
(void) USBx; (void) USBx;
/* WA: few cycles for RX PMA descriptor to update, otherwise doesn't return the correct value.
Note: required for G0, U5, H5 etc.
This workaround is ported from stm32h5xx_hal_pcd.h and fixes the issue when calling this function fast enough.
Reproduced with GCC ast optimization(O2/O3) and stm32h573i_dk with an high frequency.
Observed on Windows 10 where tud_task() is scheduled by interrupt handler.
*/
volatile uint32_t count = 10; // defined as PCD_RX_PMA_CNT in stm32 hal_driver
while (count > 0U) {
count--;
}
return (pma32[2*bEpIdx + 1] & 0x03FF0000) >> 16; return (pma32[2*bEpIdx + 1] & 0x03FF0000) >> 16;
#else #else
__I uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); __I uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpIdx);
@ -320,8 +300,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USB
* @param bAddr Address. * @param bAddr Address.
* @retval None * @retval None
*/ */
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t bAddr) TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t bAddr) {
{
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPREG_MASK; regVal &= USB_EPREG_MASK;
regVal |= bAddr; regVal |= bAddr;
@ -329,8 +308,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx,
pcd_set_endpoint(USBx, bEpIdx,regVal); pcd_set_endpoint(USBx, bEpIdx,regVal);
} }
TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx) TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx) {
{
#ifdef FSDEV_BUS_32BIT #ifdef FSDEV_BUS_32BIT
(void) USBx; (void) USBx;
return pma32[2*bEpIdx] & 0x0000FFFFu ; return pma32[2*bEpIdx] & 0x0000FFFFu ;
@ -339,8 +317,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef *
#endif #endif
} }
TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx) TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx) {
{
#ifdef FSDEV_BUS_32BIT #ifdef FSDEV_BUS_32BIT
(void) USBx; (void) USBx;
return pma32[2*bEpIdx + 1] & 0x0000FFFFu; return pma32[2*bEpIdx + 1] & 0x0000FFFFu;
@ -349,8 +326,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef *
#endif #endif
} }
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) {
{
#ifdef FSDEV_BUS_32BIT #ifdef FSDEV_BUS_32BIT
(void) USBx; (void) USBx;
pma32[2*bEpIdx] = (pma32[2*bEpIdx] & 0xFFFF0000u) | (addr & 0x0000FFFCu); pma32[2*bEpIdx] = (pma32[2*bEpIdx] & 0xFFFF0000u) | (addr & 0x0000FFFCu);
@ -359,8 +335,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USB
#endif #endif
} }
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) {
{
#ifdef FSDEV_BUS_32BIT #ifdef FSDEV_BUS_32BIT
(void) USBx; (void) USBx;
pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & 0xFFFF0000u) | (addr & 0x0000FFFCu); pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & 0xFFFF0000u) | (addr & 0x0000FFFCu);
@ -369,8 +344,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USB
#endif #endif
} }
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
{
#ifdef FSDEV_BUS_32BIT #ifdef FSDEV_BUS_32BIT
(void) USBx; (void) USBx;
pma32[2*bEpIdx] = (pma32[2*bEpIdx] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16); pma32[2*bEpIdx] = (pma32[2*bEpIdx] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16);
@ -380,8 +354,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, u
#endif #endif
} }
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
{
#ifdef FSDEV_BUS_32BIT #ifdef FSDEV_BUS_32BIT
(void) USBx; (void) USBx;
pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16); pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16);
@ -391,8 +364,8 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, u
#endif #endif
} }
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDef * USBx, uint32_t rxtx_idx, uint32_t blocksize, uint32_t numblocks) TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDef * USBx, uint32_t rxtx_idx,
{ uint32_t blocksize, uint32_t numblocks) {
/* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */
#ifdef FSDEV_BUS_32BIT #ifdef FSDEV_BUS_32BIT
(void) USBx; (void) USBx;
@ -403,8 +376,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDe
#endif #endif
} }
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_bufsize(USB_TypeDef * USBx, uint32_t rxtx_idx, uint32_t wCount) TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_bufsize(USB_TypeDef * USBx, uint32_t rxtx_idx, uint32_t wCount) {
{
wCount = pcd_aligned_buffer_size(wCount); wCount = pcd_aligned_buffer_size(wCount);
/* We assume that the buffer size is already aligned to hardware requirements. */ /* We assume that the buffer size is already aligned to hardware requirements. */
@ -418,13 +390,11 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_bufsize(USB_TypeDef * USBx,
pcd_set_ep_blsize_num_blocks(USBx, rxtx_idx, blocksize, numblocks); pcd_set_ep_blsize_num_blocks(USBx, rxtx_idx, blocksize, numblocks);
} }
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
{
pcd_set_ep_bufsize(USBx, 2*bEpIdx, wCount); pcd_set_ep_bufsize(USBx, 2*bEpIdx, wCount);
} }
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
{
pcd_set_ep_bufsize(USBx, 2*bEpIdx + 1, wCount); pcd_set_ep_bufsize(USBx, 2*bEpIdx + 1, wCount);
} }
@ -435,8 +405,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_bufsize(USB_TypeDef * USB
* @param wState new state * @param wState new state
* @retval None * @retval None
*/ */
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) {
{
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPTX_DTOGMASK; regVal &= USB_EPTX_DTOGMASK;
@ -453,7 +422,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
pcd_set_endpoint(USBx, bEpIdx, regVal); pcd_set_endpoint(USBx, bEpIdx, regVal);
} /* pcd_set_ep_tx_status */ }
/** /**
* @brief sets the status for rx transfer (bits STAT_TX[1:0]) * @brief sets the status for rx transfer (bits STAT_TX[1:0])
@ -463,31 +432,27 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx
* @retval None * @retval None
*/ */
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) {
{
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPRX_DTOGMASK; regVal &= USB_EPRX_DTOGMASK;
/* toggle first bit ? */ /* toggle first bit ? */
if((USB_EPRX_DTOG1 & wState)!= 0U) if((USB_EPRX_DTOG1 & wState)!= 0U) {
{
regVal ^= USB_EPRX_DTOG1; regVal ^= USB_EPRX_DTOG1;
} }
/* toggle second bit ? */ /* toggle second bit ? */
if((USB_EPRX_DTOG2 & wState)!= 0U) if((USB_EPRX_DTOG2 & wState)!= 0U) {
{
regVal ^= USB_EPRX_DTOG2; regVal ^= USB_EPRX_DTOG2;
} }
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
pcd_set_endpoint(USBx, bEpIdx, regVal); pcd_set_endpoint(USBx, bEpIdx, regVal);
} /* pcd_set_ep_rx_status */ }
TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx) TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx) {
{
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
return (regVal & USB_EPRX_STAT) >> (12u); return (regVal & USB_EPRX_STAT) >> (12u);
} /* pcd_get_ep_rx_status */ }
/** /**
@ -496,16 +461,14 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef *
* @param bEpIdx Endpoint Number. * @param bEpIdx Endpoint Number.
* @retval None * @retval None
*/ */
TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
{
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPREG_MASK; regVal &= USB_EPREG_MASK;
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_RX; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_RX;
pcd_set_endpoint(USBx, bEpIdx, regVal); pcd_set_endpoint(USBx, bEpIdx, regVal);
} }
TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
{
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPREG_MASK; regVal &= USB_EPREG_MASK;
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_TX; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_TX;
@ -518,21 +481,16 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32
* @param bEpIdx Endpoint Number. * @param bEpIdx Endpoint Number.
* @retval None * @retval None
*/ */
TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx)
{
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
if((regVal & USB_EP_DTOG_RX) != 0) if((regVal & USB_EP_DTOG_RX) != 0) {
{
pcd_rx_dtog(USBx,bEpIdx); pcd_rx_dtog(USBx,bEpIdx);
} }
} }
TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
{
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
if((regVal & USB_EP_DTOG_TX) != 0) if((regVal & USB_EP_DTOG_TX) != 0) {
{
pcd_tx_dtog(USBx,bEpIdx); pcd_tx_dtog(USBx,bEpIdx);
} }
} }
@ -543,17 +501,15 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx,
* @param bEpIdx Endpoint Number. * @param bEpIdx Endpoint Number.
* @retval None * @retval None
*/ */
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) {
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx)
{
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal |= USB_EP_KIND; regVal |= USB_EP_KIND;
regVal &= USB_EPREG_MASK; regVal &= USB_EPREG_MASK;
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
pcd_set_endpoint(USBx, bEpIdx, regVal); pcd_set_endpoint(USBx, bEpIdx, regVal);
} }
TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx)
{ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPKIND_MASK; regVal &= USB_EPKIND_MASK;
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;