This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nrf52 SAADC - NRFX_SAADC_EVT_DONE never called

using nRF5SDK 160098a08e2

I have the following code:

#define ADC_NOF_SAMPLES 16u
static int16_t s_sample_buffer[ ADC_NOF_SAMPLES ];
static nrf_saadc_channel_config_t const s_adc_channel0 = NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE( NRF_SAADC_INPUT_AIN5 );
static void saadc_event_isr( nrfx_saadc_evt_t const *p_event )
{
    volatile uint32_t numOfSamples = 0;
    switch ( p_event->type )
    {
    case NRFX_SAADC_EVT_DONE:  // Event generated when the buffer is filled with samples.
        numOfSamples = p_event->data.done.size;
        break;
    case NRFX_SAADC_EVT_LIMIT: // Event generated after one of the limits is reached.
        break;
    case NRFX_SAADC_EVT_CALIBRATEDONE: // Event generated when the calibration is complete.
        {
            nrfx_err_t err;
            err = nrfx_saadc_buffer_convert( &s_sample_buffer[0], ADC_NOF_SAMPLES );
            APP_ERROR_CHECK(err);
            /*err = nrfx_saadc_sample();
            APP_ERROR_CHECK(err);*/
        }
        break;
    default:
        break;
    }
}

    nrfx_err_t err;
    static nrfx_saadc_config_t const s_saadc_config = {
            .resolution = NRF_SAADC_RESOLUTION_12BIT,
            .oversample = NRF_SAADC_OVERSAMPLE_256X,
            .interrupt_priority = NRFX_SAADC_CONFIG_IRQ_PRIORITY,
            .low_power_mode = false
    };

    // ADC driver is initialized in non-blocking mode, since an event handler is given
    err = nrfx_saadc_init( &s_saadc_config, saadc_event_isr );

    if ( err == NRFX_SUCCESS )
    {
        // Initialize the ADC channel 0
        err = nrfx_saadc_channel_init( 0, &s_adc_channel0 );

        if ( err == NRFX_SUCCESS )
        {
            /*
            * Calibrate the offset with a call to nrfx_saadc_calibrate_offset.
            * You need to wait for the SAADCs DONE event before you can proceed.
            * */
            do
            {
                err = nrfx_saadc_calibrate_offset();
            } while ( err == NRFX_ERROR_BUSY );

            rc = 1u;
        }
    }



I never receive NRFX_SAADC_EVT_DONE. Please advise

  • Hello,

    BardenDK said:
    Thank you for your support and patience

    It is no problem at all, I am happy to help! :) 

    BardenDK said:
    No i do not use a timer. I did not expect that it was needed. The app_timer is initialized and never used. I run FreeRTOS as RTOS and this uses RTC2 for ticks

    I understand. If you want the sampling to happen on a certain interval, you will have to use a timer or event of some kind. Otherwise, the SAADC will not have any reference as to when and how often it should be sampling.

    BardenDK said:
    All this ADC i have tested is run through calls from main.

    Is the results as expected when you call the sample function multiple times from main? Does the events trigger as expected?
    If this is the case, I suspect that the issue is with the aforementioned need for a timer or event.

    BardenDK said:
    I dont want to load the CPU with interriputs and thats why i wanted to DMA and expected the system to be able to handle this in the way it is described in API documentation.

    Please link me the API documentation you are referring to, and tell me what parts did not work as expected.

    BardenDK said:
    I need to at least make 128 samples pr. second and calculate all samples when done. So (128 / 16) pr second.

    This seems very reasonable, and a perfect task for a timer based SAADC. For reference, the SAADC example I have linked you earlier does exactly this; the example demonstrates the setup and use of a timer with the SAADC. You seem uninterested in this example, is this due to a constraint on your application that I am unaware of?

    BardenDK said:

    I want to start the ADC sequence and get an interrupt/event when 16 samples have been made, i.e. the sample buffer is full.

    Is this possible ?

    Yes, this is possible. As you have seen in the documentation, the DONE event will trigger when the buffer is full. However, the problem seems to me to stem from a lack of sampling being done. If the sampling is not tied to an event or timer, then it will not happen(unless you call it manually), and as such the buffer will not fill up - which means you will not get the DONE event.

    Bear in mind, I might be wrong in my suspicion since I have only seen snippets from different places in the code, but I hope this is helpful to you.


    Best regards,
    Karl

     

  • Hi Karl,

    Thank you for your reply.

    This seems very reasonable, and a perfect task for a timer based SAADC. For reference, the SAADC example I have linked you earlier does exactly this; the example demonstrates the setup and use of a timer with the SAADC. You seem uninterested in this example, is this due to a constraint on your application that I am unaware of?

    I think I will refer to it again. I had hoped it was possible to achieve the ADC conversion in a less CPU intensive manor. So i tried to chase a solution that could make use of DMA transfer and just give an interrupt when completed. This is the behavior of the system i am porting our application from.

    Please link me the API documentation you are referring to, and tell me what parts did not work as expected.
    nrfx_saadc_buffer_convert()
    Quote: "This function is non-blocking. The application is notified about filling the buffer by the event handler. Conversion will be done on all enabled channels. If the SAADC is in idle state, the function will set up EasyDMA for the conversion. The SAADC will be ready for sampling and wait for the SAMPLE task. It can be triggered manually by the nrfx_saadc_sample function or by PPI using the NRF_SAADC_TASK_SAMPLE task "
    and this:
    nrfx_saadc_sample()
    Quote: "Function for starting the SAADC sampling."
    It is not stated in the above that i must call nrfx_saadc_sample() for each sample i want. This is further confused by the fact that i thought this function would behave differently than nrfx_saadc_sample_convert() which only does 1 sample.
    quote: "Blocking function for executing a single SAADC conversion. "
    So my advise is that you expand the API description to mention, that only 1 sample is done.
  • To close this issue. I have refered to the SAADC example and used TIMER1 (softdevice uses TIMER0).

    I have setup the timer to meet my sampling frequency and have confirmed i get the expected results.

    Thank you Karl for your support.

    maybe Nordic should consider to clarify that the nrfx_saadc_sample() only causes sampling of 1 sample and not the number of samples configured via nrfx_saadc_buffer_convert()

  • Hi,

    BardenDK said:
    I think I will refer to it again. I had hoped it was possible to achieve the ADC conversion in a less CPU intensive manor. So i tried to chase a solution that could make use of DMA transfer and just give an interrupt when completed. This is the behavior of the system i am porting our application from.

    Yes, please refer to it again and let me know if you found it useful for you implementation. As mentioned, the SAADC example pretty much demonstrates exactly the functionality you are describing - it sets up a timed interval for sampling, and outputs the data on the DONE event.
    If you are afraid of missing samples during the DONE event handling, you could make use of the double-buffer feature(which is also demonstrated in the SAADC example).
    In that case, the second buffer will start filling immediately upon DONE event for the first buffer.

    In any case, the buffer_convert function makes use of the EasyDMA functionality. That is to say, if you in each callback from the DONE event call the saadc_buffer_convert again, with a new/incremented buffer, that buffer will be filled with the following conversions done by saadc_sample(). Is this perhaps the functionality you were looking for? 

    BardenDK said:
    It is not stated in the above that i must call nrfx_saadc_sample() for each sample i want. This is further confused by the fact that i thought this function would behave differently than nrfx_saadc_sample_convert() which only does 1 sample.

    You do not have to call nrfx_saadc_sample in your main() for each sample, if the SAADC is connected to trigger on a certain interval or event, such as a timer, or any other interrupt. Please see the SAADC examples function saadc_sampling_event_init(), it demonstrates how to set up a timer to trigger at a given frequency, enable PPI,  and finally: how to connect the saadc sampling to the created timer using PPI. It sounds to me like this is exactly this functionality you are missing.

    BardenDK said:
    So my advise is that you expand the API description to mention, that only 1 sample is done.

    I can understand why you would think that. The nrfx_saadc_buffer_convert actually does not do any conversions, but rather designates the location to which the nrfx_saadc_sample will output. I see how the naming and accompanying API reference could be interpreted ambiguously here, my apologies.

    nrfx_saadc_sample_convert however does behave quite differently than the nrfx_saadc_sample. As written in the API reference, they both perform a single sampling, but the difference is that nrfx_saadc_sample is non-blockingwhile nrfx_saadc_sample_convert is blocking.

    In short: nrfx_saadc_sample triggers a single non-blocking sampling, which is placed in the buffer specified by nrfx_saacd_buffer_convert.
    nrfx_saadc_sample_convert on the other hand is blocking, for one sample, to be placed in the location specified in its second function parameter.

    I hope this could provide some clarity, and I am looking forward to hearing how you progress with your application! :) 

    Best regards,
    Karl

  • BardenDK said:
    Thank you Karl for your support.

    No problem at all! I am happy we could figure this out together and get your application to work as expected.

    BardenDK said:
    maybe Nordic should consider to clarify that the nrfx_saadc_sample() only causes sampling of 1 sample and not the number of samples configured via nrfx_saadc_buffer_convert()

    Yes, we will improve the function naming and accompanying API reference in the future.

    Best regards,
    Karl

Related