Browse Source

samples: usb: uac2: Implement feedback on nRF54H20

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ń <tomasz.mon@nordicsemi.no>
pull/91613/merge
Tomasz Moń 2 months ago committed by Fabio Baltieri
parent
commit
e0c2372eeb
  1. 4
      samples/subsys/usb/uac2_explicit_feedback/CMakeLists.txt
  2. 2
      samples/subsys/usb/uac2_explicit_feedback/Kconfig
  3. 8
      samples/subsys/usb/uac2_explicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf
  4. 72
      samples/subsys/usb/uac2_explicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay
  5. 4
      samples/subsys/usb/uac2_explicit_feedback/sample.yaml
  6. 59
      samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c
  7. 4
      samples/subsys/usb/uac2_implicit_feedback/CMakeLists.txt
  8. 7
      samples/subsys/usb/uac2_implicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf
  9. 67
      samples/subsys/usb/uac2_implicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay
  10. 4
      samples/subsys/usb/uac2_implicit_feedback/sample.yaml
  11. 43
      samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf.c

4
samples/subsys/usb/uac2_explicit_feedback/CMakeLists.txt

@ -7,8 +7,8 @@ project(usb_audio_async_i2s) @@ -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()

2
samples/subsys/usb/uac2_explicit_feedback/Kconfig

@ -9,6 +9,8 @@ config APP_USE_I2S_LRCLK_EDGES_COUNTER @@ -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

8
samples/subsys/usb/uac2_explicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf

@ -0,0 +1,8 @@ @@ -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

72
samples/subsys/usb/uac2_explicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay

@ -0,0 +1,72 @@ @@ -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 = <NRF_PSEL(TDM_SCK_M, 1, 3)>,
<NRF_PSEL(TDM_FSYNC_M, 1, 6)>,
<NRF_PSEL(TDM_SDOUT, 1, 4)>;
};
};
};
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 = <NRFS_AUDIOPLL_FREQ_AUDIO_48K>;
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";
};

4
samples/subsys/usb/uac2_explicit_feedback/sample.yaml

@ -8,5 +8,7 @@ tests: @@ -8,5 +8,7 @@ tests:
tags:
- usb
- i2s
platform_allow: nrf5340dk/nrf5340/cpuapp
platform_allow:
- nrf5340dk/nrf5340/cpuapp
- nrf54h20dk/nrf54h20/cpuapp
harness: TBD

59
samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf53.c → samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c

@ -12,18 +12,56 @@ @@ -12,18 +12,56 @@
#include <nrfx_gpiote.h>
#include <nrfx_timer.h>
#include <hal/nrf_gpio.h>
#include <hal/nrf_usbd.h>
#include <hal/nrf_i2s.h>
#include <helpers/nrfx_gppi.h>
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 <hal/nrf_usbd.h>
#include <hal/nrf_i2s.h>
#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 <hal/nrf_tdm.h>
#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) @@ -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) @@ -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) @@ -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) @@ -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));

4
samples/subsys/usb/uac2_implicit_feedback/CMakeLists.txt

@ -7,8 +7,8 @@ project(usb_audio_async_i2s) @@ -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()

7
samples/subsys/usb/uac2_implicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf

@ -0,0 +1,7 @@ @@ -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

67
samples/subsys/usb/uac2_implicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay

@ -0,0 +1,67 @@ @@ -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 = <NRF_PSEL(TDM_SCK_M, 1, 3)>,
<NRF_PSEL(TDM_FSYNC_M, 1, 6)>,
<NRF_PSEL(TDM_SDOUT, 1, 4)>,
<NRF_PSEL(TDM_SDIN, 1, 5)>;
};
};
};
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 = <NRFS_AUDIOPLL_FREQ_AUDIO_48K>;
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";
};

4
samples/subsys/usb/uac2_implicit_feedback/sample.yaml

@ -8,5 +8,7 @@ tests: @@ -8,5 +8,7 @@ tests:
tags:
- usb
- i2s
platform_allow: nrf5340dk/nrf5340/cpuapp
platform_allow:
- nrf5340dk/nrf5340/cpuapp
- nrf54h20dk/nrf54h20/cpuapp
harness: TBD

43
samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf53.c → samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf.c

@ -10,16 +10,47 @@ @@ -10,16 +10,47 @@
#include <nrfx_dppi.h>
#include <nrfx_timer.h>
#include <hal/nrf_usbd.h>
#include <hal/nrf_i2s.h>
#include <helpers/nrfx_gppi.h>
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 <hal/nrf_usbd.h>
#include <hal/nrf_i2s.h>
#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 <hal/nrf_tdm.h>
#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) @@ -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) @@ -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) @@ -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));
Loading…
Cancel
Save