From e0c2372eebc7400676cfbc30838f2a84c9bcbca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Thu, 15 May 2025 08:34:09 +0200 Subject: [PATCH] samples: usb: uac2: Implement feedback on nRF54H20 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add configuration and feedback implementation necessary to run UAC2 samples on nRF54H20. Limit nRF54H20 to Full-Speed only operation because the samples currently don't have necessary logic to support High-Speed. Signed-off-by: Tomasz Moń --- .../usb/uac2_explicit_feedback/CMakeLists.txt | 4 +- .../subsys/usb/uac2_explicit_feedback/Kconfig | 2 + .../boards/nrf54h20dk_nrf54h20_cpuapp.conf | 8 +++ .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 72 +++++++++++++++++++ .../usb/uac2_explicit_feedback/sample.yaml | 4 +- .../src/{feedback_nrf53.c => feedback_nrf.c} | 59 ++++++++++++--- .../usb/uac2_implicit_feedback/CMakeLists.txt | 4 +- .../boards/nrf54h20dk_nrf54h20_cpuapp.conf | 7 ++ .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 67 +++++++++++++++++ .../usb/uac2_implicit_feedback/sample.yaml | 4 +- .../src/{feedback_nrf53.c => feedback_nrf.c} | 43 +++++++++-- 11 files changed, 253 insertions(+), 21 deletions(-) create mode 100644 samples/subsys/usb/uac2_explicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf create mode 100644 samples/subsys/usb/uac2_explicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay rename samples/subsys/usb/uac2_explicit_feedback/src/{feedback_nrf53.c => feedback_nrf.c} (89%) create mode 100644 samples/subsys/usb/uac2_implicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf create mode 100644 samples/subsys/usb/uac2_implicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay rename samples/subsys/usb/uac2_implicit_feedback/src/{feedback_nrf53.c => feedback_nrf.c} (85%) diff --git a/samples/subsys/usb/uac2_explicit_feedback/CMakeLists.txt b/samples/subsys/usb/uac2_explicit_feedback/CMakeLists.txt index 26ce264c421..56bba10717c 100644 --- a/samples/subsys/usb/uac2_explicit_feedback/CMakeLists.txt +++ b/samples/subsys/usb/uac2_explicit_feedback/CMakeLists.txt @@ -7,8 +7,8 @@ project(usb_audio_async_i2s) include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake) target_sources(app PRIVATE src/main.c) -if (CONFIG_SOC_COMPATIBLE_NRF5340_CPUAPP) - target_sources(app PRIVATE src/feedback_nrf53.c) +if (CONFIG_SOC_COMPATIBLE_NRF5340_CPUAPP OR CONFIG_SOC_SERIES_NRF54HX) + target_sources(app PRIVATE src/feedback_nrf.c) else() target_sources(app PRIVATE src/feedback_dummy.c) endif() diff --git a/samples/subsys/usb/uac2_explicit_feedback/Kconfig b/samples/subsys/usb/uac2_explicit_feedback/Kconfig index bee6118a00d..76373b61469 100644 --- a/samples/subsys/usb/uac2_explicit_feedback/Kconfig +++ b/samples/subsys/usb/uac2_explicit_feedback/Kconfig @@ -9,6 +9,8 @@ config APP_USE_I2S_LRCLK_EDGES_COUNTER Use this to use I2S LRCLK edge counting for calculating feedback. On nRF53 this option requires externally connecting I2S LRCLK back to separate GPIOTE input pin (P1.09). + On nRF54 this option requires externally connecting TDM FSYNC back to + separate GPIOTE input pin (P0.08). endmenu # Source common USB sample options used to initialize new experimental USB diff --git a/samples/subsys/usb/uac2_explicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf new file mode 100644 index 00000000000..0e35fa1f491 --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -0,0 +1,8 @@ +# Enable timer for asynchronous feedback +CONFIG_NRFX_GPPI=y +CONFIG_NRFX_TIMER131=y +CONFIG_NRFX_GPIOTE130=y + +# Sample is Full-Speed only, prevent High-Speed enumeration +CONFIG_UDC_DRIVER_HIGH_SPEED_SUPPORT_ENABLED=n +CONFIG_USBD_MAX_SPEED_FULL=y diff --git a/samples/subsys/usb/uac2_explicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..0e6b18cbae9 --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "../app.overlay" + +&pinctrl { + tdm130_default_alt: tdm130_default_alt { + group1 { + psels = , + , + ; + }; + }; +}; + +i2s_tx: &tdm130 { + status = "okay"; + pinctrl-0 = <&tdm130_default_alt>; + pinctrl-names = "default"; + memory-regions = <&cpuapp_dma_region>; + mck-clock-source = "ACLK"; + sck-clock-source = "ACLK"; +}; + +&audiopll { + frequency = ; + status = "okay"; +}; + +&cpuapp_dma_region { + status = "okay"; +}; + +/* PPI channel 0 for TDM130 MAXCNT */ +&dppic132 { + compatible = "nordic,nrf-dppic-global"; + owned-channels = <0>; + source-channels = <0>; + nonsecure-channels = <0>; + status = "okay"; +}; + +/* PPI channel 1 for GPIOTE used for feedback in edge counter mode */ +&gpiote130 { + status = "okay"; + owned-channels = <1>; +}; + +/* GPIOTE130 and TDM130 PPI needs routing to TIMER131 through main APB */ +&dppic130 { + compatible = "nordic,nrf-dppic-global"; + owned-channels = <0 1>; + sink-channels = <0 1>; + source-channels = <0 1>; + nonsecure-channels = <0 1>; + status = "okay"; +}; + +/* TIMER131 PPI channel 2 is used for SOF */ +&dppic133 { + compatible = "nordic,nrf-dppic-global"; + owned-channels = <0 1 2>; + sink-channels = <0 1 2>; + status = "okay"; +}; + +&timer131 { + status = "okay"; +}; diff --git a/samples/subsys/usb/uac2_explicit_feedback/sample.yaml b/samples/subsys/usb/uac2_explicit_feedback/sample.yaml index bc0797a9812..9a58d1b6443 100644 --- a/samples/subsys/usb/uac2_explicit_feedback/sample.yaml +++ b/samples/subsys/usb/uac2_explicit_feedback/sample.yaml @@ -8,5 +8,7 @@ tests: tags: - usb - i2s - platform_allow: nrf5340dk/nrf5340/cpuapp + platform_allow: + - nrf5340dk/nrf5340/cpuapp + - nrf54h20dk/nrf54h20/cpuapp harness: TBD diff --git a/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf53.c b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c similarity index 89% rename from samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf53.c rename to samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c index 7e949d61211..62a7ad05ef9 100644 --- a/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf53.c +++ b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c @@ -12,18 +12,56 @@ #include #include #include -#include -#include #include LOG_MODULE_REGISTER(feedback, LOG_LEVEL_INF); -static const nrfx_gpiote_t gpiote = NRFX_GPIOTE_INSTANCE(0); +#define FEEDBACK_TIMER_USBD_SOF_CAPTURE 0 +#define FEEDBACK_TIMER_I2S_FRAMESTART_CAPTURE 1 + +#if IS_ENABLED(CONFIG_SOC_COMPATIBLE_NRF5340_CPUAPP) + +#include +#include #define FEEDBACK_PIN NRF_GPIO_PIN_MAP(1, 9) +#define FEEDBACK_GPIOTE_INSTANCE_NUMBER 0 #define FEEDBACK_TIMER_INSTANCE_NUMBER 2 -#define FEEDBACK_TIMER_USBD_SOF_CAPTURE 0 -#define FEEDBACK_TIMER_I2S_FRAMESTART_CAPTURE 1 +#define USB_SOF_EVENT_ADDRESS nrf_usbd_event_address_get(NRF_USBD, NRF_USBD_EVENT_SOF) +#define I2S_FRAMESTART_EVENT_ADDRESS nrf_i2s_event_address_get(NRF_I2S0, NRF_I2S_EVENT_FRAMESTART) + +static inline void feedback_target_init(void) +{ + if (IS_ENABLED(CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER)) { + /* App core is using feedback pin */ + nrf_gpio_pin_control_select(FEEDBACK_PIN, NRF_GPIO_PIN_SEL_APP); + } +} + +#elif IS_ENABLED(CONFIG_SOC_SERIES_NRF54HX) + +#include + +#define FEEDBACK_PIN NRF_GPIO_PIN_MAP(0, 8) +#define FEEDBACK_GPIOTE_INSTANCE_NUMBER 130 +#define FEEDBACK_TIMER_INSTANCE_NUMBER 131 +#define USB_SOF_EVENT_ADDRESS nrf_timer_event_address_get(NRF_TIMER131, NRF_TIMER_EVENT_COMPARE5) +#define I2S_FRAMESTART_EVENT_ADDRESS nrf_tdm_event_address_get(NRF_TDM130, NRF_TDM_EVENT_MAXCNT) + +static inline void feedback_target_init(void) +{ + /* Enable Start-of-Frame workaround in TIMER131 */ + *(volatile uint32_t *)0x5F9A3C04 = 0x00000002; + *(volatile uint32_t *)0x5F9A3C04 = 0x00000003; + *(volatile uint32_t *)0x5F9A3C80 = 0x00000082; +} + +#else +#error "Unsupported target" +#endif + +static const nrfx_gpiote_t gpiote = + NRFX_GPIOTE_INSTANCE(FEEDBACK_GPIOTE_INSTANCE_NUMBER); static const nrfx_timer_t feedback_timer_instance = NRFX_TIMER_INSTANCE(FEEDBACK_TIMER_INSTANCE_NUMBER); @@ -80,13 +118,12 @@ static nrfx_err_t feedback_edge_counter_setup(void) .trigger = NRFX_GPIOTE_TRIGGER_TOGGLE, .p_in_channel = &feedback_gpiote_channel, }; + nrf_gpio_pin_pull_t pull = NRF_GPIO_PIN_PULLUP; nrfx_gpiote_input_pin_config_t input_pin_config = { + .p_pull_config = &pull, .p_trigger_config = &trigger_config, }; - /* App core is using feedback pin */ - nrf_gpio_pin_control_select(FEEDBACK_PIN, NRF_GPIO_PIN_SEL_APP); - err = nrfx_gpiote_channel_alloc(&gpiote, &feedback_gpiote_channel); if (err != NRFX_SUCCESS) { return err; @@ -151,6 +188,8 @@ struct feedback_ctx *feedback_init(void) uint8_t usbd_sof_gppi_channel; uint8_t i2s_framestart_gppi_channel; + feedback_target_init(); + feedback_reset_ctx(&fb_ctx); if (IS_ENABLED(CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER)) { @@ -171,7 +210,7 @@ struct feedback_ctx *feedback_init(void) } nrfx_gppi_channel_endpoints_setup(usbd_sof_gppi_channel, - nrf_usbd_event_address_get(NRF_USBD, NRF_USBD_EVENT_SOF), + USB_SOF_EVENT_ADDRESS, nrfx_timer_capture_task_address_get(&feedback_timer_instance, FEEDBACK_TIMER_USBD_SOF_CAPTURE)); nrfx_gppi_fork_endpoint_setup(usbd_sof_gppi_channel, @@ -188,7 +227,7 @@ struct feedback_ctx *feedback_init(void) } nrfx_gppi_channel_endpoints_setup(i2s_framestart_gppi_channel, - nrf_i2s_event_address_get(NRF_I2S0, NRF_I2S_EVENT_FRAMESTART), + I2S_FRAMESTART_EVENT_ADDRESS, nrfx_timer_capture_task_address_get(&feedback_timer_instance, FEEDBACK_TIMER_I2S_FRAMESTART_CAPTURE)); diff --git a/samples/subsys/usb/uac2_implicit_feedback/CMakeLists.txt b/samples/subsys/usb/uac2_implicit_feedback/CMakeLists.txt index 26ce264c421..56bba10717c 100644 --- a/samples/subsys/usb/uac2_implicit_feedback/CMakeLists.txt +++ b/samples/subsys/usb/uac2_implicit_feedback/CMakeLists.txt @@ -7,8 +7,8 @@ project(usb_audio_async_i2s) include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake) target_sources(app PRIVATE src/main.c) -if (CONFIG_SOC_COMPATIBLE_NRF5340_CPUAPP) - target_sources(app PRIVATE src/feedback_nrf53.c) +if (CONFIG_SOC_COMPATIBLE_NRF5340_CPUAPP OR CONFIG_SOC_SERIES_NRF54HX) + target_sources(app PRIVATE src/feedback_nrf.c) else() target_sources(app PRIVATE src/feedback_dummy.c) endif() diff --git a/samples/subsys/usb/uac2_implicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf b/samples/subsys/usb/uac2_implicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf new file mode 100644 index 00000000000..1b1edb40666 --- /dev/null +++ b/samples/subsys/usb/uac2_implicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -0,0 +1,7 @@ +# Enable timer for asynchronous feedback +CONFIG_NRFX_GPPI=y +CONFIG_NRFX_TIMER131=y + +# Sample is Full-Speed only, prevent High-Speed enumeration +CONFIG_UDC_DRIVER_HIGH_SPEED_SUPPORT_ENABLED=n +CONFIG_USBD_MAX_SPEED_FULL=y diff --git a/samples/subsys/usb/uac2_implicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/samples/subsys/usb/uac2_implicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..7fec156ff7e --- /dev/null +++ b/samples/subsys/usb/uac2_implicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "../app.overlay" + +&pinctrl { + tdm130_default_alt: tdm130_default_alt { + group1 { + psels = , + , + , + ; + }; + }; +}; + +i2s_rxtx: &tdm130 { + status = "okay"; + pinctrl-0 = <&tdm130_default_alt>; + pinctrl-names = "default"; + memory-regions = <&cpuapp_dma_region>; + mck-clock-source = "ACLK"; + sck-clock-source = "ACLK"; +}; + +&audiopll { + frequency = ; + status = "okay"; +}; + +&cpuapp_dma_region { + status = "okay"; +}; + +/* PPI channel 0 for TDM130 MAXCNT */ +&dppic132 { + compatible = "nordic,nrf-dppic-global"; + owned-channels = <0>; + source-channels = <0>; + nonsecure-channels = <0>; + status = "okay"; +}; + +/* TDM130 PPI needs routing to TIMER131 through main APB */ +&dppic130 { + compatible = "nordic,nrf-dppic-global"; + owned-channels = <0>; + sink-channels = <0>; + source-channels = <0>; + nonsecure-channels = <0>; + status = "okay"; +}; + +/* TIMER131 PPI channel 1 is used for SOF */ +&dppic133 { + compatible = "nordic,nrf-dppic-global"; + owned-channels = <0 1>; + sink-channels = <0 1>; + status = "okay"; +}; + +&timer131 { + status = "okay"; +}; diff --git a/samples/subsys/usb/uac2_implicit_feedback/sample.yaml b/samples/subsys/usb/uac2_implicit_feedback/sample.yaml index 6682ac0ed83..03cf7145e89 100644 --- a/samples/subsys/usb/uac2_implicit_feedback/sample.yaml +++ b/samples/subsys/usb/uac2_implicit_feedback/sample.yaml @@ -8,5 +8,7 @@ tests: tags: - usb - i2s - platform_allow: nrf5340dk/nrf5340/cpuapp + platform_allow: + - nrf5340dk/nrf5340/cpuapp + - nrf54h20dk/nrf54h20/cpuapp harness: TBD diff --git a/samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf53.c b/samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf.c similarity index 85% rename from samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf53.c rename to samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf.c index ecc59f1a35a..a7dfad370b8 100644 --- a/samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf53.c +++ b/samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf.c @@ -10,16 +10,47 @@ #include #include -#include -#include #include LOG_MODULE_REGISTER(feedback, LOG_LEVEL_INF); -#define FEEDBACK_TIMER_INSTANCE_NUMBER 2 #define FEEDBACK_TIMER_USBD_SOF_CAPTURE 0 #define FEEDBACK_TIMER_I2S_FRAMESTART_CAPTURE 1 +#if IS_ENABLED(CONFIG_SOC_COMPATIBLE_NRF5340_CPUAPP) + +#include +#include + +#define FEEDBACK_TIMER_INSTANCE_NUMBER 2 +#define USB_SOF_EVENT_ADDRESS nrf_usbd_event_address_get(NRF_USBD, NRF_USBD_EVENT_SOF) +#define I2S_FRAMESTART_EVENT_ADDRESS nrf_i2s_event_address_get(NRF_I2S0, NRF_I2S_EVENT_FRAMESTART) + +static inline void feedback_target_init(void) +{ + /* No target specific init necessary */ +} + +#elif IS_ENABLED(CONFIG_SOC_SERIES_NRF54HX) + +#include + +#define FEEDBACK_TIMER_INSTANCE_NUMBER 131 +#define USB_SOF_EVENT_ADDRESS nrf_timer_event_address_get(NRF_TIMER131, NRF_TIMER_EVENT_COMPARE5) +#define I2S_FRAMESTART_EVENT_ADDRESS nrf_tdm_event_address_get(NRF_TDM130, NRF_TDM_EVENT_MAXCNT) + +static inline void feedback_target_init(void) +{ + /* Enable Start-of-Frame workaround in TIMER131 */ + *(volatile uint32_t *)0x5F9A3C04 = 0x00000002; + *(volatile uint32_t *)0x5F9A3C04 = 0x00000003; + *(volatile uint32_t *)0x5F9A3C80 = 0x00000082; +} + +#else +#error "Unsupported target" +#endif + static const nrfx_timer_t feedback_timer_instance = NRFX_TIMER_INSTANCE(FEEDBACK_TIMER_INSTANCE_NUMBER); @@ -57,6 +88,8 @@ struct feedback_ctx *feedback_init(void) .p_context = NULL, }; + feedback_target_init(); + feedback_reset_ctx(&fb_ctx); err = nrfx_timer_init(&feedback_timer_instance, &cfg, NULL); @@ -73,7 +106,7 @@ struct feedback_ctx *feedback_init(void) } nrfx_gppi_channel_endpoints_setup(usbd_sof_gppi_channel, - nrf_usbd_event_address_get(NRF_USBD, NRF_USBD_EVENT_SOF), + USB_SOF_EVENT_ADDRESS, nrfx_timer_capture_task_address_get(&feedback_timer_instance, FEEDBACK_TIMER_USBD_SOF_CAPTURE)); nrfx_gppi_fork_endpoint_setup(usbd_sof_gppi_channel, @@ -90,7 +123,7 @@ struct feedback_ctx *feedback_init(void) } nrfx_gppi_channel_endpoints_setup(i2s_framestart_gppi_channel, - nrf_i2s_event_address_get(NRF_I2S0, NRF_I2S_EVENT_FRAMESTART), + I2S_FRAMESTART_EVENT_ADDRESS, nrfx_timer_capture_task_address_get(&feedback_timer_instance, FEEDBACK_TIMER_I2S_FRAMESTART_CAPTURE));