Hello,
I am trying to measure a fast, impulsive signal from an amplified analog microphone using an ADC pin on the nRF54L15-DK. When I read the same signal using a 12-bit analog input on an Arduino board (ESP32 Feather V2), the waveform behaves as expected and spans nearly the full ADC range (0–4095). However, when reading the signal at 8 kHz with the SAADC on the nRF54L15-DK at 12-bit resolution, the waveform appears clipped and consistently maxes out at around ~2150 counts (see plots below).


To rule out range or reference limitations, I applied a static DC voltage to the same nRF ADC pin (approximately 3.0 V from a bench supply). In this case, the SAADC reads correctly (~3400 counts), confirming that the ADC can measure higher voltages and that the issue is specific to fast transient signals. I also swept the acquisition time from 2 µs to 40 µs, but the impulse signal still clips at ~2150 counts for all acquisition times tested.
The SAADC input is configured as single-ended with 12-bit resolution, using the internal reference and a gain of 1/4, with oversampling and burst mode disabled. The relevant ADC sampling code is included below.#define SAMPLE_PERIOD_US 125
/* ------------------ SAADC Setup ------------------ */
static int16_t saadc_sample;
#define NRF_SAADC_INPUT_AIN2 NRF_PIN_PORT_TO_PIN_NUMBER(6U, 1)
#define SAADC_INPUT_PIN NRF_SAADC_INPUT_AIN2
static nrfx_saadc_channel_t channel = NRFX_SAADC_DEFAULT_CHANNEL_SE(SAADC_INPUT_PIN, 0);
int saadc_setup(void)
{
nrfx_err_t err;
IRQ_CONNECT(DT_IRQN(DT_NODELABEL(adc)), DT_IRQ(DT_NODELABEL(adc), priority), nrfx_isr, nrfx_saadc_irq_handler, 0);
err = nrfx_saadc_init(DT_IRQ(DT_NODELABEL(adc), priority));
if (err != NRFX_SUCCESS) return -1;
channel.channel_config.gain = NRF_SAADC_GAIN1_4;
err = nrfx_saadc_channels_config(&channel, 1);
if (err != NRFX_SUCCESS) return -1;
nrfx_saadc_adv_config_t adv = NRFX_SAADC_DEFAULT_ADV_CONFIG;
err = nrfx_saadc_advanced_mode_set(BIT(0), NRF_SAADC_RESOLUTION_12BIT, &adv, saadc_event_handler);
if (err != NRFX_SUCCESS) return -1;
/* Single-sample buffer */
err = nrfx_saadc_buffer_set(&saadc_sample, 1);
if (err != NRFX_SUCCESS) return -1;
/* Arm SAADC (sampling still triggered by PPI) */
nrfx_saadc_mode_trigger();
return 0;
}
/* ------------------ GPPI wiring ------------------ */
int gppi_setup(void)
{
/* ---------------- GPPI: GRTC compare -> SAADC SAMPLE ---------------- */
uint8_t ppi_sample;
nrfx_gppi_channel_alloc(&ppi_sample);
uint32_t grtc_evt_addr = controller_time_trigger_event_addr_get();
uint32_t saadc_start = nrf_saadc_task_address_get(NRF_SAADC, NRF_SAADC_TASK_START);
uint32_t saadc_sample = nrf_saadc_task_address_get(NRF_SAADC, NRF_SAADC_TASK_SAMPLE);
nrfx_gppi_channel_endpoints_setup(ppi_sample, grtc_evt_addr, saadc_start);
nrfx_gppi_fork_endpoint_setup(ppi_sample, saadc_sample);
nrfx_gppi_channels_enable(BIT(ppi_sample));
/* ---------------- GPPI: SAADC END -> GRTC CAPTURE ---------------- */
uint8_t ppi_capture;
nrfx_gppi_channel_alloc(&ppi_capture);
uint32_t adc_end_evt = nrf_saadc_event_address_get(NRF_SAADC, NRF_SAADC_EVENT_END);
uint32_t grtc_capture_task = controller_time_capture_task_addr_get();
nrfx_gppi_channel_endpoints_setup(ppi_capture, adc_end_evt, grtc_capture_task);
nrfx_gppi_channels_enable(BIT(ppi_capture));
/* ---------------- Setup first compare ---------------- */
uint64_t now = controller_time_us_get();
uint64_t next_cc = now + SAMPLE_PERIOD_US;
controller_time_trigger_set(next_cc);
return 0;
}
/* ------------------ SAADC event handler ------------------ */
static void saadc_event_handler(nrfx_saadc_evt_t const * p_event)
{
if (p_event->type == NRFX_SAADC_EVT_DONE) {
uint64_t prev_trigger = controller_trigger_time_us_get();
controller_time_trigger_set(prev_trigger + SAMPLE_PERIOD_US);
uint64_t ts = controller_capture_time_us_get();
int16_t sample = saadc_sample;
printk("%d\n", sample);
push_sample_into_circular_buffer(sample, ts);
/* Re-arm buffer */
nrfx_saadc_buffer_set(&saadc_sample, 1);
}
}
Do you have any recommendations on how to fix this issue? Thanks for any help you're able to provide.