From 5a4d1701023e5dd841eb7cfb84605c8c3e5c6953 Mon Sep 17 00:00:00 2001 From: Epagris Date: Tue, 25 Jun 2024 08:07:55 +0200 Subject: [PATCH 1/4] - HS implementation debugging --- usb_common_defs.h | 10 ++-- usb_driver.c | 127 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 111 insertions(+), 26 deletions(-) diff --git a/usb_common_defs.h b/usb_common_defs.h index 8162e38..f5f6678 100644 --- a/usb_common_defs.h +++ b/usb_common_defs.h @@ -18,10 +18,10 @@ #endif -#define USBD ((USB_OTG_DeviceTypeDef *) ((uint32_t)(USBG) + (uint32_t)(USB_OTG_DEVICE_BASE))) -#define USBINEP ((USB_OTG_INEndpointTypeDef *) ((uint32_t)(USBG) + (uint32_t)(USB_OTG_IN_ENDPOINT_BASE))) -#define USBOUTEP ((USB_OTG_OUTEndpointTypeDef *) ((uint32_t)(USBG) + (uint32_t)(USB_OTG_OUT_ENDPOINT_BASE))) -#define USBFIFO(ep) ((uint32_t *)((uint32_t)(USBG) + USB_OTG_FIFO_BASE + (USB_OTG_FIFO_SIZE) * (ep))) -#define USBPCGCCTL ((uint32_t *)((uint32_t)(USBG) + USB_OTG_PCGCCTL_BASE)) +#define USBD ((USB_OTG_DeviceTypeDef *) (((uint32_t)(USBG)) + ((uint32_t)(USB_OTG_DEVICE_BASE)))) +#define USBINEP ((USB_OTG_INEndpointTypeDef *) (((uint32_t)(USBG)) + ((uint32_t)(USB_OTG_IN_ENDPOINT_BASE)))) +#define USBOUTEP ((USB_OTG_OUTEndpointTypeDef *) (((uint32_t)(USBG)) + ((uint32_t)(USB_OTG_OUT_ENDPOINT_BASE)))) +#define USBFIFO(ep) ((uint32_t *)(((uint32_t)(USBG)) + USB_OTG_FIFO_BASE + (USB_OTG_FIFO_SIZE) * (ep))) +#define USBPCGCCTL ((uint32_t *)(((uint32_t)(USBG)) + USB_OTG_PCGCCTL_BASE)) #endif /* CORE_USB_USB_COMMON_DEFS */ diff --git a/usb_driver.c b/usb_driver.c index c8f75e7..9d1e962 100644 --- a/usb_driver.c +++ b/usb_driver.c @@ -45,14 +45,22 @@ static const char *FIFO_STATUS_STR[6] = { #if defined(USB_STM32H7) #define USB_GPIO_AF (GPIO_AF10_OTG2_FS) #elif defined(USB_STM32F4) +#ifdef USB_HIGH_SPEED +#define USB_GPIO_AF (GPIO_AF10_OTG_HS) +#else #define USB_GPIO_AF (GPIO_AF10_OTG_FS) #endif +#endif // USB pin low level, early peripheral initialization // PA12: D+, PA11: D- void usbdrv_gpio_init() { // turn GPIO-s into AF mode __HAL_RCC_GPIOA_CLK_ENABLE(); // turn ON GPIOA clocks +#ifdef USB_HIGH_SPEED + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); +#endif GPIO_InitTypeDef gpio_init; gpio_init.Mode = GPIO_MODE_AF_PP; @@ -60,6 +68,19 @@ void usbdrv_gpio_init() { gpio_init.Pull = GPIO_NOPULL; gpio_init.Alternate = USB_GPIO_AF; +#ifdef USB_HIGH_SPEED + gpio_init.Pin = GPIO_PIN_3 | GPIO_PIN_5; // D0, CK + HAL_GPIO_Init(GPIOA, &gpio_init); + + // D1, D2, D7, D3, D4, D5, D6 + gpio_init.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_5 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13; + HAL_GPIO_Init(GPIOB, &gpio_init); + + // STP, DIR, NXT + gpio_init.Pin = GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_3; + HAL_GPIO_Init(GPIOC, &gpio_init); +#else + /* Pin initializations cannot be OR-ed together! */ gpio_init.Pin = GPIO_PIN_11; @@ -81,13 +102,20 @@ void usbdrv_gpio_init() { // gpio_init.Alternate = 0; // HAL_GPIO_Init(GPIOA, &gpio_init); // USB VBUSSENSE +#endif } // --------------- +#ifdef USB_HIGH_SPEED +#define USB_IRQn OTG_HS_IRQn +#else +#define USB_IRQn OTG_FS_IRQn +#endif + // initialize USB subsystem void usbdrv_init() { - NVIC_DisableIRQ(OTG_FS_IRQn); + NVIC_DisableIRQ(USB_IRQn); usbdrv_init_global_state(); usbdrv_gpio_init(); @@ -95,8 +123,8 @@ void usbdrv_init() { usbdrv_initial_ep0_setup(); usbdrv_power_and_connect(true); - NVIC_SetPriority(OTG_FS_IRQn, 6); - NVIC_EnableIRQ(OTG_FS_IRQn); + NVIC_SetPriority(USB_IRQn, 0); + NVIC_EnableIRQ(USB_IRQn); } void usbdrv_reset() { @@ -132,17 +160,30 @@ void usbdrv_init_global_state() { #endif } -#if defined(USB_STM32H7) +#ifdef USB_HIGH_SPEED +__weak void usbdrv_ulpi_init() { + return; +} +#endif + +#if defined(USB_STM32H7) /*|| defined(USB_HIGH_SPEED)*/ #define TOCAL_VALUE (0x00) #define TRDT_VALUE (0x05) #elif defined(USB_STM32F4) +#if !defined(USB_HIGH_SPEED) #define TOCAL_VALUE (0x07) #define TRDT_VALUE (0x06) +#else +#define TOCAL_VALUE (0x07) +#define TRDT_VALUE (0x09) +#endif #endif // --------------- #define USB_LINESPEED_FULL_SPEED (0b11) +#define USB_LINESPEED_FULL_SPEED_ULPI (0b01) +#define USB_LINESPEED_HIGH_SPEED_ULPI (0b00) // initialize USB peripheral void usbdrv_periph_init() { @@ -151,9 +192,17 @@ void usbdrv_periph_init() { WAIT_FOR_nBIT(PWR->CR3, PWR_CR3_USB33RDY); #endif - __HAL_RCC_USB_OTG_FS_CLK_ENABLE(); // enable clock on USB peripheral +#ifdef USB_STM32F4 - HAL_Delay(1000); +#ifdef USB_HIGH_SPEED + __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); // enable HS USB peripheral + __HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE(); // also enable ULPI module clock +#else + __HAL_RCC_USB_OTG_FS_CLK_ENABLE(); // enable FS USB peripheral +#endif +#endif + + // HAL_Delay(1000); //__HAL_RCC_USB_OTG_FS_ULPI_CLK_ENABLE(); //__HAL_RCC_USB_OTG_FS_FORCE_RESET(); @@ -164,6 +213,23 @@ void usbdrv_periph_init() { SET_BIT(USBG->GRSTCTL, USB_OTG_GRSTCTL_CSRST); // reset USB core WAIT_FOR_BIT(USBG->GRSTCTL, USB_OTG_GRSTCTL_CSRST); +#else + +#if defined(USB_HIGH_SPEED) + CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_PHYSEL); // select the external HS PHY + CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_TSDPS); + CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_ULPIFSLS); + + CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_ULPIEVBUSD); + CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_ULPIEVBUSI); + // SET_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_PHYSEL); + + SET_BIT(USBG->GRSTCTL, USB_OTG_GRSTCTL_CSRST); // reset USB core + WAIT_FOR_BIT(USBG->GRSTCTL, USB_OTG_GRSTCTL_CSRST); + + usbdrv_ulpi_init(); // initialize PHY +#endif + #endif CLEAR_BIT(USBG->GCCFG, USB_OTG_GCCFG_PWRDWN); // power down the peripheral @@ -171,21 +237,32 @@ void usbdrv_periph_init() { CLEAR_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT); // mask all interrupts for now CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_HNPCAP | USB_OTG_GUSBCFG_SRPCAP); // disable HNP and SRP WRITE_FIELD(USBG->GUSBCFG, USB_OTG_GUSBCFG_TRDT, TRDT_VALUE); // set TRDT according to the RM - WRITE_FIELD(USBG->GUSBCFG, USB_OTG_GUSBCFG_TOCAL, TOCAL_VALUE); // set TOCAL - SET_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_FDMOD); // force Device mode + // WRITE_FIELD(USBG->GUSBCFG, USB_OTG_GUSBCFG_TOCAL, TOCAL_VALUE); // set TOCAL + CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_FHMOD); // clear Host mode forcing + SET_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_FDMOD); // force Device mode + + HAL_Delay(25); // wait for Device mode forcing propagation + WAIT_FOR_BIT(USBG->GINTSTS, 0b1); + + // SET_BIT(USBD->DCTL, USB_OTG_DCTL_SDIS); // soft disconnect peripheral (should be upper, but since it's controlled by a Device register, cannot be set before switching to device mode) #if defined(USB_STM32H7) CLEAR_BIT(USBG->GCCFG, USB_OTG_GCCFG_VBDEN); // turn on VBUSSENSE SET_BIT(USBG->GOTGCTL, USB_OTG_GOTGCTL_BVALOEN | USB_OTG_GOTGCTL_BVALOVAL); // force B-session #elif defined(USB_STM32F4) SET_BIT(USBG->GCCFG, USB_OTG_GCCFG_NOVBUSSENS); // turn off VBUSSENSE + CLEAR_BIT(USBG->GCCFG, USB_OTG_GCCFG_VBUSBSEN | USB_OTG_GCCFG_VBUSASEN); #endif - // HAL_Delay(50); // it takes time to forcing Device mode takes effect - SET_BIT(USBD->DCTL, USB_OTG_DCTL_SDIS); // soft disconnect peripheral (should be upper, but since it's controlled by a Device register, cannot be set before switching to device mode) +#ifdef USB_HIGH_SPEED + // WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_FULL_SPEED); + // WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_HIGH_SPEED_ULPI); + WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_FULL_SPEED_ULPI); +#else WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_FULL_SPEED); // there's no other possible option +#endif // allow specific interrupts uint32_t intmask = /*USB_OTG_GINTMSK_WUIM | // Wake up */ @@ -305,9 +382,9 @@ void usbdrv_fetch_endpoint_configuration(uint8_t config_index) { #define USB_RX_FIFO_SETUP_RESERVATION_DWORDS (10) #define USB_MIN_GROSS_TX_FIFO_SIZE (2 * USB_MIN_EP_FIFO_SIZE) -#if defined(USB_STM32F4) +#if defined(USB_STM32F4) && !defined(USB_HIGH_SPEED) #define USB_MIN_GROSS_RX_FIFO_SIZE (2 * USB_MIN_EP_FIFO_SIZE + USB_RX_FIFO_SETUP_RESERVATION_DWORDS * 4) -#elif defined(USB_STM32H7) +#elif defined(USB_STM32H7) || defined(USB_HIGH_SPEED) #define USB_MIN_GROSS_RX_FIFO_SIZE (256) #endif @@ -382,10 +459,10 @@ void usbdrv_initial_ep0_setup() { // addresses of specific DIEPTXF registers, addresses from the RM static uint32_t *USB_pDIEPTXF[4] = { - (uint32_t *)(USBG + 0x028), // DIEPTXF0 - (uint32_t *)(USBG + 0x104), // DIEPTXF1 - (uint32_t *)(USBG + 0x108), // DIEPTXF2 - (uint32_t *)(USBG + 0x10C), // DIEPTXF3 + (uint32_t *)(((uint32_t)USBG) + 0x028), // DIEPTXF0 + (uint32_t *)(((uint32_t)USBG) + 0x104), // DIEPTXF1 + (uint32_t *)(((uint32_t)USBG) + 0x108), // DIEPTXF2 + (uint32_t *)(((uint32_t)USBG) + 0x10C), // DIEPTXF3 // TODO: HS USB controller has more endpoints }; @@ -423,15 +500,16 @@ void usbdrv_configure_endpoint(uint8_t ep, uint8_t dir, const USBDRV_EpConfig *c } else { WRITE_FIELD(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPTYP, cfg->type); // program endpoint type WRITE_FIELD(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_MPSIZ, cfg->max_packet_size); // program maximum packet size - SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_USBAEP); // the endpoint is active in the current configuration + SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_USBAEP); // the endpoint is active in the current configuration } + // ---- common for all endpoints ---- // program FIFO corresponding FIFO number WRITE_FIELD(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_TXFNUM, ep); - // store Tx FIFO size (both fields are WORD units, NOT bytes, this RM is missing this information!) + // store Tx FIFO size (both fields are WORD units, NOT bytes, RM is missing this information!) uint32_t tx_fifo_config = ((cfg->fifo_size >> 2) << USB_OTG_DIEPTXF_INEPTXFD_Pos) | (cfg->fifo_address >> 2); // combine size in DWORDs and address *(USB_pDIEPTXF[ep]) = tx_fifo_config; // save @@ -601,7 +679,7 @@ uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len) { SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK); } - // turn interrupt generation on only, if this is NOT the last FIFO write considering the current transfer + // turn on interrupt generation only, if this is NOT the last FIFO write considering the current transfer if (len > writeSize) { USBD->DIEPEMPMSK |= ((uint32_t)(1 << ep)); } @@ -609,6 +687,8 @@ uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len) { // disable ALL USB interrupts to prevent access to specific registers (see errata) CLEAR_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT); + // WAIT_FOR_nBIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_TXFE); + // https://github.com/iliasam/STM32F4_USB_MICROPHONE/blob/master/Libraries/STM32_USB_OTG_Driver/src/usb_dcd_int.c#L655 // https://github.com/iliasam/STM32F4_USB_MICROPHONE/blob/master/Libraries/STM32_USB_OTG_Driver/src/usb_core.c#L168 @@ -888,7 +968,12 @@ bool usbdrv_get_endpoint_interrupt_flag(uint8_t ep, uint8_t dir) { #define PROCESS_EVENT(evt, data) usbdrv_process_event((evt), (data)) #endif -void OTG_FS_IRQHandler() { +#ifdef USB_HIGH_SPEED +void OTG_HS_IRQHandler() +#else +void OTG_FS_IRQHandler() +#endif +{ uint32_t ints = USBG->GINTSTS; @@ -949,4 +1034,4 @@ void OTG_FS_IRQHandler() { } return; -} \ No newline at end of file +} From c7b69000e73dc289a8ff77c660678cf05aa3f5bd Mon Sep 17 00:00:00 2001 From: Epagris Date: Tue, 25 Jun 2024 09:24:51 +0200 Subject: [PATCH 2/4] - OtherSpeedConfigution descriptor handling added - PWRDWN flag is kept cleared in HS mode - RX FIFO size increased to 1024 when operating in HS mode --- usb.c | 5 +++++ usb_driver.c | 20 ++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/usb.c b/usb.c index 46d5716..236576c 100644 --- a/usb.c +++ b/usb.c @@ -131,8 +131,13 @@ void usbcore_process_setup_pckt(const uint8_t *data, uint16_t size, uint8_t stag SET_TRANSMISSION_POINTER(&devDesc); break; case UD_Configuration: // CONFIGURATION DESCRIPTOR + case UD_OtherSpeedConfiguration: // OTHER SPEED CONFIGURATION DESCRIPTOR DETERMINE_TRANSFER_SIZE(confDescs[desc_index]->wTotalLength); SET_TRANSMISSION_POINTER(confDescs[desc_index]); + + if (desc_type == UD_OtherSpeedConfiguration) { // change bDescriptorType to Other_Speed_Configuration + confDescs[desc_index]->bDescriptorType = UD_OtherSpeedConfiguration; + } break; case UD_String: // STRING DESCRIPTOR DETERMINE_TRANSFER_SIZE(strDescs[desc_index]->bLength); diff --git a/usb_driver.c b/usb_driver.c index 9d1e962..0e50406 100644 --- a/usb_driver.c +++ b/usb_driver.c @@ -123,7 +123,7 @@ void usbdrv_init() { usbdrv_initial_ep0_setup(); usbdrv_power_and_connect(true); - NVIC_SetPriority(USB_IRQn, 0); + NVIC_SetPriority(USB_IRQn, 7); NVIC_EnableIRQ(USB_IRQn); } @@ -237,7 +237,7 @@ void usbdrv_periph_init() { CLEAR_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT); // mask all interrupts for now CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_HNPCAP | USB_OTG_GUSBCFG_SRPCAP); // disable HNP and SRP WRITE_FIELD(USBG->GUSBCFG, USB_OTG_GUSBCFG_TRDT, TRDT_VALUE); // set TRDT according to the RM - // WRITE_FIELD(USBG->GUSBCFG, USB_OTG_GUSBCFG_TOCAL, TOCAL_VALUE); // set TOCAL + //WRITE_FIELD(USBG->GUSBCFG, USB_OTG_GUSBCFG_TOCAL, TOCAL_VALUE); // set TOCAL CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_FHMOD); // clear Host mode forcing SET_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_FDMOD); // force Device mode @@ -258,8 +258,8 @@ void usbdrv_periph_init() { #ifdef USB_HIGH_SPEED // WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_FULL_SPEED); - // WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_HIGH_SPEED_ULPI); - WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_FULL_SPEED_ULPI); + WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_HIGH_SPEED_ULPI); + //WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_FULL_SPEED_ULPI); #else WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_FULL_SPEED); // there's no other possible option #endif @@ -301,10 +301,14 @@ void usbdrv_periph_init() { void usbdrv_power_and_connect(bool en) { if (en) { // ON CLEAR_BIT(USBD->DCTL, USB_OTG_DCTL_SDIS); + #ifndef USB_HIGH_SPEED SET_BIT(USBG->GCCFG, USB_OTG_GCCFG_PWRDWN); // actually, this is power UP + #endif } else { // OFF SET_BIT(USBD->DCTL, USB_OTG_DCTL_SDIS); + #ifndef USB_HIGH_SPEED CLEAR_BIT(USBG->GCCFG, USB_OTG_GCCFG_PWRDWN); + #endif } } @@ -382,9 +386,13 @@ void usbdrv_fetch_endpoint_configuration(uint8_t config_index) { #define USB_RX_FIFO_SETUP_RESERVATION_DWORDS (10) #define USB_MIN_GROSS_TX_FIFO_SIZE (2 * USB_MIN_EP_FIFO_SIZE) -#if defined(USB_STM32F4) && !defined(USB_HIGH_SPEED) +#if defined(USB_STM32F4) +#ifndef USB_HIGH_SPEED #define USB_MIN_GROSS_RX_FIFO_SIZE (2 * USB_MIN_EP_FIFO_SIZE + USB_RX_FIFO_SETUP_RESERVATION_DWORDS * 4) -#elif defined(USB_STM32H7) || defined(USB_HIGH_SPEED) +#else +#define USB_MIN_GROSS_RX_FIFO_SIZE (1024) +#endif +#elif defined(USB_STM32H7) #define USB_MIN_GROSS_RX_FIFO_SIZE (256) #endif From 25dc4a9aa86a37a5175f183a1da4db18369c8760 Mon Sep 17 00:00:00 2001 From: Epagris Date: Tue, 25 Jun 2024 10:36:50 +0200 Subject: [PATCH 3/4] - descriptor generator updated --- desc/Descriptor.py | 3 ++- desc/main.py | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/desc/Descriptor.py b/desc/Descriptor.py index 2e848ea..8bd488c 100644 --- a/desc/Descriptor.py +++ b/desc/Descriptor.py @@ -27,9 +27,10 @@ class USB_DescriptorSize(Enum): # base class for descriptor generator class Descriptor(StructGenerator.StructRecord): + QUALIFIERS = "const" def __init__(self, name, ctype, content, comment=None): super().__init__(name, ctype, content, comment) - self.qualifiers = "const" + self.qualifiers = Descriptor.QUALIFIERS self.typedef = ctype[8:] self.attribute = "packed" diff --git a/desc/main.py b/desc/main.py index 8830e79..8498b2a 100644 --- a/desc/main.py +++ b/desc/main.py @@ -10,10 +10,21 @@ from ConfigGenerator import ConfigGenerator # fetch USB settings usb_config_file_name = argv[1] +#usb_config_file_name = "/home/epagris/VCSDEV/usbt1/stws/USB-T1/Modules/flatUSB/desc/usb_config_cdc.json" with open(usb_config_file_name, 'r') as usb_config_file: usb_config_data = usb_config_file.read() usb_config = json.loads(usb_config_data) +# process "misc" +if "misc" in usb_config: + misc = usb_config["misc"] + + # mutable descriptors + if "mutable_descriptors" in misc: + if misc["mutable_descriptors"]: + desc.Descriptor.QUALIFIERS = "" + +# generate config cfggen = ConfigGenerator(usb_config) cfggen.generate() From 9a34b5e28688a4b7223c426969a78f16f8c1a8b1 Mon Sep 17 00:00:00 2001 From: Epagris Date: Thu, 11 Jul 2024 08:04:01 +0200 Subject: [PATCH 4/4] - the way TxFIFO empty interrupts are handled has been redesigned, and the ability to "wake up" the endpoint added --- class/cdc.c | 1 + usb.c | 14 ++++++++- usb.h | 5 ++-- usb_driver.c | 83 +++++++++++++++++++++++++++++++++++++++------------- usb_driver.h | 15 ++++++---- 5 files changed, 90 insertions(+), 28 deletions(-) diff --git a/class/cdc.c b/class/cdc.c index b4a8346..5e174af 100644 --- a/class/cdc.c +++ b/class/cdc.c @@ -125,6 +125,7 @@ int usb_cdc_process_and_return(USB_CallbackEvent *cbevt) { void usb_cdc_write(const uint8_t * data, uint32_t size) { if (cdcs.initialized) { bfifo_push_all(&fifo, data, size); + usbcore_wake_up_endpoint(cdcs.ep_assignments.data_ep, USB_IN); } } diff --git a/usb.c b/usb.c index 236576c..317322b 100644 --- a/usb.c +++ b/usb.c @@ -25,7 +25,14 @@ // --------------- -static uint8_t tx_assembly_buf[USB_MAX_FS_PCKT_SIZE_NON_ISOCHRONOUS] DWORD_ALIGN; // buffer for assembling packets +#ifndef USB_HIGH_SPEED +#define USB_RX_BUF_SIZE (USB_MAX_FS_PCKT_SIZE_NON_ISOCHRONOUS) +#else +#define USB_RX_BUF_SIZE (USB_MAX_HS_PCKT_SIZE_NON_ISOCHRONOUS) +#endif + + +static uint8_t tx_assembly_buf[USB_RX_BUF_SIZE] DWORD_ALIGN; // buffer for assembling packets // --------------- @@ -241,7 +248,12 @@ void usbcore_process_nonsetup_event(USBDRV_CallbackCompound *cbcpd) { } } +void usbcore_wake_up_endpoint(uint8_t ep, uint8_t dir) { + usbdrv_enable_endpoint_interrupt(ep, dir, true); +} + uint32_t usbcore_schedule_transmission(uint8_t ep, const uint8_t *data, uint16_t size) { + usbdrv_enable_endpoint_interrupt(ep, USB_IN, true); return usbdrv_arm_IN_endpoint(ep, data, size); } diff --git a/usb.h b/usb.h index 9a52c6b..ab439b1 100644 --- a/usb.h +++ b/usb.h @@ -3,8 +3,9 @@ #include "usb_callback_event.h" -void usbcore_init(); // initialize USB core +void usbcore_init(); // initialize USB core uint32_t usbcore_schedule_transmission(uint8_t ep, const uint8_t *data, uint16_t size); // write data to endpoint, return with number of bytes actually written -uint32_t usbcore_schedule_reception(uint8_t ep, uint16_t size); // expect data coming from the endpoint +uint32_t usbcore_schedule_reception(uint8_t ep, uint16_t size); // expect data coming from the endpoint +void usbcore_wake_up_endpoint(uint8_t ep, uint8_t dir); // wake up endpoint #endif /* CORE_USB_USB */ diff --git a/usb_driver.c b/usb_driver.c index 0e50406..c07e53e 100644 --- a/usb_driver.c +++ b/usb_driver.c @@ -8,6 +8,9 @@ #include "desc/usb_desc.h" +#include "embfmt/embformat.h" +#define SNPRINTF(str, n, fmt, ...) embfmt(str, n, fmt, __VA_ARGS__) + // --------------- #define MAX(a, b) (((a) > (b)) ? (a) : (b)) @@ -24,7 +27,13 @@ static USBDRV_GlobalState gs; // global USB state -static uint8_t rx_buf[USB_MAX_FS_PCKT_SIZE_NON_ISOCHRONOUS] DWORD_ALIGN; // receive buffer +#ifndef USB_HIGH_SPEED +#define USB_RX_BUF_SIZE (USB_MAX_FS_PCKT_SIZE_NON_ISOCHRONOUS) +#else +#define USB_RX_BUF_SIZE (USB_MAX_HS_PCKT_SIZE_NON_ISOCHRONOUS) +#endif + +static uint8_t rx_buf[USB_RX_BUF_SIZE] DWORD_ALIGN; // receive buffer #define USB_EVENT_QUEUE_LENGTH (16) @@ -115,7 +124,7 @@ void usbdrv_gpio_init() { // initialize USB subsystem void usbdrv_init() { - NVIC_DisableIRQ(USB_IRQn); + HAL_NVIC_DisableIRQ(USB_IRQn); usbdrv_init_global_state(); usbdrv_gpio_init(); @@ -123,8 +132,8 @@ void usbdrv_init() { usbdrv_initial_ep0_setup(); usbdrv_power_and_connect(true); - NVIC_SetPriority(USB_IRQn, 7); - NVIC_EnableIRQ(USB_IRQn); + HAL_NVIC_SetPriority(USB_IRQn, 8, 0); + HAL_NVIC_EnableIRQ(USB_IRQn); } void usbdrv_reset() { @@ -237,7 +246,7 @@ void usbdrv_periph_init() { CLEAR_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT); // mask all interrupts for now CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_HNPCAP | USB_OTG_GUSBCFG_SRPCAP); // disable HNP and SRP WRITE_FIELD(USBG->GUSBCFG, USB_OTG_GUSBCFG_TRDT, TRDT_VALUE); // set TRDT according to the RM - //WRITE_FIELD(USBG->GUSBCFG, USB_OTG_GUSBCFG_TOCAL, TOCAL_VALUE); // set TOCAL + // WRITE_FIELD(USBG->GUSBCFG, USB_OTG_GUSBCFG_TOCAL, TOCAL_VALUE); // set TOCAL CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_FHMOD); // clear Host mode forcing SET_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_FDMOD); // force Device mode @@ -258,8 +267,8 @@ void usbdrv_periph_init() { #ifdef USB_HIGH_SPEED // WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_FULL_SPEED); - WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_HIGH_SPEED_ULPI); - //WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_FULL_SPEED_ULPI); + // WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_HIGH_SPEED_ULPI); + WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_FULL_SPEED_ULPI); #else WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_FULL_SPEED); // there's no other possible option #endif @@ -301,14 +310,14 @@ void usbdrv_periph_init() { void usbdrv_power_and_connect(bool en) { if (en) { // ON CLEAR_BIT(USBD->DCTL, USB_OTG_DCTL_SDIS); - #ifndef USB_HIGH_SPEED +#ifndef USB_HIGH_SPEED SET_BIT(USBG->GCCFG, USB_OTG_GCCFG_PWRDWN); // actually, this is power UP - #endif - } else { // OFF +#endif + } else { // OFF SET_BIT(USBD->DCTL, USB_OTG_DCTL_SDIS); - #ifndef USB_HIGH_SPEED +#ifndef USB_HIGH_SPEED CLEAR_BIT(USBG->GCCFG, USB_OTG_GCCFG_PWRDWN); - #endif +#endif } } @@ -386,7 +395,7 @@ void usbdrv_fetch_endpoint_configuration(uint8_t config_index) { #define USB_RX_FIFO_SETUP_RESERVATION_DWORDS (10) #define USB_MIN_GROSS_TX_FIFO_SIZE (2 * USB_MIN_EP_FIFO_SIZE) -#if defined(USB_STM32F4) +#if defined(USB_STM32F4) #ifndef USB_HIGH_SPEED #define USB_MIN_GROSS_RX_FIFO_SIZE (2 * USB_MIN_EP_FIFO_SIZE + USB_RX_FIFO_SETUP_RESERVATION_DWORDS * 4) #else @@ -396,6 +405,9 @@ void usbdrv_fetch_endpoint_configuration(uint8_t config_index) { #define USB_MIN_GROSS_RX_FIFO_SIZE (256) #endif +#define USBDRV_ADDR_TABLE_STR_LEN (255) +static char usbdrv_addr_table[USBDRV_ADDR_TABLE_STR_LEN + 1]; + // build FIFO (compute addresses) void usbdrv_build_fifo() { // ---- OUT ---- @@ -430,19 +442,28 @@ void usbdrv_build_fifo() { next_fifo_addr += fifo_size; // advance next FIFO address usbdrv_set_rx_fifo_size(fifo_size); // set Rx FIFO size in hardware + uint32_t str_offset = SNPRINTF(usbdrv_addr_table, USBDRV_ADDR_TABLE_STR_LEN, "RX: 000-%03x (%u)\r\n", fifo_size - 1, fifo_size); + // ---- IN ---- for (uint8_t i = 0; i < USB_NUM_OF_ENDPOINTS; i++) { USBDRV_EpConfig *cfg = &gs.ep_IN[i]; if (cfg->is_configured) { - cfg->fifo_size = CEIL4(MAX(USB_MIN_GROSS_TX_FIFO_SIZE, 2 * cfg->max_packet_size)); // correct FIFO size if necessary - cfg->fifo_address = next_fifo_addr; // store FIFO address + cfg->fifo_size = CEIL4(MAX(USB_MIN_GROSS_TX_FIFO_SIZE, cfg->max_packet_size + 64)); // correct FIFO size if necessary + cfg->fifo_address = next_fifo_addr; // store FIFO address cfg->zlp_next = false; + + str_offset += SNPRINTF(usbdrv_addr_table + str_offset, USBDRV_ADDR_TABLE_STR_LEN - str_offset, "TX%u: %03x-%03x (%u)\r\n", i, next_fifo_addr, next_fifo_addr + cfg->fifo_size - 1, cfg->fifo_size); + // cfg->txp = false; // no transfer is in progress next_fifo_addr += cfg->fifo_size; // advance next address } } } +const char * usbdrv_get_fifo_addr_table() { + return usbdrv_addr_table; +} + // create an initial setup for EP0 in both directions void usbdrv_initial_ep0_setup() { // setup EP0 OUT and IN @@ -508,10 +529,9 @@ void usbdrv_configure_endpoint(uint8_t ep, uint8_t dir, const USBDRV_EpConfig *c } else { WRITE_FIELD(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPTYP, cfg->type); // program endpoint type WRITE_FIELD(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_MPSIZ, cfg->max_packet_size); // program maximum packet size - SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_USBAEP); // the endpoint is active in the current configuration + SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_USBAEP); // the endpoint is active in the current configuration } - // ---- common for all endpoints ---- // program FIFO corresponding FIFO number @@ -522,7 +542,7 @@ void usbdrv_configure_endpoint(uint8_t ep, uint8_t dir, const USBDRV_EpConfig *c *(USB_pDIEPTXF[ep]) = tx_fifo_config; // save // enable interrupt - SET_BIT(USBD->DAINTMSK, 1 << ep); + // SET_BIT(USBD->DAINTMSK, 1 << ep); // NAK processing if (cfg->responding_NAK) { @@ -685,6 +705,9 @@ uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len) { // enable endpoint and cancel responding NAK SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK); + + // enable endpoint interrupts + SET_BIT(USBD->DAINTMSK, 1 << ep); } // turn on interrupt generation only, if this is NOT the last FIFO write considering the current transfer @@ -753,6 +776,15 @@ void usbdrv_autoarm_OUT_endpoint(uint8_t ep) { gs.ep_OUT[ep].autoarm = true; } +void usbdrv_enable_endpoint_interrupt(uint8_t ep, uint8_t dir, bool en) { + uint32_t mask = 1 << (ep + ((dir == USB_OUT) ? USB_OTG_DAINTMSK_OEPM_Pos : 0)); + if (en) { + SET_BIT(USBD->DAINTMSK, mask); + } else { + CLEAR_BIT(USBD->DAINTMSK, mask); + } +} + // ---------------- void usbdrv_set_address(uint8_t addr) { @@ -858,7 +890,7 @@ void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data) { // SET_BIT(USBG->GINTMSK, USB_OTG_GINTMSK_RXFLVLM); // unmask interrupt } else { // not EP0 - if (evt_data.rx.pckt_status == USB_PCKT_STATUS_OUT_DATA_RECV) { // TODO maybe the + if (evt_data.rx.pckt_status == USB_PCKT_STATUS_OUT_DATA_RECV) { // TODO: "maybe the"???? USBDRV_CallbackCompound cbcpd; cbcpd.ep = evt_data.rx.ep_num; cbcpd.dir = USB_OUT; @@ -903,7 +935,8 @@ void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data) { for (uint8_t ep = 0; ep < USB_NUM_OF_ENDPOINTS; ep++) { cbcpd.ep = ep; - if (gs.ep_IN[ep].is_configured) { // if the endpoint is running + bool ep_on = USBD->DAINTMSK & (1 << ep); // decide if this endpoint is currently enable for transmission based on its endpoint mask + if (gs.ep_IN[ep].is_configured && ep_on) { // if the endpoint is running if (READ_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_TOC)) { // timeout done SET_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_TOC); USBMSG("TO\n"); @@ -931,14 +964,24 @@ void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data) { cbcpd.code = USB_CBC_IN_DONE; usbcore_process_nonsetup_event(&cbcpd); } + } else if (READ_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_ITTXFE)) { // IN endpoint IN token received with Tx FIFO empty interrupt SET_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_ITTXFE); + // MSG("E %u\n", ep); + // USBMSG("IN FIFOEMPTY [%d]\n", ep); // transfer finished // gs.ep_IN[ep].txp = false; + // if (!gs.ep_IN[ep].) { + + //} + + // disable endpoint interrupt + usbdrv_enable_endpoint_interrupt(ep, USB_IN, false); + cbcpd.code = USB_CBC_IN_FIFOEMPTY; usbcore_process_nonsetup_event(&cbcpd); } diff --git a/usb_driver.h b/usb_driver.h index 58db2e9..ca0a17e 100644 --- a/usb_driver.h +++ b/usb_driver.h @@ -7,9 +7,13 @@ // #define USBDBGMSG -#define USB_NUM_OF_ENDPOINTS (4) +#define USB_NUM_OF_ENDPOINTS (4) // FIXME: this is module-dependend +// non isochronous transfers #define USB_MAX_FS_PCKT_SIZE_NON_ISOCHRONOUS (64) +#define USB_MAX_HS_PCKT_SIZE_NON_ISOCHRONOUS (512) + +// isochronous transfers #define USB_MAX_FS_PCKT_SIZE_ISOCHRONOUS (1023) #define USB_MIN_EP_FIFO_SIZE (64) @@ -135,6 +139,7 @@ void usbdrv_preload_endpoint_config(uint8_t ep, uint8_t dir, const USBDRV_EpConf void usbdrv_clear_endpoint_config(); // clear endpoint config void usbdrv_apply_endpoint_config(); // apply preloaded endpoint configuration void usbdrv_build_fifo(); // build FIFO (compute addresses) +const char *usbdrv_get_fifo_addr_table(); // get FIFO address table void usbdrv_fetch_endpoint_configuration(uint8_t config_index); // fetch endpoint configuration from descriptor dump void usbdrv_configure_endpoint(uint8_t ep, uint8_t dir, const USBDRV_EpConfig *cfg); // configure USB endpoint @@ -151,10 +156,10 @@ void usbdrv_process_rx_fifo_top(USBDRV_EventData *evt_data); // see what's on to uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len); // write data to specific endpoint FIFO #define USBDRV_ARM_IN_ZLP(ep) usbdrv_arm_IN_endpoint((ep), NULL, 0) -uint32_t usbdrv_arm_OUT_endpoint(uint8_t ep, uint8_t size); // arm OUT endpoint, returned with the actual armed size (capped by the max packet size on that endpoint) -void usbdrv_autoarm_OUT_endpoint(uint8_t ep); // automatically re-arm OUT endpoint at the and of the current OUT transfer - -bool usbdrv_get_endpoint_interrupt_flag(uint8_t ep, uint8_t dir); // get endpoint interrupt flag +uint32_t usbdrv_arm_OUT_endpoint(uint8_t ep, uint8_t size); // arm OUT endpoint, returned with the actual armed size (capped by the max packet size on that endpoint) +void usbdrv_autoarm_OUT_endpoint(uint8_t ep); // automatically re-arm OUT endpoint at the and of the current OUT transfer +void usbdrv_enable_endpoint_interrupt(uint8_t ep, uint8_t dir, bool en); // enable/disable endpoint interrupt signaling +bool usbdrv_get_endpoint_interrupt_flag(uint8_t ep, uint8_t dir); // get endpoint interrupt flag void usbdrv_set_address(uint8_t addr); // set device address