Running SAADC in continuous mode without timer/ppi trigger

Hi All,

I have problem running nRF5340 in continuous mode without any external trigger (timer/ppi). I would like to setup SAADC so that last conversion triggered new set of conversions.

I'm using nrfx_saadc_advanced_mode_set function with internal_timer_cc set to 0 and start_on_end to true. Then I setup two buffers (primary and secondary) and then call nrfx_saadc_mode_trigger.

With that configuration I get irq handler called with NRF_SAADC_EVENT_STARTED, but not get NRF_SAADC_EVENT_END which I believe should restart conversion with provided configuration.

Can you point me what I'm doing wrong?

Parents Reply Children
  • I'm using advanced mode because I need to fill buffer with couple of samples from each channel. As I understand in simple mode I'm going to get only one sample per each channel.

    I'm using nrfx_saadc_mode_trigger to trigger conversion, I forgot to mention that in previous post. Attaching code snippet might be hard as I'm doing stuff in different places of code.

  • You still need to trigger the SAMPLE task externally when internal_timer_cc is set to 0, even it you call nrfx_saadc_mode_trigger(). This is from the SAADC driver API documentation:

    "When performing conversions in the non-blocking manner and nrfx_saadc_adv_config_t::internal_timer_cc is set to 0, sampling needs to be done by triggering NRF_SAADC_TASK_SAMPLE externally (for example by using the TIMER and/or the PPI/DPPI)."

    If you do not want to use PPI, you can trigger it in your application similar to how the driver does it for the blocking mode:

    nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_SAMPLE);

  • Hi,

    I have created sample code below with two channels setup. It works when ADC_BUFFER_SIZE is set to 2. This defines buffer size for samples. I get NRFX_SAADC_EVT_READY in first callback and then alternately NRFX_SAADC_EVT_DONE and NRFX_SAADC_EVT_BUF_REQ.

    However, when i changed ADC_BUFFER_SIZE to 4 (to fit 2 samples for each channel) I only get NRFX_SAADC_EVT_READY and don't have any samples. I expected to get NRFX_SAADC_EVT_DONE twice and then one NRFX_SAADC_EVT_BUF_REQ. Can you tell me why buffer size can't be bigger than number of channels?

    #include <kernel.h>
    #include <nrfx_saadc.h>
    
    #define ADC_BUFFER_SIZE 2
    static nrf_saadc_value_t adcBuffer[2][ADC_BUFFER_SIZE];
    
    uint8_t currentBuffer = 0;
    
    static void adcCallback( nrfx_saadc_evt_t const * p_event )
    {
        nrfx_saadc_evt_type_t eventType = p_event->type;
    
        switch( eventType )
        {
            case NRFX_SAADC_EVT_DONE:
            {
                nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_SAMPLE);
            }
            break;
    
            case NRFX_SAADC_EVT_LIMIT:
            {
            }
            break;
    
            case NRFX_SAADC_EVT_CALIBRATEDONE:
            {
            }
            break;
    
            case NRFX_SAADC_EVT_BUF_REQ:
            {
                nrfx_saadc_buffer_set( adcBuffer[currentBuffer], ADC_BUFFER_SIZE );
                ++currentBuffer;
                currentBuffer = currentBuffer % 2;
            }
            break;
    
            case NRFX_SAADC_EVT_READY:
            {
                nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_SAMPLE);
            }
            break;
    
            case NRFX_SAADC_EVT_FINISHED:
            {
            }
            break;
        }
    }
    
    /*!
     * @brief Application entry point.
     */
    int main( int argc, char** argv )
    {
        printk("ADC example on %s\n", CONFIG_BOARD);
    
        nrfx_saadc_channel_t channelConfig = {
            .channel_config =
                {
                    .resistor_p = NRF_SAADC_RESISTOR_DISABLED,
                    .resistor_n = NRF_SAADC_RESISTOR_DISABLED,
                    .gain       = NRF_SAADC_GAIN1_4,
                    .reference  = SAADC_CH_CONFIG_REFSEL_VDD1_4,
                    .acq_time   = SAADC_CH_CONFIG_TACQ_40us,
                    .mode       = NRF_SAADC_MODE_SINGLE_ENDED,
                    .burst      = NRF_SAADC_BURST_DISABLED,
                },
                .pin_p          = NRF_SAADC_INPUT_AIN0,
                .pin_n          = NRF_SAADC_INPUT_DISABLED,
                .channel_index  = 0
        };
    
        nrfx_saadc_adv_config_t adcAdvancedConfig = NRFX_SAADC_DEFAULT_ADV_CONFIG;
        adcAdvancedConfig.start_on_end = true;
    
        nrfx_err_t nrfxError = nrfx_saadc_init( 0 );
    
        IRQ_DIRECT_CONNECT( SAADC_IRQn, 0, nrfx_saadc_irq_handler, IRQ_ZERO_LATENCY );
    
        // First channel.
        nrfxError = nrfx_saadc_channel_config( &channelConfig );
    
        // Second channel.
        channelConfig.pin_p = NRF_SAADC_INPUT_AIN1;
        channelConfig.channel_index = 1;
    
        nrfxError = nrfx_saadc_channel_config( &channelConfig );
        nrfxError = nrfx_saadc_advanced_mode_set( 0x03, NRF_SAADC_RESOLUTION_12BIT, &adcAdvancedConfig, adcCallback );
    
        // Set buffers.
        nrfxError = nrfx_saadc_buffer_set( adcBuffer[0], ADC_BUFFER_SIZE );
        nrfxError = nrfx_saadc_buffer_set( adcBuffer[1], ADC_BUFFER_SIZE );
    
        // Trigger conversion.
        nrfxError = nrfx_saadc_mode_trigger();
    
        while( 1 )
        {
            printk( "ADC1: p_buffer = %d\n", adcBuffer[currentBuffer][0] );
            printk( "ADC2: p_buffer = %d\n", adcBuffer[currentBuffer][1] );
            k_msleep( 1000 );
        };
    
        return 0;
    }

  • Hi,

    You need to trigger the SAMPLE task once for each time the SAADC should sample each enabled channel once. If you set the buffer size to 2xnum_enabled_channels, you need to trigger the SAMPLE task twice for the buffer to be filled and the END event to be generated by the SAADC peripheral. The DONE event from the peripheral is only used when doing oversampling with burst. The NRFX_SAADC_EVT_DONE event from the driver is only triggered by the END event from the peripheral. The naming is maybe a bit confusing, as DONE from the driver does not correspond to the DONE event from the peripheral.

    You need to trigger the SAMPLE task twice, with a delay in between corresponding to num_enabled_channels x (configured acquisition time + conversion time).

    Best regards,
    Jørgen

Related