This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

ADC Continuous Sampling Issue - NRF52840 on Nano 33

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();
}

Parents
  • Hello,

    I notice that you are triggering the START task in your sample_voltage function - could you change this to TASKS_SAMPLE?
    The START task only starts the SAADC and prepares the result buffer - it does not actually perform a conversion. While the continuous mode issues its own SAMPLE tasks using the internal timer, it seems to need to have the sequence started by the SAMPLE task.

    I have created an internal ticket with our developers to have this reviewed and highlighted in the documentation if confirmed.

    Please also be aware of the Errata 237 for the nRF52840's SAADC when using the SAADC peripheral directly.

    Best regards,
    Karl

  • Hi Karl,

    I may have accidentally locked this ticket. I responded to your above question in a message 1hr ago.

    Best

Reply Children
No Data
Related