Hello,
I developed a script which has a 40Hz timer which repeatedly starts the NRF52840's SAADC in continuous mode (with a 40kHz rate) which is supposed to fill a revolving buffer in RAM while my CPU does other activities.
An interrupt is then triggered at the end of the ADC collection (SAADC "END" EVENT), which notifies the CPU to send out those ADC values either Serially or through BLE (working through that later).
My snippet implementation is below. The issue I am having right now is that no samples are being read into the buffer, and I confirmed this further by regularly checking the SAADC's RESULT.AMOUNT register which stayed at zero indefinitely. I also verified that the STARTED EVENT was triggered, just no samples are being read despite the SAADC being set to continuous mode.
Any ideas?
// 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. } 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(); }