diff --git a/boards/stm32f746g-disco/Kconfig b/boards/stm32f746g-disco/Kconfig index 2331ef2f0a..d0f3356462 100644 --- a/boards/stm32f746g-disco/Kconfig +++ b/boards/stm32f746g-disco/Kconfig @@ -24,6 +24,7 @@ config BOARD_STM32F746G_DISCO select HAS_PERIPH_UART select HAS_PERIPH_USBDEV select HAS_PERIPH_USBDEV_HS_ULPI + select HAS_TINYUSB_DEVICE # Clock configuration select BOARD_HAS_HSE diff --git a/boards/stm32f746g-disco/features-shared.mk b/boards/stm32f746g-disco/features-shared.mk index 2cb5fa6403..2e2d5ecb41 100644 --- a/boards/stm32f746g-disco/features-shared.mk +++ b/boards/stm32f746g-disco/features-shared.mk @@ -10,6 +10,7 @@ FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += periph_uart FEATURES_PROVIDED += periph_usbdev FEATURES_PROVIDED += periph_usbdev_hs_ulpi +FEATURES_PROVIDED += tinyusb_device # stm32f746g-disco provides a custom default Kconfig clock configuration KCONFIG_BOARD_CONFIG += $(RIOTBOARD)/stm32f746g-disco/clock.config diff --git a/boards/stm32f7508-dk/Kconfig b/boards/stm32f7508-dk/Kconfig index 1fcd054153..e37295848b 100644 --- a/boards/stm32f7508-dk/Kconfig +++ b/boards/stm32f7508-dk/Kconfig @@ -24,6 +24,7 @@ config BOARD_STM32F7508_DK select HAS_PERIPH_UART select HAS_PERIPH_USBDEV select HAS_PERIPH_USBDEV_HS_ULPI + select HAS_TINYUSB_DEVICE # Clock configuration select BOARD_HAS_HSE diff --git a/cpu/stm32/include/tinyusb_hw_defaults.h b/cpu/stm32/include/tinyusb_hw_defaults.h index b669be43ab..02b20095e8 100644 --- a/cpu/stm32/include/tinyusb_hw_defaults.h +++ b/cpu/stm32/include/tinyusb_hw_defaults.h @@ -55,6 +55,9 @@ extern "C" { * - In all other cases, both the device and the host stack use port 0. * This also applies if only the USB FS controller is used. * + * @warning + * - tinyUSB does not support host mode for STM32 MCUs yet. + * - tinyUSB does not support to use multiple ports with device stack * @{ */ #if defined(DWC2_USB_OTG_HS_ENABLED) && defined(DWC2_USB_OTG_FS_ENABLED) @@ -67,6 +70,9 @@ extern "C" { #define TINYUSB_TUH_RHPORT 1 #endif +#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED) +#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED) + #elif defined(DWC2_USB_OTG_HS_ENABLED) #ifndef TINYUSB_TUD_RHPORT @@ -77,6 +83,13 @@ extern "C" { #define TINYUSB_TUH_RHPORT 1 #endif +/* + * Since tinyUSB does not support host mode for STM32 MCUs yet, only + * OPT_MODE_DEVICE is enabled for the port. Once tinyUSB supports the host mode, + * OPT_MODE_HOST could be added to CFG_TUSB_RHPORT1_MODE + */ +#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED) + #else #ifndef TINYUSB_TUD_RHPORT @@ -87,6 +100,13 @@ extern "C" { #define TINYUSB_TUH_RHPORT 0 #endif +/* + * Since tinyUSB does not support host mode for STM32 MCUs yet, only + * OPT_MODE_DEVICE is enabled for the port. Once tinyUSB supports the host mode, + * OPT_MODE_HOST could be added to CFG_TUSB_RHPORT0_MODE. + */ +#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED) + #endif /** @} */ diff --git a/pkg/tinyusb/contrib/include/tinyusb_config.h b/pkg/tinyusb/contrib/include/tinyusb_config.h index 55ec032e98..b135436460 100644 --- a/pkg/tinyusb/contrib/include/tinyusb_config.h +++ b/pkg/tinyusb/contrib/include/tinyusb_config.h @@ -80,10 +80,6 @@ */ #define CFG_TUD_ENABLED MODULE_TINYUSB_DEVICE -#ifndef CFG_TUD_MAX_SPEED -#define CFG_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED -#endif - #ifndef CFG_TUD_ENDPOINT0_SIZE #define CFG_TUD_ENDPOINT0_SIZE 64 #endif diff --git a/pkg/tinyusb/hw/hw_stm32.c b/pkg/tinyusb/hw/hw_stm32.c index e8e9e91ed9..b4dc61c035 100644 --- a/pkg/tinyusb/hw/hw_stm32.c +++ b/pkg/tinyusb/hw/hw_stm32.c @@ -32,50 +32,175 @@ static int tinyusb_hw_init_dev(const dwc2_usb_otg_fshs_config_t *conf) pm_block(STM32_PM_STOP); pm_block(STM32_PM_STANDBY); +#if defined(PWR_CR2_USV) /* on L4 */ + /* Validate USB Supply */ + PWR->CR2 |= PWR_CR2_USV; +#endif /* PWR_CR2_USV */ + /* Enable the clock to the peripheral */ periph_clk_en(conf->ahb, conf->rcc_mask); +#ifndef MODULE_PERIPH_USBDEV_HS_ULPI /* Enables clock on the GPIO bus */ gpio_init(conf->dp, GPIO_IN); gpio_init(conf->dm, GPIO_IN); /* Configure AF for the pins */ gpio_init_af(conf->dp, conf->af); gpio_init_af(conf->dm, conf->af); +#endif /* MODULE_PERIPH_USBDEV_HS_ULPI */ -#if 0 /* TODO we don't use USB ID pin for now */ - gpio_init(conf->id, GPIO_IN); -#endif - -#ifdef USB_OTG_GCCFG_NOVBUSSENS -#if 0 /* TODO V_USB sensing pin */ - gpio_init(conf->vbus, GPIO_OD_PU); - gpio_init_af(conf->vbus, conf->af); - - USB_OTG_GlobalTypeDef *global_regs = - (USB_OTG_GlobalTypeDef *)(conf->periph + USB_OTG_GLOBAL_BASE); - - global_regs->GCCFG &= ~USB_OTG_GCCFG_NOVBUSSENS; - global_regs->GCCFG |= USB_OTG_GCCFG_VBUSBSEN; -#else - /* Enable no Vbus sensing and enable `Power Down Disable` */ USB_OTG_GlobalTypeDef *global_regs = (USB_OTG_GlobalTypeDef *)(conf->periph + USB_OTG_GLOBAL_BASE); +#ifdef USB_OTG_GCCFG_NOVBUSSENS /* Enable no Vbus Detect enable and enable `Power Down Disable` */ - global_regs->GCCFG |= USB_OTG_GCCFG_NOVBUSSENS | USB_OTG_GCCFG_PWRDWN; + global_regs->GCCFG |= USB_OTG_GCCFG_NOVBUSSENS; #endif -#endif /* USB_OTG_GCCFG_NOVBUSSENS */ #ifdef DWC2_USB_OTG_HS_ENABLED if (conf->type == DWC2_USB_OTG_HS) { - /* Disable the ULPI clock in low power mode, this is essential for the - * peripheral when using the built-in phy */ - periph_lpclk_dis(conf->ahb, RCC_AHB1LPENR_OTGHSULPILPEN); - /* Only the built-in phy supported for now */ - assert(conf->phy == DWC2_USB_OTG_PHY_BUILTIN); - global_regs->GUSBCFG |= USB_OTG_GUSBCFG_PHYSEL; - } + if (conf->phy == DWC2_USB_OTG_PHY_BUILTIN) { + /* set `Power Down Disable` to activate the on-chip FS transceiver */ + global_regs->GCCFG |= USB_OTG_GCCFG_PWRDWN; + /* Disable the ULPI clock in low power mode, this is essential for the + * peripheral when using the built-in PHY */ + periph_lpclk_dis(conf->ahb, RCC_AHB1LPENR_OTGHSULPILPEN); + /* select on-chip builtin PHY */ + global_regs->GUSBCFG |= USB_OTG_GUSBCFG_PHYSEL; + } +#ifdef MODULE_PERIPH_USBDEV_HS_ULPI + else if (conf->phy == DWC2_USB_OTG_PHY_ULPI) { + /* initialize ULPI interface */ + gpio_init(conf->ulpi_clk, GPIO_IN); + gpio_init(conf->ulpi_d0, GPIO_IN); + gpio_init(conf->ulpi_d1, GPIO_IN); + gpio_init(conf->ulpi_d2, GPIO_IN); + gpio_init(conf->ulpi_d3, GPIO_IN); + gpio_init(conf->ulpi_d4, GPIO_IN); + gpio_init(conf->ulpi_d5, GPIO_IN); + gpio_init(conf->ulpi_d6, GPIO_IN); + gpio_init(conf->ulpi_d7, GPIO_IN); + gpio_init(conf->ulpi_stp, GPIO_IN); + gpio_init(conf->ulpi_dir, GPIO_IN); + gpio_init(conf->ulpi_nxt, GPIO_IN); + gpio_init_af(conf->ulpi_clk, conf->ulpi_af); + gpio_init_af(conf->ulpi_d0, conf->ulpi_af); + gpio_init_af(conf->ulpi_d1, conf->ulpi_af); + gpio_init_af(conf->ulpi_d2, conf->ulpi_af); + gpio_init_af(conf->ulpi_d3, conf->ulpi_af); + gpio_init_af(conf->ulpi_d4, conf->ulpi_af); + gpio_init_af(conf->ulpi_d5, conf->ulpi_af); + gpio_init_af(conf->ulpi_d6, conf->ulpi_af); + gpio_init_af(conf->ulpi_d7, conf->ulpi_af); + gpio_init_af(conf->ulpi_stp, conf->ulpi_af); + gpio_init_af(conf->ulpi_dir, conf->ulpi_af); + gpio_init_af(conf->ulpi_nxt, conf->ulpi_af); + + /* enable ULPI clock */ + periph_clk_en(conf->ahb, RCC_AHB1ENR_OTGHSULPIEN); + +#ifdef USB_OTG_GUSBCFG_ULPI_UTMI_SEL + /* select ULPI PHY */ + global_regs->GUSBCFG |= USB_OTG_GUSBCFG_ULPI_UTMI_SEL; #endif +#ifdef USB_OTG_GUSBCFG_PHYIF + /* use the 8-bit interface */ + global_regs->GUSBCFG &= ~USB_OTG_GUSBCFG_PHYIF; +#endif /* USB_OTG_GUSBCFG_PHYIF */ +#ifdef USB_OTG_GUSBCFG_DDRSEL + /* use single data rate */ + global_regs->GUSBCFG &= ~USB_OTG_GUSBCFG_DDRSEL; +#endif /* USB_OTG_GUSBCFG_DDRSEL */ + + /* disable the on-chip FS transceiver */ + global_regs->GUSBCFG &= ~USB_OTG_GUSBCFG_PHYSEL; + + /* use internal V_BUS valid indicator and internal charge pump */ + global_regs->GUSBCFG &= ~(USB_OTG_GUSBCFG_ULPIEVBUSD | + USB_OTG_GUSBCFG_ULPIEVBUSI); + /* disable ULPI FS/LS serial interface */ + global_regs->GUSBCFG &= ~USB_OTG_GUSBCFG_ULPIFSLS; + } + +#elif defined(MODULE_PERIPH_USBDEV_HS_UTMI) + else if (conf->phy == DWC2_USB_OTG_PHY_UTMI) { + /* enable ULPI clock */ + periph_clk_en(conf->ahb, RCC_AHB1ENR_OTGHSULPIEN); + /* enable UTMI HS PHY Controller clock */ + periph_clk_en(APB2, RCC_APB2ENR_OTGPHYCEN); + +#ifdef USB_OTG_GUSBCFG_ULPI_UTMI_SEL + /* select UTMI+ PHY */ + global_regs->GUSBCFG &= ~USB_OTG_GUSBCFG_ULPI_UTMI_SEL; +#endif /* USB_OTG_GUSBCFG_ULPI_UTMI_SEL */ +#ifdef USB_OTG_GUSBCFG_PHYIF + /* use the 8-bit interface and single data rate */ + global_regs->GUSBCFG &= ~USB_OTG_GUSBCFG_PHYIF; +#endif /* USB_OTG_GUSBCFG_PHYIF */ + + /* disable the on-chip FS transceiver */ + global_regs->GUSBCFG &= ~USB_OTG_GUSBCFG_PHYSEL; + + /* configure the USB HS PHY Controller (USB_HS_PHYC), + * USB_HS_PHYC and GCCFG are STM32 specific */ +#ifdef USB_HS_PHYC + /* enable USB HS PHY Controller */ + global_regs->GCCFG |= USB_OTG_GCCFG_PHYHSEN; + + /* determine the PLL input clock of the USB HS PHY from HSE clock */ + switch (CLOCK_HSE) { + case 12000000: + USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL1_PLLSEL_12MHZ; + break; + case 12500000: + USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL1_PLLSEL_12_5MHZ; + break; + case 16000000: + USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL1_PLLSEL_16MHZ; + break; + case 24000000: + USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL1_PLLSEL_24MHZ; + break; + case 25000000: + USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL1_PLLSEL_25MHZ; + break; + default: + assert(0); + } + + /* configure the tuning interface of the USB HS PHY */ + USB_HS_PHYC->USB_HS_PHYC_TUNE |= conf->phy_tune; + + /* check whether the LDO regulator is used by on the chip */ + if (USB_HS_PHYC->USB_HS_PHYC_LDO & USB_HS_PHYC_LDO_USED) { + /* enable the LDO */ + USB_HS_PHYC->USB_HS_PHYC_LDO |= USB_HS_PHYC_LDO_ENABLE; + /* wait until the LDO is ready */ + while (!(USB_HS_PHYC->USB_HS_PHYC_LDO & USB_HS_PHYC_LDO_STATUS)) {} + } + + /* enable the PLL of the USB HS PHY */ + USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL_PLLEN; +#endif /* USB_HS_PHYC */ + } + +#else /* MODULE_PERIPH_USBDEV_HS_ULPI */ + else { + /* only on-chip PHY support enabled */ + assert(conf->phy == DWC2_USB_OTG_PHY_BUILTIN); + } +#endif /* MODULE_PERIPH_USBDEV_HS_ULPI */ + } +#endif /* DWC2_USB_OTG_HS_ENABLED */ + + if (conf->phy == DWC2_USB_OTG_PHY_BUILTIN) { + /* set `Power Down Disable` to activate the on-chip FS transceiver */ + global_regs->GCCFG |= USB_OTG_GCCFG_PWRDWN; + } + else { + /* clear `Power Down Disable` to deactivate the on-chip FS transceiver */ + global_regs->GCCFG &= ~USB_OTG_GCCFG_PWRDWN; + } return 0; }