Hi Nordic team,
I’m working on the nRF54L15 DK with the SAADC peripheral and have encountered an issue when enabling noise shaping.
Here’s the setup:
- Platform: nRF54L15 DK
- SAADC resolution: 12-bit
- Input range: Single-ended input, 0~VDD (3.3V)
- Gain setting: 1/4
- Sampling rate: 10k samples/sec
- Buffer size: 1 sample (streamed continuously using TIMER + GPPI)
- Mode: Advanced mode with noise shaping enabled (NRF_SAADC->NOISESHAPE = 1)
After converting the signed 12-bit samples to unsigned using 2’s complement mapping, I expected a clean sine wave ranging from 0 to 4095.
However, the resulting waveform contains occasional sharp spikes, which seem to appear periodically or randomly and do not correspond to the analog input signal.
Here is an example of the output waveform plotted in Excel:

To eliminate data conversion issues, I also tried printing the raw signed values directly, and the spikes were already present before conversion.
Here’s what I’ve verified so far:
- Without noise shaping, the waveform is clean and matches the input.
- With noise shaping, the overall shape is correct, but spikes appear.
- Spikes occur even when the input is a low-noise sine wave (from a function generator).
I’m wondering:
- Is this expected behavior when using noise shaping on the nRF54L15 SAADC?
- Are there any known limitations or special considerations when using noise shaping with TIMER + PPI triggering?
- Is there a recommended method to reduce or filter these spikes in software or hardware?
The code i use is attached
Any insights or suggestions would be greatly appreciated.
Thanks in advance!
static void saadc_event_handler(nrfx_saadc_evt_t const * p_event)
{
nrfx_err_t err;
switch (p_event->type)
{
case NRFX_SAADC_EVT_READY:
nrfx_timer_enable(&timer_instance);
break;
case NRFX_SAADC_EVT_BUF_REQ:
err = nrfx_saadc_buffer_set(saadc_sample_buffer[(saadc_current_buffer++)%2], SAADC_BUFFER_SIZE);
//err = nrfx_saadc_buffer_set(saadc_sample_buffer[((saadc_current_buffer == 0 )? saadc_current_buffer++ : 0)], SAADC_BUFFER_SIZE);
if (err != NRFX_SUCCESS) {
LOG_ERR("nrfx_saadc_buffer_set error: %08x", err);
return;
}
break;
case NRFX_SAADC_EVT_DONE:
int64_t average = 1;
int16_t max = INT16_MIN;
int16_t min = INT16_MAX;
int16_t current_value;
//LOG_INF("SAADC buffer at 0x%x filled with %d samples", (uint32_t)p_event->data.done.p_buffer, p_event->data.done.size);
//printk("ADC Samples:\n");
for (int i = 0; i < p_event->data.done.size; i++) {
current_value = ((int16_t *)(p_event->data.done.p_buffer))[i];
uint16_t unsigned_val = (current_value < 0)?(uint16_t)(current_value + 4096):(uint16_t)(current_value);
average += current_value;
if (current_value > max) max = current_value;
if (current_value < min) min = current_value;
printk("%d\n", unsigned_val);
}
average /= p_event->data.done.size;
//printk("\nAVG=%d, MIN=%d, MAX=%d\n", (int16_t)average, min, max);
break;
default:
LOG_INF("Unhandled SAADC evt %d", p_event->type);
break;
}
}
static void configure_saadc(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) {
LOG_ERR("nrfx_saadc_init error: %08x", err);
return;
}
NRF_SAADC->NOISESHAPE = 1;
#if defined(CONFIG_SOC_NRF54L15)
channel.channel_config.gain = NRF_SAADC_GAIN1_4;
#else
channel.channel_config.gain = NRF_SAADC_GAIN1_4;
#endif
err = nrfx_saadc_channels_config(&channel, 1);
if (err != NRFX_SUCCESS) {
LOG_ERR("nrfx_saadc_channels_config error: %08x", err);
return;
}
nrfx_saadc_adv_config_t saadc_adv_config = NRFX_SAADC_DEFAULT_ADV_CONFIG;
err = nrfx_saadc_advanced_mode_set(BIT(0),
NRF_SAADC_RESOLUTION_12BIT,
&saadc_adv_config,
saadc_event_handler);
if (err != NRFX_SUCCESS) {
LOG_ERR("nrfx_saadc_advanced_mode_set error: %08x", err);
return;
}
err = nrfx_saadc_buffer_set(saadc_sample_buffer[0], SAADC_BUFFER_SIZE);
if (err != NRFX_SUCCESS) {
LOG_ERR("nrfx_saadc_buffer_set error: %08x", err);
return;
}
err = nrfx_saadc_buffer_set(saadc_sample_buffer[1], SAADC_BUFFER_SIZE);
if (err != NRFX_SUCCESS) {
LOG_ERR("nrfx_saadc_buffer_set error: %08x", err);
return;
}
err = nrfx_saadc_mode_trigger();
if (err != NRFX_SUCCESS) {
LOG_ERR("nrfx_saadc_mode_trigger error: %08x", err);
return;
}
}
Best regards,
Kyle Anderson






