Issues measuring fast signals on the nRF54L15-DK ADC

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.

Parents Reply Children
No Data
Related