This builds on a previous Forum Post that was closed out.
There is a peculiar issue with the NRF52840 SAADC sampling. For an unknown reason, triggering the SAMPLE Task in the SAADC only triggers the collection sequence in the SAADC (on continuous) if there is a while loop with a bit of trivial code in it (if empty, it does not work).
Note, other code elsewhere in the program runs normally (Nowhere else are there interrupts, other than a 40Hz TIMER4); it is the SAADC_IRQHandler_v that never triggers. Also, note this is a configuration with interrupts.
As you can see in the code below, interrupts are enabled at priority 3 (unsigned long), I am just unsure what could cause the SAADC to stall like that and never send the END update (nor collect any ADC reads).
// Contains the (16-bit) results for the SAADC - volatile buffer constexpr uint16_t NUM_SAADC_RESULT_BUFFERS = 40; constexpr uint16_t SAADC_RESULT_BUFFER_SIZE = 1024; volatile nrf_saadc_value_t SAADC_RESULT_BUFFER[NUM_SAADC_RESULT_BUFFERS * SAADC_RESULT_BUFFER_SIZE]; // Start the transmission bool START_TRANSMISSION = false; // Buffer index (For the SAADC Buffers) uint32_t BUFFER_INDEX = 0; /** * SAADC IRQ Handler: Weak Link to be taken here and triggered during END event in SAADC (Enabled elsewhere) */ extern "C" void SAADC_IRQHandler_v( void ) { // Check to see if the ADC has filled up the result buffer if (nrf_saadc_event_check(NRF_SAADC_EVENT_END)) { nrf_saadc_event_clear(NRF_SAADC_EVENT_END); // Clear the "END" event START_TRANSMISSION = true; // Start transmission BUFFER_INDEX = BUFFER_INDEX >= NUM_SAADC_RESULT_BUFFERS - 1 ? 0 : BUFFER_INDEX + 1; } } static void configure_saadc_channel_2() { // Configure A1 & A2 channel as differential nrf_saadc_channel_config_t channel_config = { .resistor_p = NRF_SAADC_RESISTOR_DISABLED, .resistor_n = NRF_SAADC_RESISTOR_DISABLED, .gain = NRF_SAADC_GAIN1_6, .reference = NRF_SAADC_REFERENCE_INTERNAL, .acq_time = NRF_SAADC_ACQTIME_3US, .mode = NRF_SAADC_MODE_DIFFERENTIAL, .burst = NRF_SAADC_BURST_DISABLED, .pin_p = NRF_SAADC_INPUT_AIN2, .pin_n = NRF_SAADC_INPUT_AIN3 }; // Configure the NRF CH[1] to values above // CH[1] is used instead of CH[0] because CH[0] is used during the analogRead Arduino API Function NRF_SAADC->CH[1].CONFIG = ((channel_config.resistor_p << SAADC_CH_CONFIG_RESP_Pos) & SAADC_CH_CONFIG_RESP_Msk) | ((channel_config.resistor_n << SAADC_CH_CONFIG_RESN_Pos) & SAADC_CH_CONFIG_RESN_Msk) | ((channel_config.gain << SAADC_CH_CONFIG_GAIN_Pos) & SAADC_CH_CONFIG_GAIN_Msk) | ((channel_config.reference << SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk) | ((channel_config.acq_time << SAADC_CH_CONFIG_TACQ_Pos) & SAADC_CH_CONFIG_TACQ_Msk) | ((channel_config.mode << SAADC_CH_CONFIG_MODE_Pos) & SAADC_CH_CONFIG_MODE_Msk) | ((channel_config.burst << SAADC_CH_CONFIG_BURST_Pos) & SAADC_CH_CONFIG_BURST_Msk); // Configure the Negative & Positive Ends of CH[1] NRF_SAADC->CH[1].PSELN = channel_config.pin_n; NRF_SAADC->CH[1].PSELP = channel_config.pin_p; } inline void sample_voltage() { nrf_saadc_task_trigger(NRF_SAADC_TASK_START); // Start the ADC and prepare the result buffer in RAM. nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE); } static void configure_saadc_channels() { nrf_saadc_disable(); // Configure each SAADC Channel // Note: Channel 1 (CH[0]) is not used as it is reserved for analogRead functionality // through Arduino's platform. configure_saadc_channel_2(); // Configure the resolution NRF_SAADC->RESOLUTION = NRF_SAADC_RESOLUTION_12BIT; // 12-bit - 14-bit attainable only through oversampling // Disable oversampling //NRF_SAADC->OVERSAMPLE = NRF_SAADC_OVERSAMPLE_DISABLED; // Enable Continuous Mode & set to 16MHz / 400 (CC) NRF_SAADC->SAMPLERATE = (SAADC_SAMPLERATE_MODE_Timers << SAADC_SAMPLERATE_MODE_Pos) | ((uint32_t)400 << SAADC_SAMPLERATE_CC_Pos); // Configure RESULT Buffer and MAXCNT NRF_SAADC->RESULT.PTR = (uint32_t)SAADC_RESULT_BUFFER; NRF_SAADC->RESULT.MAXCNT = SAADC_RESULT_BUFFER_SIZE; // Enable the SAADC IRQ NRF_SAADC->EVENTS_END = 0; nrf_saadc_int_enable( NRF_SAADC_INT_END ); // Set the END mask to an interrupt NVIC_SetPriority( SAADC_IRQn, 3UL ); NVIC_EnableIRQ( SAADC_IRQn ); nrf_saadc_enable(); // Enable the SAADC // Calibrate the SAADC by finding its offset NRF_SAADC->TASKS_CALIBRATEOFFSET = 1; while (NRF_SAADC->EVENTS_CALIBRATEDONE == 0); NRF_SAADC->EVENTS_CALIBRATEDONE = 0; while (NRF_SAADC->STATUS == (SAADC_STATUS_STATUS_Busy << SAADC_STATUS_STATUS_Pos)); } static uint32_t inline collect_adc_data() { nrf_saadc_disable(); NRF_SAADC->RESULT.PTR = (uint32_t)(SAADC_RESULT_BUFFER + (BUFFER_INDEX * SAADC_RESULT_BUFFER_SIZE)); nrf_saadc_enable(); // Enable the SAADC sample_voltage(); } void setup() { collect_adc_data(); }