Setup:
Device: nRF52840DK PCA10056
Software: NCS v1.3.99
What I am trying to do:
I have 3 SAADC sequences that I need to run for my application that I wish to poll periodically.
1. 1 input (single ended), 16x oversampling, 14bit
2. 1 input (single ended), 8x oversampling, 10bit
3. 3 inputs (2 single ended, 1 differential), no oversampling, 10bit
What is going wrong:
After running each sequence once, #3 from above hangs waiting for the END event, and sometimes the START event.
Code Isolating the Bug:
#include <zephyr.h>
#include <device.h>
#include <sys/printk.h>
#include <nrfx_saadc.h>
#include <hal/nrf_saadc.h>
#include <nrf52840.h>
#include <nrf52840_bitfields.h>
volatile int sampling = 0;
uint16_t buf0 = 0;
uint16_t buf1 = 0;
uint16_t buf2[3] = {0};
static void saadc_irq_handler(void *param)
{
if (nrf_saadc_event_check(NRF_SAADC, NRF_SAADC_EVENT_END)) {
nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_END);
nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_STOP);
nrf_saadc_disable(NRF_SAADC);
sampling = 0;
}
if (nrf_saadc_event_check(NRF_SAADC,
NRF_SAADC_EVENT_CALIBRATEDONE))
{
nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_CALIBRATEDONE);
nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_STOP);
nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_START);
}
if (nrf_saadc_event_check(NRF_SAADC,
NRF_SAADC_EVENT_STARTED))
{
nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_STARTED);
nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_SAMPLE);
}
}
void setup_saadc()
{
nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_END);
nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_CALIBRATEDONE);
nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_END);
nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_CALIBRATEDONE);
nrf_saadc_int_enable(NRF_SAADC,
NRF_SAADC_INT_END | NRF_SAADC_INT_CALIBRATEDONE | NRF_SAADC_INT_STARTED);
NRFX_IRQ_ENABLE(SAADC_IRQn);
IRQ_CONNECT(SAADC_IRQn, 1,
saadc_irq_handler, NULL, 0);
}
void config0()
{
NRF_SAADC->OVERSAMPLE = NRF_SAADC_OVERSAMPLE_16X;
NRF_SAADC->RESOLUTION = NRF_SAADC_RESOLUTION_14BIT;
NRF_SAADC->CH[0].CONFIG =
((NRF_SAADC_RESISTOR_DISABLED << SAADC_CH_CONFIG_RESP_Pos) & SAADC_CH_CONFIG_RESP_Msk)
| ((NRF_SAADC_RESISTOR_DISABLED << SAADC_CH_CONFIG_RESN_Pos) & SAADC_CH_CONFIG_RESN_Msk)
| ((NRF_SAADC_GAIN1_2 << SAADC_CH_CONFIG_GAIN_Pos) & SAADC_CH_CONFIG_GAIN_Msk)
| ((NRF_SAADC_REFERENCE_INTERNAL<< SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk)
| ((NRF_SAADC_ACQTIME_40US << SAADC_CH_CONFIG_TACQ_Pos) & SAADC_CH_CONFIG_TACQ_Msk)
| ((NRF_SAADC_MODE_SINGLE_ENDED << SAADC_CH_CONFIG_MODE_Pos) & SAADC_CH_CONFIG_MODE_Msk)
| ((NRF_SAADC_BURST_ENABLED << SAADC_CH_CONFIG_BURST_Pos) & SAADC_CH_CONFIG_BURST_Msk);
NRF_SAADC->CH[0].PSELP = NRF_SAADC_INPUT_AIN0;
NRF_SAADC->CH[0].PSELN = NRF_SAADC_INPUT_DISABLED;
NRF_SAADC->RESULT.MAXCNT = 1;
NRF_SAADC->RESULT.PTR = (uint32_t)&buf0;
}
void config1()
{
NRF_SAADC->OVERSAMPLE = NRF_SAADC_OVERSAMPLE_8X;
NRF_SAADC->RESOLUTION = NRF_SAADC_RESOLUTION_10BIT;
NRF_SAADC->CH[1].CONFIG =
((NRF_SAADC_RESISTOR_DISABLED << SAADC_CH_CONFIG_RESP_Pos) & SAADC_CH_CONFIG_RESP_Msk)
| ((NRF_SAADC_RESISTOR_DISABLED << SAADC_CH_CONFIG_RESN_Pos) & SAADC_CH_CONFIG_RESN_Msk)
| ((NRF_SAADC_GAIN1_4 << SAADC_CH_CONFIG_GAIN_Pos) & SAADC_CH_CONFIG_GAIN_Msk)
| ((NRF_SAADC_REFERENCE_INTERNAL<< SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk)
| ((NRF_SAADC_ACQTIME_10US << SAADC_CH_CONFIG_TACQ_Pos) & SAADC_CH_CONFIG_TACQ_Msk)
| ((NRF_SAADC_MODE_SINGLE_ENDED << SAADC_CH_CONFIG_MODE_Pos) & SAADC_CH_CONFIG_MODE_Msk)
| ((NRF_SAADC_BURST_ENABLED << SAADC_CH_CONFIG_BURST_Pos) & SAADC_CH_CONFIG_BURST_Msk);
NRF_SAADC->CH[1].PSELP = NRF_SAADC_INPUT_AIN1;
NRF_SAADC->CH[1].PSELN = NRF_SAADC_INPUT_DISABLED;
NRF_SAADC->RESULT.MAXCNT = 1;
NRF_SAADC->RESULT.PTR = (uint32_t)&buf1;
}
void config2()
{
NRF_SAADC->OVERSAMPLE = NRF_SAADC_OVERSAMPLE_DISABLED;
NRF_SAADC->RESOLUTION = NRF_SAADC_RESOLUTION_10BIT;
NRF_SAADC->CH[2].CONFIG =
((NRF_SAADC_RESISTOR_DISABLED << SAADC_CH_CONFIG_RESP_Pos) & SAADC_CH_CONFIG_RESP_Msk)
| ((NRF_SAADC_RESISTOR_DISABLED << SAADC_CH_CONFIG_RESN_Pos) & SAADC_CH_CONFIG_RESN_Msk)
| ((NRF_SAADC_GAIN1_6 << SAADC_CH_CONFIG_GAIN_Pos) & SAADC_CH_CONFIG_GAIN_Msk)
| ((NRF_SAADC_REFERENCE_INTERNAL<< SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk)
| ((NRF_SAADC_ACQTIME_40US << SAADC_CH_CONFIG_TACQ_Pos) & SAADC_CH_CONFIG_TACQ_Msk)
| ((NRF_SAADC_MODE_SINGLE_ENDED << SAADC_CH_CONFIG_MODE_Pos) & SAADC_CH_CONFIG_MODE_Msk)
| ((NRF_SAADC_BURST_DISABLED << SAADC_CH_CONFIG_BURST_Pos) & SAADC_CH_CONFIG_BURST_Msk);
NRF_SAADC->CH[2].PSELP = NRF_SAADC_INPUT_AIN2;
NRF_SAADC->CH[2].PSELN = NRF_SAADC_INPUT_DISABLED;
NRF_SAADC->CH[3].CONFIG =
((NRF_SAADC_RESISTOR_DISABLED << SAADC_CH_CONFIG_RESP_Pos) & SAADC_CH_CONFIG_RESP_Msk)
| ((NRF_SAADC_RESISTOR_DISABLED << SAADC_CH_CONFIG_RESN_Pos) & SAADC_CH_CONFIG_RESN_Msk)
| ((NRF_SAADC_GAIN1_6 << SAADC_CH_CONFIG_GAIN_Pos) & SAADC_CH_CONFIG_GAIN_Msk)
| ((NRF_SAADC_REFERENCE_INTERNAL<< SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk)
| ((NRF_SAADC_ACQTIME_40US << SAADC_CH_CONFIG_TACQ_Pos) & SAADC_CH_CONFIG_TACQ_Msk)
| ((NRF_SAADC_MODE_SINGLE_ENDED << SAADC_CH_CONFIG_MODE_Pos) & SAADC_CH_CONFIG_MODE_Msk)
| ((NRF_SAADC_BURST_DISABLED << SAADC_CH_CONFIG_BURST_Pos) & SAADC_CH_CONFIG_BURST_Msk);
NRF_SAADC->CH[3].PSELP = NRF_SAADC_INPUT_AIN3;
NRF_SAADC->CH[3].PSELN = NRF_SAADC_INPUT_DISABLED;
NRF_SAADC->CH[4].CONFIG =
((NRF_SAADC_RESISTOR_DISABLED << SAADC_CH_CONFIG_RESP_Pos) & SAADC_CH_CONFIG_RESP_Msk)
| ((NRF_SAADC_RESISTOR_DISABLED << SAADC_CH_CONFIG_RESN_Pos) & SAADC_CH_CONFIG_RESN_Msk)
| ((NRF_SAADC_GAIN1_6 << SAADC_CH_CONFIG_GAIN_Pos) & SAADC_CH_CONFIG_GAIN_Msk)
| ((NRF_SAADC_REFERENCE_INTERNAL<< SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk)
| ((NRF_SAADC_ACQTIME_40US << SAADC_CH_CONFIG_TACQ_Pos) & SAADC_CH_CONFIG_TACQ_Msk)
| ((NRF_SAADC_MODE_DIFFERENTIAL << SAADC_CH_CONFIG_MODE_Pos) & SAADC_CH_CONFIG_MODE_Msk)
| ((NRF_SAADC_BURST_DISABLED << SAADC_CH_CONFIG_BURST_Pos) & SAADC_CH_CONFIG_BURST_Msk);
NRF_SAADC->CH[4].PSELP = NRF_SAADC_INPUT_AIN4;
NRF_SAADC->CH[4].PSELN = NRF_SAADC_INPUT_AIN5;
NRF_SAADC->RESULT.MAXCNT = sizeof(buf2)/sizeof(buf2[0]);
NRF_SAADC->RESULT.PTR = (uint32_t)buf2;
}
void clear_configs()
{
for (int i = 0; i < 8; i++)
{
NRF_SAADC->CH[i].PSELP = NRF_SAADC_INPUT_DISABLED;
}
}
void sample_saadc_blocking()
{
sampling = 1;
NRF_SAADC->ENABLE = 1;
NRF_SAADC->TASKS_CALIBRATEOFFSET = 1;
while (sampling)
{
k_sleep(K_MSEC(10));
}
}
int main(void)
{
printk("Begin Test\n");
setup_saadc();
for (int i = 0; ; i++)
{
printk("\ni = %d\n",i);
clear_configs();
config0();
sample_saadc_blocking();
printk("seq0\n");
clear_configs();
config1();
sample_saadc_blocking();
printk("seq1\n");
clear_configs();
config2();
sample_saadc_blocking();
printk("seq2\n");
}
return 0;
}
Console Output:
*** Booting Zephyr OS version 2.3.99 ***
Begin Test
i = 0
seq0
seq1
seq2
i = 1
seq0
seq1