From 9cd79b1ff8769f604161ab34244a35464dfd2f13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Wed, 25 Jun 2025 13:26:32 +0200 Subject: [PATCH 1/8] [nrf fromtree] samples: usb: uac2: Support High-Speed operation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow the samples to work both at Full-Speed and High-Speed exposing the same capabilities at both speeds. Signed-off-by: Tomasz Moń (cherry picked from commit ff50dfb002ab9e780d57508b5bd4f6c187a88a97) --- .../usb/uac2_explicit_feedback/app.overlay | 1 + .../boards/nrf54h20dk_nrf54h20_cpuapp.conf | 4 - .../usb/uac2_explicit_feedback/src/feedback.h | 13 +- .../src/feedback_dummy.c | 28 ++- .../uac2_explicit_feedback/src/feedback_nrf.c | 166 +++++++++++++----- .../usb/uac2_explicit_feedback/src/main.c | 28 +-- .../usb/uac2_implicit_feedback/app.overlay | 1 + .../boards/nrf54h20dk_nrf54h20_cpuapp.conf | 4 - .../usb/uac2_implicit_feedback/src/feedback.h | 9 +- .../src/feedback_dummy.c | 4 +- .../uac2_implicit_feedback/src/feedback_nrf.c | 26 ++- .../usb/uac2_implicit_feedback/src/main.c | 51 ++++-- 12 files changed, 226 insertions(+), 109 deletions(-) diff --git a/samples/subsys/usb/uac2_explicit_feedback/app.overlay b/samples/subsys/usb/uac2_explicit_feedback/app.overlay index 3ff71797aa9..21119a79206 100644 --- a/samples/subsys/usb/uac2_explicit_feedback/app.overlay +++ b/samples/subsys/usb/uac2_explicit_feedback/app.overlay @@ -11,6 +11,7 @@ compatible = "zephyr,uac2"; status = "okay"; full-speed; + high-speed; audio-function = ; uac_aclk: aclk { 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 index 0e35fa1f491..d7526fc6ec9 100644 --- a/samples/subsys/usb/uac2_explicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf +++ b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -2,7 +2,3 @@ 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/src/feedback.h b/samples/subsys/usb/uac2_explicit_feedback/src/feedback.h index 7f5bf2027d8..37c1dc975e5 100644 --- a/samples/subsys/usb/uac2_explicit_feedback/src/feedback.h +++ b/samples/subsys/usb/uac2_explicit_feedback/src/feedback.h @@ -9,15 +9,14 @@ #include -/* Nominal number of samples received on each SOF. This sample is currently - * supporting only 48 kHz sample rate. - */ -#define SAMPLES_PER_SOF 48 +/* This sample is currently supporting only 48 kHz sample rate. */ +#define SAMPLE_RATE 48000 struct feedback_ctx *feedback_init(void); -void feedback_reset_ctx(struct feedback_ctx *ctx); +void feedback_reset_ctx(struct feedback_ctx *ctx, bool microframes); void feedback_process(struct feedback_ctx *ctx); -void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued); +void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued, + bool microframes); uint32_t feedback_value(struct feedback_ctx *ctx); - +#define SAMPLES_PER_SOF 48 #endif /* FEEDBACK_H_ */ diff --git a/samples/subsys/usb/uac2_explicit_feedback/src/feedback_dummy.c b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_dummy.c index 7e274ca2ed0..378a43e06ef 100644 --- a/samples/subsys/usb/uac2_explicit_feedback/src/feedback_dummy.c +++ b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_dummy.c @@ -5,15 +5,23 @@ */ #include +#include #include "feedback.h" #warning "No target specific feedback code, overruns/underruns will occur" -#define FEEDBACK_K 10 +#define FEEDBACK_FS_K 10 +#define FEEDBACK_FS_SHIFT 4 +#define FEEDBACK_HS_K 13 +#define FEEDBACK_HS_SHIFT 3 + +static struct feedback_ctx { + bool high_speed; +} fb_ctx; struct feedback_ctx *feedback_init(void) { - return NULL; + return &fb_ctx; } void feedback_process(struct feedback_ctx *ctx) @@ -21,19 +29,25 @@ void feedback_process(struct feedback_ctx *ctx) ARG_UNUSED(ctx); } -void feedback_reset_ctx(struct feedback_ctx *ctx) +void feedback_reset_ctx(struct feedback_ctx *ctx, bool microframes) { - ARG_UNUSED(ctx); + ctx->high_speed = microframes; } -void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued) +void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued, + bool microframes) { - ARG_UNUSED(ctx); ARG_UNUSED(i2s_blocks_queued); + + ctx->high_speed = microframes; } uint32_t feedback_value(struct feedback_ctx *ctx) { /* Always request nominal number of samples */ - return SAMPLES_PER_SOF << FEEDBACK_K; + if (USBD_SUPPORTS_HIGH_SPEED && ctx->high_speed) { + return (SAMPLE_RATE / 8000) << (FEEDBACK_HS_K + FEEDBACK_HS_SHIFT); + } + + return (SAMPLE_RATE / 1000) << (FEEDBACK_FS_K + FEEDBACK_FS_SHIFT); } diff --git a/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c index 62a7ad05ef9..6ea9d2374d9 100644 --- a/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c +++ b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c @@ -84,8 +84,14 @@ static const nrfx_timer_t feedback_timer_instance = * Full-Speed isochronous feedback is Q10.10 unsigned integer left-justified in * the 24-bits so it has Q10.14 format. This sample application puts zeroes to * the 4 least significant bits (does not use the bits for extra precision). + * + * High-Speed isochronous feedback is Q12.13 unsigned integer aligned in the + * 32-bits so the binary point is located between second and third byte so it + * has Q16.16 format. This sample applications puts zeroes to the 3 least + * significant bits (does not use the bits for extra precision). */ -#define FEEDBACK_K 10 +#define FEEDBACK_FS_K 10 +#define FEEDBACK_HS_K 13 #if defined(CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER) #define FEEDBACK_P 1 #else @@ -93,11 +99,14 @@ static const nrfx_timer_t feedback_timer_instance = #endif #define FEEDBACK_FS_SHIFT 4 +#define FEEDBACK_HS_SHIFT 3 static struct feedback_ctx { uint32_t fb_value; int32_t rel_sof_offset; int32_t base_sof_offset; + uint32_t counts_per_sof; + bool high_speed; union { /* For edge counting */ struct { @@ -190,7 +199,7 @@ struct feedback_ctx *feedback_init(void) feedback_target_init(); - feedback_reset_ctx(&fb_ctx); + feedback_reset_ctx(&fb_ctx, false); if (IS_ENABLED(CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER)) { err = feedback_edge_counter_setup(); @@ -239,6 +248,24 @@ struct feedback_ctx *feedback_init(void) return &fb_ctx; } +static uint32_t nominal_feedback_value(struct feedback_ctx *ctx) +{ + if (ctx->high_speed) { + return (SAMPLE_RATE / 8000) << (FEEDBACK_HS_K + FEEDBACK_HS_SHIFT); + } + + return (SAMPLE_RATE / 1000) << (FEEDBACK_FS_K + FEEDBACK_FS_SHIFT); +} + +static uint32_t feedback_period(struct feedback_ctx *ctx) +{ + if (ctx->high_speed) { + return BIT(FEEDBACK_HS_K - FEEDBACK_P); + } + + return BIT(FEEDBACK_FS_K - FEEDBACK_P); +} + static void update_sof_offset(struct feedback_ctx *ctx, uint32_t sof_cc, uint32_t framestart_cc) { @@ -255,7 +282,7 @@ static void update_sof_offset(struct feedback_ctx *ctx, uint32_t sof_cc, * when regulated and therefore the relative clock frequency * discrepancies are essentially negligible. */ - clks_per_edge = sof_cc / (SAMPLES_PER_SOF << FEEDBACK_P); + clks_per_edge = sof_cc / ctx->counts_per_sof; sof_cc /= MAX(clks_per_edge, 1); framestart_cc /= MAX(clks_per_edge, 1); } @@ -263,8 +290,8 @@ static void update_sof_offset(struct feedback_ctx *ctx, uint32_t sof_cc, /* /2 because we treat the middle as a turning point from being * "too late" to "too early". */ - if (framestart_cc > (SAMPLES_PER_SOF << FEEDBACK_P)/2) { - sof_offset = framestart_cc - (SAMPLES_PER_SOF << FEEDBACK_P); + if (framestart_cc > ctx->counts_per_sof/2) { + sof_offset = framestart_cc - ctx->counts_per_sof; } else { sof_offset = framestart_cc; } @@ -279,17 +306,17 @@ static void update_sof_offset(struct feedback_ctx *ctx, uint32_t sof_cc, if (sof_offset >= 0) { abs_diff = sof_offset - ctx->rel_sof_offset; - base_change = -(SAMPLES_PER_SOF << FEEDBACK_P); + base_change = -ctx->counts_per_sof; } else { abs_diff = ctx->rel_sof_offset - sof_offset; - base_change = SAMPLES_PER_SOF << FEEDBACK_P; + base_change = ctx->counts_per_sof; } /* Adjust base offset only if the change happened through the * outer bound. The actual changes should be significantly lower * than the threshold here. */ - if (abs_diff > (SAMPLES_PER_SOF << FEEDBACK_P)/2) { + if (abs_diff > ctx->counts_per_sof/2) { ctx->base_sof_offset += base_change; } } @@ -297,8 +324,12 @@ static void update_sof_offset(struct feedback_ctx *ctx, uint32_t sof_cc, ctx->rel_sof_offset = sof_offset; } -static inline int32_t offset_to_correction(int32_t offset) +static inline int32_t offset_to_correction(struct feedback_ctx *ctx, int32_t offset) { + if (ctx->high_speed) { + return -(offset / BIT(FEEDBACK_P)) * BIT(FEEDBACK_HS_SHIFT); + } + return -(offset / BIT(FEEDBACK_P)) * BIT(FEEDBACK_FS_SHIFT); } @@ -320,39 +351,66 @@ static int32_t pi_update(struct feedback_ctx *ctx) int32_t error = SP - PV; /* - * With above normalization at Full-Speed, when data received during - * SOF n appears on I2S during SOF n+3, the Ziegler Nichols Ultimate - * Gain is around 1.15 and the oscillation period is around 90 SOF. - * (much nicer oscillations with 204.8 SOF period can be observed with - * gain 0.5 when the delay is not n+3, but n+33 - surprisingly the - * resulting PI coefficients after power of two rounding are the same). + * With above normalization, when data received during SOF n appears on + * I2S during SOF n+3, the Ziegler Nichols Ultimate Gain and oscillation + * periods are as follows: * - * Ziegler-Nichols rule with applied stability margin of 2 results in: - * Kc = 0.22 * Ku = 0.22 * 1.15 = 0.253 - * Ti = 0.83 * tu = 0.83 * 80 = 66.4 + * Full-Speed Linux: Ku = 1.34 tu=77 [FS SOFs] + * Full-Speed Mac OS: Ku = 0.173 tu=580 [FS SOFs] + * High-Speed Mac OS: Ku = 0.895 tu=4516 [HS SOFs] + * High-Speed Windows: Ku = 0.515 tu=819 [HS SOFs] * - * Converting the rules above to parallel PI gives: - * Kp = Kc = 0.253 - * Ki = Kc/Ti = 0.254/66.4 ~= 0.0038253 + * Linux and Mac OS oscillations were very neat, while Windows seems to + * be averaging feedback value and therefore it is hard to get steady + * oscillations without getting buffer uderrun. * - * Because we want fixed-point optimized non-tunable implementation, - * the parameters can be conveniently expressed with power of two: - * Kp ~= pow(2, -2) = 0.25 (divide by 4) - * Ki ~= pow(2, -8) = 0.0039 (divide by 256) + * Ziegler-Nichols rule with applied stability margin of 2 results in: + * [FS Linux] [FS Mac] [HS Mac] [HS Windows] + * Kc = 0.22 * Ku 0.2948 0.0381 0.1969 0.1133 + * Ti = 0.83 * tu 63.91 481.4 3748 647.9 * - * This can be implemented as: + * Converting the rules to work with following simple regulator: * ctx->integrator += error; - * return (error + (ctx->integrator / 64)) / 4; - * but unfortunately such regulator is pretty aggressive and keeps - * oscillating rather quickly around the setpoint (within +-1 sample). + * return (error + (ctx->integrator / Ti)) / invKc; + * + * gives following parameters: + * [FS Linux] [FS Mac] [HS Mac] [HS Windows] + * invKc = 1/Kc 3 26 5 8 + * Ti 64 482 3748 648 + * + * The respective regulators seem to give quarter-amplitude-damping on + * respective hosts, but tuning from one host can get into oscillations + * on another host. The regulation goal is to achieve a single set of + * parameters to be used with all hosts, the only parameter difference + * can be based on operating speed. + * + * After a number of tests with all the hosts, following parameters + * were determined to result in nice no-overshoot response: + * [Full-Speed] [High-Speed] + * invKc 128 128 + * Ti 2048 16384 + * + * The power-of-two parameters were arbitrarily chosen for rounding. + * The 16384 = 2048 * 8 can be considered as unifying integration time. + * + * While the no-overshoot is also present with invKc as low as 32, such + * regulator is pretty aggressive and keeps oscillating rather quickly + * around the setpoint (within +-1 sample). Lowering the controller gain + * (increasing invKc value) yields really good results (the outcome is + * similar to using I2S LRCLK edge counting directly). * - * Manually tweaking the constants so the regulator output is shifted - * down by 4 bits (i.e. change /64 to /2048 and /4 to /128) yields - * really good results (the outcome is similar, even slightly better, - * than using I2S LRCLK edge counting directly). + * The most challenging scenario is for the regulator to stabilize right + * after startup when I2S consumes data faster than nominal sample rate + * (48 kHz = 6 samples per SOF at High-Speed, 48 samples at Full-Speed) + * according to host (I2S consuming data slower slower than nominal + * sample rate is not problematic at all because buffer overrun does not + * stop I2S streaming). This regulator should be able to stabilize for + * any frequency that is within required USB SOF accuracy of 500 ppm, + * i.e. when nominal sample rate is 48 kHz the real sample rate can be + * anywhere in [47.976 kHz; 48.024 kHz] range. */ ctx->integrator += error; - return (error + (ctx->integrator / 2048)) / 128; + return (error + (ctx->integrator / (ctx->high_speed ? 16384 : 2048))) / 128; } void feedback_process(struct feedback_ctx *ctx) @@ -374,17 +432,21 @@ void feedback_process(struct feedback_ctx *ctx) ctx->fb_counter += sof_cc; ctx->fb_periods++; - if (ctx->fb_periods == BIT(FEEDBACK_K - FEEDBACK_P)) { + if (ctx->fb_periods == feedback_period(ctx)) { - /* fb_counter holds Q10.10 value, left-justify it */ - fb = ctx->fb_counter << FEEDBACK_FS_SHIFT; + if (ctx->high_speed) { + fb = ctx->fb_counter << FEEDBACK_HS_SHIFT; + } else { + /* fb_counter holds Q10.10 value, left-justify it */ + fb = ctx->fb_counter << FEEDBACK_FS_SHIFT; + } /* Align I2S FRAMESTART to USB SOF by adjusting reported * feedback value. This is endpoint specific correction * mentioned but not specified in USB 2.0 Specification. */ if (abs(offset) > BIT(FEEDBACK_P)) { - fb += offset_to_correction(offset); + fb += offset_to_correction(ctx, offset); } ctx->fb_value = fb; @@ -392,22 +454,25 @@ void feedback_process(struct feedback_ctx *ctx) ctx->fb_periods = 0; } } else { + const uint32_t zero_lsb_mask = ctx->high_speed ? 0x7 : 0xF; + /* Use PI controller to generate required feedback deviation * from nominal feedback value. */ - fb = SAMPLES_PER_SOF << (FEEDBACK_K + FEEDBACK_FS_SHIFT); + fb = nominal_feedback_value(ctx); /* Clear the additional LSB bits in feedback value, i.e. do not * use the optional extra resolution. */ - fb += pi_update(ctx) & ~0xF; + fb += pi_update(ctx) & ~zero_lsb_mask; ctx->fb_value = fb; } } -void feedback_reset_ctx(struct feedback_ctx *ctx) +void feedback_reset_ctx(struct feedback_ctx *ctx, bool microframes) { /* Reset feedback to nominal value */ - ctx->fb_value = SAMPLES_PER_SOF << (FEEDBACK_K + FEEDBACK_FS_SHIFT); + ctx->high_speed = microframes; + ctx->fb_value = nominal_feedback_value(ctx); if (IS_ENABLED(CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER)) { ctx->fb_counter = 0; ctx->fb_periods = 0; @@ -416,19 +481,28 @@ void feedback_reset_ctx(struct feedback_ctx *ctx) } } -void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued) +void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued, + bool microframes) { + ctx->high_speed = microframes; + ctx->fb_value = nominal_feedback_value(ctx); + + if (microframes) { + ctx->counts_per_sof = (SAMPLE_RATE / 8000) << FEEDBACK_P; + } else { + ctx->counts_per_sof = (SAMPLE_RATE / 1000) << FEEDBACK_P; + } + /* I2S data was supposed to go out at SOF, but it is inevitably * delayed due to triggering I2S start by software. Set relative * SOF offset value in a way that ensures that values past "half * frame" are treated as "too late" instead of "too early" */ - ctx->rel_sof_offset = (SAMPLES_PER_SOF << FEEDBACK_P) / 2; + ctx->rel_sof_offset = ctx->counts_per_sof / 2; /* If there are more than 2 I2S blocks queued, use feedback regulator * to correct the situation. */ - ctx->base_sof_offset = (i2s_blocks_queued - 2) * - (SAMPLES_PER_SOF << FEEDBACK_P); + ctx->base_sof_offset = (i2s_blocks_queued - 2) * ctx->counts_per_sof; } uint32_t feedback_value(struct feedback_ctx *ctx) diff --git a/samples/subsys/usb/uac2_explicit_feedback/src/main.c b/samples/subsys/usb/uac2_explicit_feedback/src/main.c index 3f4f596f35c..40df3f5b8fc 100644 --- a/samples/subsys/usb/uac2_explicit_feedback/src/main.c +++ b/samples/subsys/usb/uac2_explicit_feedback/src/main.c @@ -20,14 +20,17 @@ LOG_MODULE_REGISTER(uac2_sample, LOG_LEVEL_INF); #define HEADPHONES_OUT_TERMINAL_ID UAC2_ENTITY_ID(DT_NODELABEL(out_terminal)) -#define SAMPLE_FREQUENCY (SAMPLES_PER_SOF * 1000) +#define FS_SAMPLES_PER_SOF 48 +#define HS_SAMPLES_PER_SOF 6 +#define MAX_SAMPLES_PER_SOF MAX(FS_SAMPLES_PER_SOF, HS_SAMPLES_PER_SOF) +#define SAMPLE_FREQUENCY (FS_SAMPLES_PER_SOF * 1000) #define SAMPLE_BIT_WIDTH 16 #define NUMBER_OF_CHANNELS 2 #define BYTES_PER_SAMPLE DIV_ROUND_UP(SAMPLE_BIT_WIDTH, 8) #define BYTES_PER_SLOT (BYTES_PER_SAMPLE * NUMBER_OF_CHANNELS) -#define MIN_BLOCK_SIZE ((SAMPLES_PER_SOF - 1) * BYTES_PER_SLOT) -#define BLOCK_SIZE (SAMPLES_PER_SOF * BYTES_PER_SLOT) -#define MAX_BLOCK_SIZE ((SAMPLES_PER_SOF + 1) * BYTES_PER_SLOT) +#define MIN_BLOCK_SIZE ((MAX_SAMPLES_PER_SOF - 1) * BYTES_PER_SLOT) +#define BLOCK_SIZE (MAX_SAMPLES_PER_SOF * BYTES_PER_SLOT) +#define MAX_BLOCK_SIZE ((MAX_SAMPLES_PER_SOF + 1) * BYTES_PER_SLOT) /* Absolute minimum is 5 buffers (1 actively consumed by I2S, 2nd queued as next * buffer, 3rd acquired by USB stack to receive data to, and 2 to handle SOF/I2S @@ -42,6 +45,7 @@ struct usb_i2s_ctx { const struct device *i2s_dev; bool terminal_enabled; bool i2s_started; + bool microframes; /* Number of blocks written, used to determine when to start I2S. * Overflows are not a problem becuse this variable is not necessary * after I2S is started. @@ -60,15 +64,15 @@ static void uac2_terminal_update_cb(const struct device *dev, uint8_t terminal, * ignore the terminal variable. */ __ASSERT_NO_MSG(terminal == HEADPHONES_OUT_TERMINAL_ID); - /* This sample is for Full-Speed only devices. */ - __ASSERT_NO_MSG(microframes == false); + + ctx->microframes = microframes; ctx->terminal_enabled = enabled; if (ctx->i2s_started && !enabled) { i2s_trigger(ctx->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_DROP); ctx->i2s_started = false; ctx->i2s_blocks_written = 0; - feedback_reset_ctx(ctx->fb); + feedback_reset_ctx(ctx->fb, ctx->microframes); } } @@ -114,7 +118,11 @@ static void uac2_data_recv_cb(const struct device *dev, uint8_t terminal, * either disable terminal (or the cable will be disconnected) * which will stop I2S. */ - size = BLOCK_SIZE; + if (USBD_SUPPORTS_HIGH_SPEED && ctx->microframes) { + size = HS_SAMPLES_PER_SOF * BYTES_PER_SLOT; + } else { + size = FS_SAMPLES_PER_SOF * BYTES_PER_SLOT; + } memset(buf, 0, size); } @@ -124,7 +132,7 @@ static void uac2_data_recv_cb(const struct device *dev, uint8_t terminal, if (ret < 0) { ctx->i2s_started = false; ctx->i2s_blocks_written = 0; - feedback_reset_ctx(ctx->fb); + feedback_reset_ctx(ctx->fb, ctx->microframes); /* Most likely underrun occurred, prepare I2S restart */ i2s_trigger(ctx->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_PREPARE); @@ -236,7 +244,7 @@ static void uac2_sof(const struct device *dev, void *user_data) ctx->i2s_blocks_written >= 2) { i2s_trigger(ctx->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_START); ctx->i2s_started = true; - feedback_start(ctx->fb, ctx->i2s_blocks_written); + feedback_start(ctx->fb, ctx->i2s_blocks_written, ctx->microframes); } } diff --git a/samples/subsys/usb/uac2_implicit_feedback/app.overlay b/samples/subsys/usb/uac2_implicit_feedback/app.overlay index 799d9e40d43..583b1f8ef7b 100644 --- a/samples/subsys/usb/uac2_implicit_feedback/app.overlay +++ b/samples/subsys/usb/uac2_implicit_feedback/app.overlay @@ -11,6 +11,7 @@ compatible = "zephyr,uac2"; status = "okay"; full-speed; + high-speed; audio-function = ; uac_aclk: aclk { 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 index 1b1edb40666..c4e23e5d54f 100644 --- a/samples/subsys/usb/uac2_implicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf +++ b/samples/subsys/usb/uac2_implicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -1,7 +1,3 @@ # 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/src/feedback.h b/samples/subsys/usb/uac2_implicit_feedback/src/feedback.h index 3fff2425d8b..584bc0135c2 100644 --- a/samples/subsys/usb/uac2_implicit_feedback/src/feedback.h +++ b/samples/subsys/usb/uac2_implicit_feedback/src/feedback.h @@ -9,15 +9,14 @@ #include -/* Nominal number of samples received on each SOF. This sample is currently - * supporting only 48 kHz sample rate. - */ -#define SAMPLES_PER_SOF 48 +/* This sample is currently supporting only 48 kHz sample rate. */ +#define SAMPLE_RATE 48000 struct feedback_ctx *feedback_init(void); void feedback_reset_ctx(struct feedback_ctx *ctx); void feedback_process(struct feedback_ctx *ctx); -void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued); +void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued, + bool microframes); /* Return offset between I2S block start and USB SOF in samples. * diff --git a/samples/subsys/usb/uac2_implicit_feedback/src/feedback_dummy.c b/samples/subsys/usb/uac2_implicit_feedback/src/feedback_dummy.c index 3b91deafe5c..d28181033b9 100644 --- a/samples/subsys/usb/uac2_implicit_feedback/src/feedback_dummy.c +++ b/samples/subsys/usb/uac2_implicit_feedback/src/feedback_dummy.c @@ -24,10 +24,12 @@ void feedback_reset_ctx(struct feedback_ctx *ctx) ARG_UNUSED(ctx); } -void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued) +void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued, + bool microframes) { ARG_UNUSED(ctx); ARG_UNUSED(i2s_blocks_queued); + ARG_UNUSED(microframes); } int feedback_samples_offset(struct feedback_ctx *ctx) diff --git a/samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf.c b/samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf.c index a7dfad370b8..9623f22e566 100644 --- a/samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf.c +++ b/samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf.c @@ -68,11 +68,12 @@ static const nrfx_timer_t feedback_timer_instance = * SOF offset is around 0 when regulated and therefore the relative clock * frequency discrepancies are essentially negligible. */ -#define CLKS_PER_SAMPLE (16000000 / (SAMPLES_PER_SOF * 1000)) +#define CLKS_PER_SAMPLE (16000000 / (SAMPLE_RATE)) static struct feedback_ctx { int32_t rel_sof_offset; int32_t base_sof_offset; + unsigned int nominal; } fb_ctx; struct feedback_ctx *feedback_init(void) @@ -143,8 +144,8 @@ static void update_sof_offset(struct feedback_ctx *ctx, uint32_t sof_cc, /* /2 because we treat the middle as a turning point from being * "too late" to "too early". */ - if (framestart_cc > (SAMPLES_PER_SOF * CLKS_PER_SAMPLE)/2) { - sof_offset = framestart_cc - SAMPLES_PER_SOF * CLKS_PER_SAMPLE; + if (framestart_cc > (ctx->nominal * CLKS_PER_SAMPLE)/2) { + sof_offset = framestart_cc - ctx->nominal * CLKS_PER_SAMPLE; } else { sof_offset = framestart_cc; } @@ -159,17 +160,17 @@ static void update_sof_offset(struct feedback_ctx *ctx, uint32_t sof_cc, if (sof_offset >= 0) { abs_diff = sof_offset - ctx->rel_sof_offset; - base_change = -(SAMPLES_PER_SOF * CLKS_PER_SAMPLE); + base_change = -(ctx->nominal * CLKS_PER_SAMPLE); } else { abs_diff = ctx->rel_sof_offset - sof_offset; - base_change = SAMPLES_PER_SOF * CLKS_PER_SAMPLE; + base_change = ctx->nominal * CLKS_PER_SAMPLE; } /* Adjust base offset only if the change happened through the * outer bound. The actual changes should be significantly lower * than the threshold here. */ - if (abs_diff > (SAMPLES_PER_SOF * CLKS_PER_SAMPLE)/2) { + if (abs_diff > (ctx->nominal * CLKS_PER_SAMPLE)/2) { ctx->base_sof_offset += base_change; } } @@ -195,19 +196,26 @@ void feedback_reset_ctx(struct feedback_ctx *ctx) ARG_UNUSED(ctx); } -void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued) +void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued, + bool microframes) { + if (microframes) { + ctx->nominal = SAMPLE_RATE / 8000; + } else { + ctx->nominal = SAMPLE_RATE / 1000; + } + /* I2S data was supposed to go out at SOF, but it is inevitably * delayed due to triggering I2S start by software. Set relative * SOF offset value in a way that ensures that values past "half * frame" are treated as "too late" instead of "too early" */ - ctx->rel_sof_offset = (SAMPLES_PER_SOF * CLKS_PER_SAMPLE) / 2; + ctx->rel_sof_offset = (ctx->nominal * CLKS_PER_SAMPLE) / 2; /* If there are more than 2 I2S TX blocks queued, use feedback regulator * to correct the situation. */ ctx->base_sof_offset = (i2s_blocks_queued - 2) * - (SAMPLES_PER_SOF * CLKS_PER_SAMPLE); + (ctx->nominal * CLKS_PER_SAMPLE); } int feedback_samples_offset(struct feedback_ctx *ctx) diff --git a/samples/subsys/usb/uac2_implicit_feedback/src/main.c b/samples/subsys/usb/uac2_implicit_feedback/src/main.c index 12abdf4fe68..06334866e7a 100644 --- a/samples/subsys/usb/uac2_implicit_feedback/src/main.c +++ b/samples/subsys/usb/uac2_implicit_feedback/src/main.c @@ -21,15 +21,17 @@ LOG_MODULE_REGISTER(uac2_sample, LOG_LEVEL_INF); #define HEADPHONES_OUT_TERMINAL_ID UAC2_ENTITY_ID(DT_NODELABEL(out_terminal)) #define MICROPHONE_IN_TERMINAL_ID UAC2_ENTITY_ID(DT_NODELABEL(in_terminal)) -#define SAMPLES_PER_SOF 48 -#define SAMPLE_FREQUENCY (SAMPLES_PER_SOF * 1000) +#define FS_SAMPLES_PER_SOF 48 +#define HS_SAMPLES_PER_SOF 6 +#define MAX_SAMPLES_PER_SOF MAX(FS_SAMPLES_PER_SOF, HS_SAMPLES_PER_SOF) +#define SAMPLE_FREQUENCY (FS_SAMPLES_PER_SOF * 1000) #define SAMPLE_BIT_WIDTH 16 #define NUMBER_OF_CHANNELS 2 #define BYTES_PER_SAMPLE DIV_ROUND_UP(SAMPLE_BIT_WIDTH, 8) #define BYTES_PER_SLOT (BYTES_PER_SAMPLE * NUMBER_OF_CHANNELS) -#define MIN_BLOCK_SIZE ((SAMPLES_PER_SOF - 1) * BYTES_PER_SLOT) -#define BLOCK_SIZE (SAMPLES_PER_SOF * BYTES_PER_SLOT) -#define MAX_BLOCK_SIZE ((SAMPLES_PER_SOF + 1) * BYTES_PER_SLOT) +#define MIN_BLOCK_SIZE ((MAX_SAMPLES_PER_SOF - 1) * BYTES_PER_SLOT) +#define BLOCK_SIZE (MAX_SAMPLES_PER_SOF * BYTES_PER_SLOT) +#define MAX_BLOCK_SIZE ((MAX_SAMPLES_PER_SOF + 1) * BYTES_PER_SLOT) /* Absolute minimum is 5 TX buffers (1 actively consumed by I2S, 2nd queued as * next buffer, 3rd acquired by USB stack to receive data to, and 2 to handle @@ -49,6 +51,7 @@ struct usb_i2s_ctx { bool i2s_started; bool rx_started; bool usb_data_received; + bool microframes; /* Counter used to determine when to start I2S and then when to start * sending RX packets to host. Overflows are not a problem because this * variable is not necessary after both I2S and RX is started. @@ -70,8 +73,8 @@ struct usb_i2s_ctx { * Used to avoid overcompensation in feedback regulator. LSBs indicate * latest write size. */ - uint8_t plus_ones; - uint8_t minus_ones; + uint32_t plus_ones; + uint32_t minus_ones; }; static void uac2_terminal_update_cb(const struct device *dev, uint8_t terminal, @@ -80,8 +83,7 @@ static void uac2_terminal_update_cb(const struct device *dev, uint8_t terminal, { struct usb_i2s_ctx *ctx = user_data; - /* This sample is for Full-Speed only devices. */ - __ASSERT_NO_MSG(microframes == false); + ctx->microframes = microframes; if (terminal == HEADPHONES_OUT_TERMINAL_ID) { ctx->headphones_enabled = enabled; @@ -104,6 +106,15 @@ static void uac2_terminal_update_cb(const struct device *dev, uint8_t terminal, } } +static int nominal_samples_per_sof(struct usb_i2s_ctx *ctx) +{ + if (USBD_SUPPORTS_HIGH_SPEED && ctx->microframes) { + return HS_SAMPLES_PER_SOF; + } + + return FS_SAMPLES_PER_SOF; +} + static void *uac2_get_recv_buf(const struct device *dev, uint8_t terminal, uint16_t size, void *user_data) { @@ -133,6 +144,7 @@ static void uac2_data_recv_cb(const struct device *dev, uint8_t terminal, void *buf, uint16_t size, void *user_data) { struct usb_i2s_ctx *ctx = user_data; + int nominal = nominal_samples_per_sof(ctx); int ret; ctx->usb_data_received = true; @@ -159,11 +171,11 @@ static void uac2_data_recv_cb(const struct device *dev, uint8_t terminal, * of samples sent. */ if (ctx->plus_ones & 1) { - size = (SAMPLES_PER_SOF + 1) * BYTES_PER_SLOT; + size = (nominal + 1) * BYTES_PER_SLOT; } else if (ctx->minus_ones & 1) { - size = (SAMPLES_PER_SOF - 1) * BYTES_PER_SLOT; + size = (nominal - 1) * BYTES_PER_SLOT; } else { - size = SAMPLES_PER_SOF * BYTES_PER_SLOT; + size = nominal * BYTES_PER_SLOT; } memset(buf, 0, size); } @@ -208,6 +220,7 @@ static void uac2_buf_release_cb(const struct device *dev, uint8_t terminal, /* Determine next number of samples to send, called at most once every SOF */ static int next_mic_num_samples(struct usb_i2s_ctx *ctx) { + int nominal = nominal_samples_per_sof(ctx); int offset = feedback_samples_offset(ctx->fb); /* The rolling buffers essentially handle controller dead time, i.e. @@ -217,12 +230,18 @@ static int next_mic_num_samples(struct usb_i2s_ctx *ctx) ctx->plus_ones <<= 1; ctx->minus_ones <<= 1; + /* At Full-Speed only remember last 8 frames */ + if (!USBD_SUPPORTS_HIGH_SPEED || !ctx->microframes) { + ctx->plus_ones &= 0x000000FF; + ctx->minus_ones &= 0x000000FF; + } + if ((offset < 0) && (POPCOUNT(ctx->plus_ones) < -offset)) { /* I2S buffer starts at least 1 sample before SOF, send nominal * + 1 samples to host in order to shift offset towards 0. */ ctx->plus_ones |= 1; - return SAMPLES_PER_SOF + 1; + return nominal + 1; } if ((offset > 0) && (POPCOUNT(ctx->minus_ones) < offset)) { @@ -230,11 +249,11 @@ static int next_mic_num_samples(struct usb_i2s_ctx *ctx) * - 1 samples to host in order to shift offset towards 0 */ ctx->minus_ones |= 1; - return SAMPLES_PER_SOF - 1; + return nominal - 1; } /* I2S is either spot on, or the offset is expected to correct soon */ - return SAMPLES_PER_SOF; + return nominal; } static void process_mic_data(const struct device *dev, struct usb_i2s_ctx *ctx) @@ -488,7 +507,7 @@ static void uac2_sof(const struct device *dev, void *user_data) ctx->i2s_counter >= 2) { i2s_trigger(ctx->i2s_dev, I2S_DIR_BOTH, I2S_TRIGGER_START); ctx->i2s_started = true; - feedback_start(ctx->fb, ctx->i2s_counter); + feedback_start(ctx->fb, ctx->i2s_counter, ctx->microframes); ctx->i2s_counter = 0; } From 7981aeae6c093ac5c013b746497ad620e48d12b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Thu, 21 Aug 2025 09:38:40 +0200 Subject: [PATCH 2/8] [nrf fromtree] samples: usb: uac2: explicit: Fix SOF offset integer conversion glitch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework the formula used to convert timer CC values to SOF offset to eliminate a "division glitch" happening around SOF crossing, i.e. when the framestart shifts from being captured shortly before SOF to being captured shortly after SOF. When audio samples are consumed faster than nominal, i.e. when there is +1 samples every now and then, the reported SOF offset at High-Speed was going 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, "glitch" 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, ... With the fix the SOF offset goes as expected from 0 to -1, i.e. there is no jump from 0 to 7 around the SOF crossing and the reported SOF offset goes linearly (until it is correclty bumped from negative values back to positive values when +1 sample packet is transmitted on I2S). Signed-off-by: Tomasz Moń (cherry picked from commit 6bb4cb592a57a2adb891369b4171f9c171a6c526) --- .../usb/uac2_explicit_feedback/src/feedback_nrf.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c index 6ea9d2374d9..6b7ed239b26 100644 --- a/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c +++ b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c @@ -272,7 +272,7 @@ static void update_sof_offset(struct feedback_ctx *ctx, uint32_t sof_cc, int sof_offset; if (!IS_ENABLED(CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER)) { - uint32_t clks_per_edge; + uint32_t nominator; /* Convert timer clock (independent from both Audio clock and * USB host SOF clock) to fake sample clock shifted by P values. @@ -282,18 +282,17 @@ static void update_sof_offset(struct feedback_ctx *ctx, uint32_t sof_cc, * when regulated and therefore the relative clock frequency * discrepancies are essentially negligible. */ - clks_per_edge = sof_cc / ctx->counts_per_sof; - sof_cc /= MAX(clks_per_edge, 1); - framestart_cc /= MAX(clks_per_edge, 1); + nominator = MIN(sof_cc, framestart_cc) * ctx->counts_per_sof; + sof_offset = nominator / MAX(sof_cc, 1); + } else { + sof_offset = framestart_cc; } /* /2 because we treat the middle as a turning point from being * "too late" to "too early". */ - if (framestart_cc > ctx->counts_per_sof/2) { - sof_offset = framestart_cc - ctx->counts_per_sof; - } else { - sof_offset = framestart_cc; + if (sof_offset > ctx->counts_per_sof/2) { + sof_offset -= ctx->counts_per_sof; } /* The heuristic above is not enough when the offset gets too large. From 0020b12f0f8a6553b76e0b550fb3bf75f78f3aad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 29 Sep 2025 16:16:19 +0200 Subject: [PATCH 3/8] [nrf fromtree] drivers: serial: nrfx_uarte: Remove redundant pinctrl call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pinctrl call is redundant as uarte_periph_enable calls it as well. Signed-off-by: Krzysztof Chruściński (cherry picked from commit 7a6c7ea0f9462d7f924693396948b681ff92aada) --- drivers/serial/uart_nrfx_uarte.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 00489e7d885..ed354e3f2e5 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -3202,7 +3202,6 @@ static void uarte_pm_resume(const struct device *dev) const struct uarte_nrfx_config *cfg = dev->config; if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) || !LOW_POWER_ENABLED(cfg)) { - (void)pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); uarte_periph_enable(dev); } } From 067b1739066ac425c7a66f1f226ec1a5902d2100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bainczyk?= Date: Wed, 1 Oct 2025 11:22:21 +0200 Subject: [PATCH 4/8] [nrf fromlist] modules: hal_nordic: add new errno error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add macro for translating new errno error codes to strings. Upstream PR #: 96858 Signed-off-by: Michał Bainczyk --- modules/hal_nordic/nrfx/nrfx_glue.c | 22 ++++++++++++++++++++++ modules/hal_nordic/nrfx/nrfx_log.h | 10 ++++++++++ 2 files changed, 32 insertions(+) diff --git a/modules/hal_nordic/nrfx/nrfx_glue.c b/modules/hal_nordic/nrfx/nrfx_glue.c index 4e7fc94e11d..dd972ee039d 100644 --- a/modules/hal_nordic/nrfx/nrfx_glue.c +++ b/modules/hal_nordic/nrfx/nrfx_glue.c @@ -45,3 +45,25 @@ char const *nrfx_error_string_get(nrfx_err_t code) default: return "unknown"; } } + +char const *nrfx_new_error_string_get(int code) +{ + #define NRFX_NEW_ERROR_STRING_CASE(code) case code: return #code + switch (-code) + { + NRFX_NEW_ERROR_STRING_CASE(0); + NRFX_NEW_ERROR_STRING_CASE(ECANCELED); + NRFX_NEW_ERROR_STRING_CASE(ENOMEM); + NRFX_NEW_ERROR_STRING_CASE(ENOTSUP); + NRFX_NEW_ERROR_STRING_CASE(EINVAL); + NRFX_NEW_ERROR_STRING_CASE(EINPROGRESS); + NRFX_NEW_ERROR_STRING_CASE(E2BIG); + NRFX_NEW_ERROR_STRING_CASE(ETIMEDOUT); + NRFX_NEW_ERROR_STRING_CASE(EPERM); + NRFX_NEW_ERROR_STRING_CASE(EFAULT); + NRFX_NEW_ERROR_STRING_CASE(EACCES); + NRFX_NEW_ERROR_STRING_CASE(EBUSY); + NRFX_NEW_ERROR_STRING_CASE(EALREADY); + default: return "unknown"; + } +} diff --git a/modules/hal_nordic/nrfx/nrfx_log.h b/modules/hal_nordic/nrfx/nrfx_log.h index 682388d7dd1..973ca672b53 100644 --- a/modules/hal_nordic/nrfx/nrfx_log.h +++ b/modules/hal_nordic/nrfx/nrfx_log.h @@ -128,6 +128,16 @@ LOG_MODULE_REGISTER(NRFX_MODULE_PREFIX, NRFX_MODULE_LOG_LEVEL); #define NRFX_LOG_ERROR_STRING_GET(error_code) nrfx_error_string_get(error_code) extern char const *nrfx_error_string_get(nrfx_err_t code); +/** + * @brief Macro for getting the textual representation of a given errno error code. + * + * @param[in] error_code Errno error code. + * + * @return String containing the textual representation of the errno error code. + */ +#define NRFX_NEW_LOG_ERROR_STRING_GET(error_code) nrfx_new_error_string_get(error_code) +extern char const *nrfx_new_error_string_get(int code); + /** @} */ #ifdef __cplusplus From ef0988bf12fea8d3e01ab737db160656dc70e489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bainczyk?= Date: Fri, 3 Oct 2025 14:15:01 +0200 Subject: [PATCH 5/8] [nrf fromlist] modules: hal_nordic: remove TIMER config symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove TIMER config symbols to align to changes in nrfx driver. Upstream PR #: 96858 Signed-off-by: Michał Bainczyk --- modules/hal_nordic/nrfx/Kconfig | 130 +------------------------ modules/hal_nordic/nrfx/nrfx_kconfig.h | 78 --------------- 2 files changed, 2 insertions(+), 206 deletions(-) diff --git a/modules/hal_nordic/nrfx/Kconfig b/modules/hal_nordic/nrfx/Kconfig index 523931be649..30f1aac0607 100644 --- a/modules/hal_nordic/nrfx/Kconfig +++ b/modules/hal_nordic/nrfx/Kconfig @@ -279,8 +279,7 @@ config NRFX_MRAMC config NRFX_NFCT bool "NFCT driver" depends on $(dt_nodelabel_exists,nfct) - select NRFX_TIMER4 if SOC_SERIES_NRF52X - select NRFX_TIMER2 if SOC_SERIES_NRF53X + select NRFX_TIMER config NRFX_NVMC bool "NVMC driver" @@ -764,132 +763,7 @@ config NRFX_TEMP depends on $(dt_nodelabel_exists,temp) config NRFX_TIMER - bool - -config NRFX_TIMER0 - bool "TIMER0 driver instance" - depends on $(dt_nodelabel_exists,timer0) - select NRFX_TIMER - -config NRFX_TIMER1 - bool "TIMER1 driver instance" - depends on $(dt_nodelabel_exists,timer1) - select NRFX_TIMER - -config NRFX_TIMER2 - bool "TIMER2 driver instance" - depends on $(dt_nodelabel_exists,timer2) - select NRFX_TIMER - -config NRFX_TIMER3 - bool "TIMER3 driver instance" - depends on $(dt_nodelabel_exists,timer3) - select NRFX_TIMER - -config NRFX_TIMER4 - bool "TIMER4 driver instance" - depends on $(dt_nodelabel_exists,timer4) - select NRFX_TIMER - -config NRFX_TIMER00 - bool "TIMER00 driver instance" - depends on $(dt_nodelabel_exists,timer00) - select NRFX_TIMER - -config NRFX_TIMER10 - bool "TIMER10 driver instance" - depends on $(dt_nodelabel_exists,timer10) - select NRFX_TIMER - -config NRFX_TIMER20 - bool "TIMER20 driver instance" - depends on $(dt_nodelabel_exists,timer20) - select NRFX_TIMER - -config NRFX_TIMER21 - bool "TIMER21 driver instance" - depends on $(dt_nodelabel_exists,timer21) - select NRFX_TIMER - -config NRFX_TIMER22 - bool "TIMER22 driver instance" - depends on $(dt_nodelabel_exists,timer22) - select NRFX_TIMER - -config NRFX_TIMER23 - bool "TIMER23 driver instance" - depends on $(dt_nodelabel_exists,timer23) - select NRFX_TIMER - -config NRFX_TIMER24 - bool "TIMER24 driver instance" - depends on $(dt_nodelabel_exists,timer24) - select NRFX_TIMER - -config NRFX_TIMER020 - bool "TIMER020 driver instance" - depends on $(dt_nodelabel_exists,timer020) - select NRFX_TIMER - -config NRFX_TIMER021 - bool "TIMER021 driver instance" - depends on $(dt_nodelabel_exists,timer021) - select NRFX_TIMER - -config NRFX_TIMER022 - bool "TIMER022 driver instance" - depends on $(dt_nodelabel_exists,timer022) - select NRFX_TIMER - -config NRFX_TIMER120 - bool "TIMER120 driver instance" - depends on $(dt_nodelabel_exists,timer120) - select NRFX_TIMER - -config NRFX_TIMER121 - bool "TIMER121 driver instance" - depends on $(dt_nodelabel_exists,timer121) - select NRFX_TIMER - -config NRFX_TIMER130 - bool "TIMER130 driver instance" - depends on $(dt_nodelabel_exists,timer130) - select NRFX_TIMER - -config NRFX_TIMER131 - bool "TIMER131 driver instance" - depends on $(dt_nodelabel_exists,timer131) - select NRFX_TIMER - -config NRFX_TIMER132 - bool "TIMER132 driver instance" - depends on $(dt_nodelabel_exists,timer132) - select NRFX_TIMER - -config NRFX_TIMER133 - bool "TIMER133 driver instance" - depends on $(dt_nodelabel_exists,timer133) - select NRFX_TIMER - -config NRFX_TIMER134 - bool "TIMER134 driver instance" - depends on $(dt_nodelabel_exists,timer134) - select NRFX_TIMER - -config NRFX_TIMER135 - bool "TIMER135 driver instance" - depends on $(dt_nodelabel_exists,timer135) - select NRFX_TIMER - -config NRFX_TIMER136 - bool "TIMER136 driver instance" - depends on $(dt_nodelabel_exists,timer136) - select NRFX_TIMER - -config NRFX_TIMER137 - bool "TIMER137 driver instance" - depends on $(dt_nodelabel_exists,timer137) - select NRFX_TIMER + bool "TIMER driver" config NRFX_TWI bool diff --git a/modules/hal_nordic/nrfx/nrfx_kconfig.h b/modules/hal_nordic/nrfx/nrfx_kconfig.h index 4f0d594a212..c65a75cd0c6 100644 --- a/modules/hal_nordic/nrfx/nrfx_kconfig.h +++ b/modules/hal_nordic/nrfx/nrfx_kconfig.h @@ -659,84 +659,6 @@ #ifdef CONFIG_NRFX_TIMER #define NRFX_TIMER_ENABLED 1 #endif -#ifdef CONFIG_NRFX_TIMER_LOG -#define NRFX_TIMER_CONFIG_LOG_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER0 -#define NRFX_TIMER0_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER1 -#define NRFX_TIMER1_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER2 -#define NRFX_TIMER2_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER3 -#define NRFX_TIMER3_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER4 -#define NRFX_TIMER4_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER00 -#define NRFX_TIMER00_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER10 -#define NRFX_TIMER10_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER20 -#define NRFX_TIMER20_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER21 -#define NRFX_TIMER21_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER22 -#define NRFX_TIMER22_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER23 -#define NRFX_TIMER23_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER24 -#define NRFX_TIMER24_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER020 -#define NRFX_TIMER020_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER021 -#define NRFX_TIMER021_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER022 -#define NRFX_TIMER022_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER120 -#define NRFX_TIMER120_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER121 -#define NRFX_TIMER121_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER130 -#define NRFX_TIMER130_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER131 -#define NRFX_TIMER131_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER132 -#define NRFX_TIMER132_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER133 -#define NRFX_TIMER133_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER134 -#define NRFX_TIMER134_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER135 -#define NRFX_TIMER135_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER136 -#define NRFX_TIMER136_ENABLED 1 -#endif -#ifdef CONFIG_NRFX_TIMER137 -#define NRFX_TIMER137_ENABLED 1 -#endif #ifdef CONFIG_NRFX_TWI #define NRFX_TWI_ENABLED 1 From 852f4978e4bea1794bf1b4145f2541b916042db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bainczyk?= Date: Fri, 3 Oct 2025 14:17:11 +0200 Subject: [PATCH 6/8] [nrf fromlist] tests: drivers: uart: remove TIMER config symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove TIMER config symbols to align to changes in nrfx driver. Upstream PR #: 96858 Signed-off-by: Michał Bainczyk --- tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml | 2 +- tests/drivers/uart/uart_pm/testcase.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml index 0ba5944cca6..d481ed33adc 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml +++ b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml @@ -79,7 +79,7 @@ tests: - CONFIG_UART_0_ENHANCED_POLL_OUT=y - CONFIG_UART_0_NRF_HW_ASYNC=y - CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 - - CONFIG_NRFX_TIMER2=y + - CONFIG_NRFX_TIMER=y platform_allow: - nrf52840dk/nrf52840 - nrf5340dk/nrf5340/cpuapp diff --git a/tests/drivers/uart/uart_pm/testcase.yaml b/tests/drivers/uart/uart_pm/testcase.yaml index 008eae9d3d7..38da5dca480 100644 --- a/tests/drivers/uart/uart_pm/testcase.yaml +++ b/tests/drivers/uart/uart_pm/testcase.yaml @@ -78,7 +78,7 @@ tests: - CONFIG_UART_0_ASYNC=y - CONFIG_UART_0_NRF_HW_ASYNC=y - CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 - - CONFIG_NRFX_TIMER2=y + - CONFIG_NRFX_TIMER=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n drivers.uart.pm.async.enhanced_poll: @@ -88,7 +88,7 @@ tests: - CONFIG_UART_0_ASYNC=y - CONFIG_UART_0_NRF_HW_ASYNC=y - CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 - - CONFIG_NRFX_TIMER2=y + - CONFIG_NRFX_TIMER=y - CONFIG_UART_0_ENHANCED_POLL_OUT=y platform_exclude: - nrf54h20dk/nrf54h20/cpuapp From e5500c186188c5ffec0c5636ecf2eb6047e5bc51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bainczyk?= Date: Wed, 1 Oct 2025 15:00:15 +0200 Subject: [PATCH 7/8] [nrf fromlist] samples: usb: uac2: align feedback_nrf to changes in nrfx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Align feedback_nrf to changes in nrfx TIMER driver. Upstream PR #: 96858 Signed-off-by: Michał Bainczyk --- .../boards/nrf5340dk_nrf5340_cpuapp.conf | 2 +- .../boards/nrf54h20dk_nrf54h20_cpuapp.conf | 2 +- samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c | 4 ++-- .../boards/nrf5340dk_nrf5340_cpuapp.conf | 2 +- .../boards/nrf54h20dk_nrf54h20_cpuapp.conf | 2 +- samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf.c | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.conf index ce67033381a..4c7c060177e 100644 --- a/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.conf +++ b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -1,2 +1,2 @@ #Enable timer for asynchronous feedback -CONFIG_NRFX_TIMER2=y +CONFIG_NRFX_TIMER=y 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 index d7526fc6ec9..ce07cde3656 100644 --- a/samples/subsys/usb/uac2_explicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf +++ b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -1,4 +1,4 @@ # Enable timer for asynchronous feedback CONFIG_NRFX_GPPI=y -CONFIG_NRFX_TIMER131=y +CONFIG_NRFX_TIMER=y CONFIG_NRFX_GPIOTE130=y diff --git a/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c index 6b7ed239b26..860048acaf7 100644 --- a/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c +++ b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf.c @@ -63,8 +63,8 @@ static inline void feedback_target_init(void) 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); +static nrfx_timer_t feedback_timer_instance = + NRFX_TIMER_INSTANCE(NRF_TIMER_INST_GET(FEEDBACK_TIMER_INSTANCE_NUMBER)); /* See 5.12.4.2 Feedback in Universal Serial Bus Specification Revision 2.0 for * more information about the feedback. There is a direct implementation of the diff --git a/samples/subsys/usb/uac2_implicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/subsys/usb/uac2_implicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.conf index ce67033381a..4c7c060177e 100644 --- a/samples/subsys/usb/uac2_implicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.conf +++ b/samples/subsys/usb/uac2_implicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -1,2 +1,2 @@ #Enable timer for asynchronous feedback -CONFIG_NRFX_TIMER2=y +CONFIG_NRFX_TIMER=y 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 index c4e23e5d54f..3f9d5d61d28 100644 --- a/samples/subsys/usb/uac2_implicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf +++ b/samples/subsys/usb/uac2_implicit_feedback/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -1,3 +1,3 @@ # Enable timer for asynchronous feedback CONFIG_NRFX_GPPI=y -CONFIG_NRFX_TIMER131=y +CONFIG_NRFX_TIMER=y diff --git a/samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf.c b/samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf.c index 9623f22e566..9e8c2ac0342 100644 --- a/samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf.c +++ b/samples/subsys/usb/uac2_implicit_feedback/src/feedback_nrf.c @@ -51,8 +51,8 @@ static inline void feedback_target_init(void) #error "Unsupported target" #endif -static const nrfx_timer_t feedback_timer_instance = - NRFX_TIMER_INSTANCE(FEEDBACK_TIMER_INSTANCE_NUMBER); +static nrfx_timer_t feedback_timer_instance = + NRFX_TIMER_INSTANCE(NRF_TIMER_INST_GET(FEEDBACK_TIMER_INSTANCE_NUMBER)); /* While it might be possible to determine I2S FRAMESTART to USB SOF offset * entirely in software, the I2S API lacks appropriate timestamping. Therefore From 6803053113559f5922fcbbfd59206aea5104344a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bainczyk?= Date: Wed, 1 Oct 2025 15:02:08 +0200 Subject: [PATCH 8/8] [nrf noup] drivers: serial: uart_nrfx_uarte: align to changes in nrfx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Align driver to changes in nrfx UARTE driver. Conflicts with UART counting. Signed-off-by: Michał Bainczyk --- drivers/serial/Kconfig.nrfx | 35 -------------------------------- drivers/serial/uart_nrfx_uarte.c | 18 ++++++++-------- 2 files changed, 9 insertions(+), 44 deletions(-) diff --git a/drivers/serial/Kconfig.nrfx b/drivers/serial/Kconfig.nrfx index a39f882f644..1e5087dc1c1 100644 --- a/drivers/serial/Kconfig.nrfx +++ b/drivers/serial/Kconfig.nrfx @@ -213,39 +213,4 @@ nrfx_uart_num = 137 rsource "Kconfig.nrfx_uart_instance" endif -config NRFX_TIMER0 - default y - depends on UART_0_NRF_HW_ASYNC_TIMER = 0 \ - || UART_1_NRF_HW_ASYNC_TIMER = 0 \ - || UART_2_NRF_HW_ASYNC_TIMER = 0 \ - || UART_3_NRF_HW_ASYNC_TIMER = 0 - -config NRFX_TIMER1 - default y - depends on UART_0_NRF_HW_ASYNC_TIMER = 1 \ - || UART_1_NRF_HW_ASYNC_TIMER = 1 \ - || UART_2_NRF_HW_ASYNC_TIMER = 1 \ - || UART_3_NRF_HW_ASYNC_TIMER = 1 - -config NRFX_TIMER2 - default y - depends on UART_0_NRF_HW_ASYNC_TIMER = 2 \ - || UART_1_NRF_HW_ASYNC_TIMER = 2 \ - || UART_2_NRF_HW_ASYNC_TIMER = 2 \ - || UART_3_NRF_HW_ASYNC_TIMER = 2 - -config NRFX_TIMER3 - default y - depends on UART_0_NRF_HW_ASYNC_TIMER = 3 \ - || UART_1_NRF_HW_ASYNC_TIMER = 3 \ - || UART_2_NRF_HW_ASYNC_TIMER = 3 \ - || UART_3_NRF_HW_ASYNC_TIMER = 3 - -config NRFX_TIMER4 - default y - depends on UART_0_NRF_HW_ASYNC_TIMER = 4 \ - || UART_1_NRF_HW_ASYNC_TIMER = 4 \ - || UART_2_NRF_HW_ASYNC_TIMER = 4 \ - || UART_3_NRF_HW_ASYNC_TIMER = 4 - endif # UART_NRFX diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index ed354e3f2e5..084e6592f27 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -306,6 +306,7 @@ struct uarte_nrfx_data { #endif #ifdef UARTE_ANY_ASYNC struct uarte_async_cb *async; + nrfx_timer_t timer; #endif atomic_val_t poll_out_lock; atomic_t flags; @@ -448,7 +449,6 @@ struct uarte_nrfx_config { size_t bounce_buf_swap_len; struct uarte_async_rx_cbwt *cbwt_data; #endif - nrfx_timer_t timer; uint8_t *tx_cache; uint8_t *rx_flush_buf; #endif @@ -878,7 +878,7 @@ static void uarte_periph_enable(const struct device *dev) #ifdef UARTE_ANY_ASYNC if (data->async) { if (HW_RX_COUNTING_ENABLED(config)) { - const nrfx_timer_t *timer = &config->timer; + nrfx_timer_t *timer = &data->timer; nrfx_timer_enable(timer); @@ -1067,13 +1067,13 @@ static int uarte_nrfx_rx_counting_init(const struct device *dev) if (HW_RX_COUNTING_ENABLED(cfg)) { nrfx_timer_config_t tmr_config = NRFX_TIMER_DEFAULT_CONFIG( - NRF_TIMER_BASE_FREQUENCY_GET(cfg->timer.p_reg)); + NRF_TIMER_BASE_FREQUENCY_GET(data->timer.p_reg)); uint32_t evt_addr = nrf_uarte_event_address_get(uarte, NRF_UARTE_EVENT_RXDRDY); - uint32_t tsk_addr = nrfx_timer_task_address_get(&cfg->timer, NRF_TIMER_TASK_COUNT); + uint32_t tsk_addr = nrfx_timer_task_address_get(&data->timer, NRF_TIMER_TASK_COUNT); tmr_config.mode = NRF_TIMER_MODE_COUNTER; tmr_config.bit_width = NRF_TIMER_BIT_WIDTH_32; - ret = nrfx_timer_init(&cfg->timer, + ret = nrfx_timer_init(&data->timer, &tmr_config, timer_handler); if (ret != NRFX_SUCCESS) { @@ -1081,12 +1081,12 @@ static int uarte_nrfx_rx_counting_init(const struct device *dev) return -EINVAL; } - nrfx_timer_clear(&cfg->timer); + nrfx_timer_clear(&data->timer); ret = nrfx_gppi_channel_alloc(&data->async->rx.cnt.ppi); if (ret != NRFX_SUCCESS) { LOG_ERR("Failed to allocate PPI Channel"); - nrfx_timer_uninit(&cfg->timer); + nrfx_timer_uninit(&data->timer); return -EINVAL; } @@ -3639,8 +3639,8 @@ static int uarte_instance_deinit(const struct device *dev) IF_ENABLED(CONFIG_UARTE_NRFX_UARTE_COUNT_BYTES_WITH_TIMER, \ (UARTE_COUNT_BYTES_WITH_TIMER_CONFIG(idx))) \ IF_ENABLED(CONFIG_UART_##idx##_NRF_HW_ASYNC, \ - (.timer = NRFX_TIMER_INSTANCE( \ - CONFIG_UART_##idx##_NRF_HW_ASYNC_TIMER),)) \ + (.timer = NRFX_TIMER_INSTANCE(NRF_TIMER_INST_GET( \ + CONFIG_UART_##idx##_NRF_HW_ASYNC_TIMER)),)) \ IF_ENABLED(INSTANCE_IS_FAST(_, /*empty*/, idx, _), \ (.clk_dev = DEVICE_DT_GET_OR_NULL(DT_CLOCKS_CTLR(UARTE(idx))), \ .clk_spec = { \