diff --git a/boards/nrf52840-mdk/Kconfig b/boards/nrf52840-mdk/Kconfig index 38b88d9cd4..d22bc62ed5 100644 --- a/boards/nrf52840-mdk/Kconfig +++ b/boards/nrf52840-mdk/Kconfig @@ -16,6 +16,7 @@ config BOARD_NRF52840_MDK select HAS_PERIPH_SPI select HAS_PERIPH_UART select HAS_PERIPH_USBDEV + select HAS_TINYUSB_DEVICE select HAS_VDD_LC_FILTER_REG1 select HAVE_SAUL_GPIO diff --git a/boards/nrf52840-mdk/Makefile.features b/boards/nrf52840-mdk/Makefile.features index 2ed3d7f90c..c1d3a9266b 100644 --- a/boards/nrf52840-mdk/Makefile.features +++ b/boards/nrf52840-mdk/Makefile.features @@ -8,5 +8,6 @@ FEATURES_PROVIDED += periph_usbdev FEATURES_PROVIDED += vdd_lc_filter_reg1 # Various other features (if any) +FEATURES_PROVIDED += tinyusb_device include $(RIOTBOARD)/common/nrf52/Makefile.features diff --git a/boards/nrf52840dk/Kconfig b/boards/nrf52840dk/Kconfig index a62270c422..0cfacdd592 100644 --- a/boards/nrf52840dk/Kconfig +++ b/boards/nrf52840dk/Kconfig @@ -14,6 +14,7 @@ config BOARD_NRF52840DK select CPU_MODEL_NRF52840XXAA select HAS_PERIPH_PWM select HAS_PERIPH_USBDEV + select HAS_TINYUSB_DEVICE select HAS_VDD_LC_FILTER_REG0 select HAVE_MTD_SPI_NOR diff --git a/boards/nrf52840dk/Makefile.features b/boards/nrf52840dk/Makefile.features index 04c16f528b..0827f58b3c 100644 --- a/boards/nrf52840dk/Makefile.features +++ b/boards/nrf52840dk/Makefile.features @@ -5,4 +5,5 @@ include $(RIOTBOARD)/common/nrf52xxxdk/Makefile.features # Various other features (if any) FEATURES_PROVIDED += periph_pwm FEATURES_PROVIDED += periph_usbdev +FEATURES_PROVIDED += tinyusb_device FEATURES_PROVIDED += vdd_lc_filter_reg0 diff --git a/boards/reel/Kconfig b/boards/reel/Kconfig index 7b3717a93e..ca7b303396 100644 --- a/boards/reel/Kconfig +++ b/boards/reel/Kconfig @@ -16,6 +16,7 @@ config BOARD_REEL select HAS_PERIPH_SPI select HAS_PERIPH_UART select HAS_PERIPH_USBDEV + select HAS_TINYUSB_DEVICE select HAS_VDD_LC_FILTER_REG1 select HAVE_MMA8X5X diff --git a/boards/reel/Makefile.features b/boards/reel/Makefile.features index 2ed3d7f90c..c1d3a9266b 100644 --- a/boards/reel/Makefile.features +++ b/boards/reel/Makefile.features @@ -8,5 +8,6 @@ FEATURES_PROVIDED += periph_usbdev FEATURES_PROVIDED += vdd_lc_filter_reg1 # Various other features (if any) +FEATURES_PROVIDED += tinyusb_device include $(RIOTBOARD)/common/nrf52/Makefile.features diff --git a/boards/waveshare-nrf52840-eval-kit/Kconfig b/boards/waveshare-nrf52840-eval-kit/Kconfig index ae476a22fa..ca9071bf6d 100644 --- a/boards/waveshare-nrf52840-eval-kit/Kconfig +++ b/boards/waveshare-nrf52840-eval-kit/Kconfig @@ -19,6 +19,7 @@ config BOARD_WAVESHARE_NRF52840_EVAL_KIT select HAS_PERIPH_SPI select HAS_PERIPH_UART select HAS_PERIPH_USBDEV + select HAS_TINYUSB_DEVICE select HAVE_SAUL_GPIO select HAVE_SDCARD_SPI diff --git a/boards/waveshare-nrf52840-eval-kit/Makefile.features b/boards/waveshare-nrf52840-eval-kit/Makefile.features index 7b255847ba..d90d92438f 100644 --- a/boards/waveshare-nrf52840-eval-kit/Makefile.features +++ b/boards/waveshare-nrf52840-eval-kit/Makefile.features @@ -12,3 +12,4 @@ FEATURES_PROVIDED += periph_usbdev # Other features FEATURES_PROVIDED += arduino FEATURES_PROVIDED += arduino_pwm +FEATURES_PROVIDED += tinyusb_device diff --git a/pkg/tinyusb/Kconfig b/pkg/tinyusb/Kconfig index 5d1309c6c6..c1224f5b59 100644 --- a/pkg/tinyusb/Kconfig +++ b/pkg/tinyusb/Kconfig @@ -38,6 +38,8 @@ menuconfig PACKAGE_TINYUSB select MODULE_TINYUSB_PORTABLE_MICROCHIP if CPU_FAM_SAMD21 || CPU_FAM_SAMR21 \ || CPU_COMMON_SAMD5X || CPU_FAM_SAML21 || CPU_FAM_SAMR34 \ || CPU_FAM_SAMR30 + select MODULE_TINYUSB_PORTABLE_NRF5X if CPU_FAM_NRF52 + select PACKAGE_NRFX if CPU_FAM_NRF52 select MODULE_ZTIMER_MSEC help tinyUSB is an open-source cross-platform USB Host/Device stack for @@ -101,6 +103,11 @@ config MODULE_TINYUSB_PORTABLE_MICROCHIP help tinyUSB Microchip SAM0 driver is used +config MODULE_TINYUSB_PORTABLE_NRF5X + bool + help + tinyUSB nRFx device driver is used + menu "Device Classes" config MODULE_TINYUSB_CLASS_AUDIO bool "Audio Class 2.0 (UAC2)" diff --git a/pkg/tinyusb/Makefile b/pkg/tinyusb/Makefile index c72a1bdf55..f4947cafd7 100644 --- a/pkg/tinyusb/Makefile +++ b/pkg/tinyusb/Makefile @@ -74,6 +74,9 @@ tinyusb_portable_espressif: tinyusb_portable_microchip: $(QQ)"$(MAKE)" -C $(PSRC)/portable/microchip/samd -f $(RIOTBASE)/Makefile.base MODULE=$@ +tinyusb_portable_nrf5x: + $(QQ)"$(MAKE)" -C $(PSRC)/portable/nordic/nrf5x -f $(RIOTPKG)/$(PKG_NAME)/Makefile.nrf52 + tinyusb_portable_stm32_fsdev: $(QQ)"$(MAKE)" -C $(PSRC)/portable/st/stm32_fsdev -f $(RIOTBASE)/Makefile.base MODULE=$@ diff --git a/pkg/tinyusb/Makefile.dep b/pkg/tinyusb/Makefile.dep index 8e1c725bec..80c81e5aa9 100644 --- a/pkg/tinyusb/Makefile.dep +++ b/pkg/tinyusb/Makefile.dep @@ -54,6 +54,9 @@ endif # tinyUSB hardware driver selection ifneq (,$(filter esp32s2 esp32s3,$(CPU_FAM))) USEMODULE += tinyusb_portable_espressif +else ifeq (nrf52,$(CPU)) + USEPKG += nrfx + USEMODULE += tinyusb_portable_nrf5x else ifneq (,$(filter saml21 samd5x samd21,$(CPU))) USEMODULE += tinyusb_portable_microchip else ifeq (stm32,$(CPU)) diff --git a/pkg/tinyusb/Makefile.include b/pkg/tinyusb/Makefile.include index a76decaf83..4e7782348a 100644 --- a/pkg/tinyusb/Makefile.include +++ b/pkg/tinyusb/Makefile.include @@ -10,6 +10,13 @@ ifeq (esp32s2,$(CPU_FAM)) CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32S2 else ifeq (esp32s3,$(CPU_FAM)) CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32S3 +else ifeq (nrf52,$(CPU)) + CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_NRF5X + CFLAGS += -Wno-cast-align + CFLAGS += -Wno-unused-parameter + INCLUDES += -I$(PKGDIRBASE)/nrfx/hal + INCLUDES += -I$(PKGDIRBASE)/nrfx/drivers/include + INCLUDES += -I$(PKGDIRBASE)/nrfx/drivers/src else ifeq (stm32,$(CPU)) CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_STM32$(call uppercase_and_underscore,$(CPU_FAM)) CFLAGS += -Dasm=__asm diff --git a/pkg/tinyusb/Makefile.nrf52 b/pkg/tinyusb/Makefile.nrf52 new file mode 100644 index 0000000000..e34774e1f6 --- /dev/null +++ b/pkg/tinyusb/Makefile.nrf52 @@ -0,0 +1,5 @@ +MODULE = tinyusb_portable_nrf5x + +INCLUDES := -I$(RIOTBASE)/pkg/tinyusb/hw/include/nrf52 $(INCLUDES) + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/tinyusb/hw/hw_nrf52.c b/pkg/tinyusb/hw/hw_nrf52.c new file mode 100644 index 0000000000..2aa1ac5416 --- /dev/null +++ b/pkg/tinyusb/hw/hw_nrf52.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2022 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup pkg_tinyusb + * @brief + * @{ + * + * @brief tinyUSB hardware driver for nRF52 MCUs + * @author Gunar Schorcht + */ + +#include + +#include "periph_conf.h" +#include "periph/gpio.h" +#include "periph/pm.h" + +#include "tusb.h" +#include "device/usbd.h" +#include "host/usbh.h" + +/* + * Definition of events as used by the tinyusb/portable/nordic/nrf5x/dcd_nrf5x.c + * https://github.com/hathach/tinyusb/blob/0.14.0/src/portable/nordic/nrf5x/dcd_nrf5x.c#L954 + */ +#define USB_EVT_DETECTED 0 +#define USB_EVT_REMOVED 1 +#define USB_EVT_READY 2 + +int tinyusb_hw_init(void) +{ + if (IS_USED(MODULE_TINYUSB_DEVICE)) { + NVIC_SetPriority(USBD_IRQn, 2); + } + + extern void tusb_hal_nrf_power_event(uint32_t event); + + if ( NRF_POWER->USBREGSTATUS & POWER_USBREGSTATUS_VBUSDETECT_Msk ) { + tusb_hal_nrf_power_event(USB_EVT_DETECTED); + } + + /* it requires some time to activate the clock */ + ztimer_sleep(ZTIMER_MSEC, 1); + + if ( NRF_POWER->USBREGSTATUS & POWER_USBREGSTATUS_OUTPUTRDY_Msk ) { + tusb_hal_nrf_power_event(USB_EVT_READY); + } + + return 0; +} + +void isr_usbd(void) +{ + /* call device interrupt handler with the first device */ + if (IS_USED(MODULE_TINYUSB_DEVICE)) { + tud_int_handler(0); + } + + /* call host interrupt handler with the first device */ + if (IS_USED(MODULE_TINYUSB_HOST)) { + tuh_int_handler(0); + } + + cortexm_isr_end(); +} diff --git a/pkg/tinyusb/hw/include/nrf52/nrf_clock.h b/pkg/tinyusb/hw/include/nrf52/nrf_clock.h new file mode 100644 index 0000000000..4ec451ec27 --- /dev/null +++ b/pkg/tinyusb/hw/include/nrf52/nrf_clock.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2022 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup pkg_tinyusb + * @brief + * @{ + * + * @brief nRF52 specific clock definitions as required by tinyUSB + * + * RIOT does not use the clock module from `pkg/nrfx/drivers`. Therefore + * the part of the clock module interface needed by tinyUSB in + * `tinyusb/src/portable/nordic/dcd_nrf5x.c` has to be defined explicitly. + * + * @author Gunar Schorcht + */ + +#ifndef NRF52_NRF_CLOCK_H +#define NRF52_NRF_CLOCK_H + +#include + +#include "nrf.h" +#include_next "nrf_clock.h" + +#if !DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif + +#define NRF_CLOCK_HFCLK_HIGH_ACCURACY (1UL) +#define NRF_CLOCK_EVENT_HFCLKSTARTED offsetof(NRF_CLOCK_Type, EVENTS_HFCLKSTARTED) + +typedef enum { + NRF_CLOCK_TASK_HFCLKSTART, + NRF_CLOCK_TASK_HFCLKSTOP, +} nrf_clock_task_t; + +/** + * @brief Status HF clock acitvation/deactivation in `dcd_nrf52.c` + * + * The `clock_hfxo_request` and `clock_hfxo_release` functions are used in + * RIOT to enable/disable the HF clock if necessary. Since `hfclk_enable` + * in `tinyusb/src/portable/nordic/dcd_nrf5x.c` activates the RF clock only + * if it is not already running, the status of the RF clock cannot be + * determined via registers. It therefore needs its own static variable + * that holds the current state of activation/deactivation by the function + * `nrf_clock_task_trigger`. + */ +static bool _nrf_clock_hf_running = false; + +/** + * @brief Check whether HF clock is running + */ +static inline bool nrf_clock_hf_is_running(NRF_CLOCK_Type const *reg, + uint32_t clk_src) +{ + + return _nrf_clock_hf_running; +} + +/** + * @brief Clear a specific event + * + * This function is not required in RIOT, it is therefore defined as dummy + * function. + */ +static inline bool nrf_clock_event_clear(NRF_CLOCK_Type *reg, uint32_t event) +{ + (void)reg; + (void)event; + return true; +} + +/** + * @brief Function used in tinyUSB to start and stop the HF clock + * + * This function is mapped to `clock_hfxo_request`/`clock_hfxo_release` in RIOT. + */ +static inline void nrf_clock_task_trigger(NRF_CLOCK_Type *reg, + nrf_clock_task_t task) +{ + switch (task) { + case NRF_CLOCK_TASK_HFCLKSTART: + clock_hfxo_request(); + _nrf_clock_hf_running = true; + break; + case NRF_CLOCK_TASK_HFCLKSTOP: + clock_hfxo_release(); + _nrf_clock_hf_running = false; + break; + default: + break; + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* !DOXYGEN */ +#endif /* NRF52_NRF_CLOCK_H */ +/** @} */