Configure sampling rate for nrf5340 SAADC

I'm working on the nrf5340 with a modified sample found here (main.c of the base sample here) and nrf connect sdk 1.7.1

I see that adc_sequence_options .interval_us can set the time between samples in microseconds, so I tried to use that to set my sampling rate like so:

const struct adc_sequence_options sequence_opts = {
	.interval_us = 17, // 17 us between 1000 samples
	.callback = NULL,
	.user_data = NULL,
	.extra_samplings = BUFFER_SIZE - 1,
};

, but the board prints Error in adc sampling: -16.

Is there a way to either resolve my interval_us bug or another way to configure the sampling rate?

Thanks

Parents
  • Hello,

    What function is it that returns -16? I see that it is adc_read(), but have you tried to investigate inside adc_read() to see why it returns -16?

    Also, did you do any modifications to the sample? Or is it exactly like the one I can download from the github that you refer to?

    Best regards,

    Edvin

  • Hi Edvin,

    I searched the entire solution for the print statement, but nothing came up and I couldnt find what was returning the -16.  (I am using SEGGER studios)

    Its almost identical to the github, I modified it to read from pin 5 instead of pin 4: #define ADC_1ST_CHANNEL_ID 1

    and I use the math library (math.h) to use some functions(sqrt, powf) on the samples I receive.

    Again, I am open to other methods of setting the sampling rate.

    Thanks for the help,

    Janpaul

  • Hello Janpaul,

    I did some digging. The unmodified sample from the github seems to work well, but when you set the sampling rate to 17µs it seems to return an error. I tried to set it to 100µs (0.1ms), and in that case the error was not returned. I tried to debug, and traced it down to:

    static inline int adc_context_wait_for_completion(struct adc_context *ctx)
    {
    #ifdef CONFIG_ADC_ASYNC
    	if (ctx->asynchronous) {
    		return 0;
    	}
    #endif /* CONFIG_ADC_ASYNC */
    
    	k_sem_take(&ctx->sync, K_FOREVER);
    	return ctx->status;
    }

    in adc_context.h.

    It is the return ctx->status that returns -16.

    I see that this probably happens because of this function (same file):

    static inline void adc_context_complete(struct adc_context *ctx, int status)
    {
    #ifdef CONFIG_ADC_ASYNC
    	if (ctx->asynchronous) {
    		if (ctx->signal) {
    			k_poll_signal_raise(ctx->signal, status);
    		}
    
    		k_sem_give(&ctx->lock);
    		return;
    	}
    #endif /* CONFIG_ADC_ASYNC */
    
    	/*
    	 * Override the status only when an error is signaled to this function.
    	 * Please note that adc_context_request_next_sampling() might have set
    	 * this field.
    	 */
    	if (status != 0) {
    		ctx->status = status;
    	}
    	k_sem_give(&ctx->sync);
    }

    which again can comes from this:

    static inline void adc_context_request_next_sampling(struct adc_context *ctx)
    {
    	if (atomic_inc(&ctx->sampling_requested) == 0) {
    		adc_context_start_sampling(ctx);
    	} else {
    		/*
    		 * If a sampling was already requested and was not finished yet,
    		 * do not start another one from here, this will be done from
    		 * adc_context_on_sampling_done() after the current sampling is
    		 * complete. Instead, note this fact, and inform the user about
    		 * it after the sequence is done.
    		 */
    		ctx->status = -EBUSY;
    	}
    }

    So the issue is that the new sample is requested before the previous sample is done. The sequence_options.interval_us is too small. 

    Do you particularly need an interval_us of 17, or was this a random test? The maximum sample rate of the ADC is 200kHz, so theoretically, it is possible to sample every 5µs, but not using the zephyr adc drivers. In that case I believe you would need to use the adc drivers directly. 

    Let me know if you really need that short interval, or if that was just a test.

    Best regards,

    Edvin

  • Hi Edvin,

    thank you for your digging. I was  digging to a bit in VS Code debugger SDK Connect 1.9.1 on nRF5340DK with example code 

    https://github.com/too1/ncs-peripheral-uart-adc/tree/d575cdb9a2e0d7e5f0984a6a228bcb0d3a6f1a7c

    The only thing I had to chang for proper build and flash was the LOG_WRN() to simple printk(), afterwards got ADC raw value: 426 , 425 or 427

    I built up some voltagefollower opamp circuit and adjust (by poti VDD to GND) the output to 2.5V and measured with my multimeter.

    Should be 512 by 10bit resolution, so i changed ADC definitions to ADC_GAIN_1 and ADC_REFERENCE to ADC_REF_VDD_1.

    Now adc_read() output err is -22 and raw value is 0

    By digging I found 

    	switch (channel_cfg->reference) {
    	case ADC_REF_INTERNAL:
    		config.reference = NRF_SAADC_REFERENCE_INTERNAL;
    		break;
    	case ADC_REF_VDD_1_4:
    		config.reference = NRF_SAADC_REFERENCE_VDD4;
    		break;
    	
    	default:
    		printk("Selected ADC reference is not valid\n");		//LOG_ERR
    		return -EINVAL;
    	}

    wanted to write the case for ADC_REF_VDD_1 by myself but in the nrf_saadc.h file

    /** @brief Reference selection for the analog-to-digital converter. */
    typedef enum
    {
        NRF_SAADC_REFERENCE_INTERNAL = SAADC_CH_CONFIG_REFSEL_Internal, ///< Internal reference (0.6 V).
        NRF_SAADC_REFERENCE_VDD4     = SAADC_CH_CONFIG_REFSEL_VDD1_4    ///< VDD/4 as reference.
        
    } nrf_saadc_reference_t;

    also no definition in the typdef enum ... why is this? Do I write all by myself or is ther better example ?

    My purpose: I have some analog signal amplification PCB and would like to digitize by nRF controller and send by BLE. The signal should be sampled by around 10-20us (10kHz of interrest, nyquist and so on). I would appreciate so much for some example code Slight smile

    would like to differentialy measure the signal to REF2.5 from the opamp pcb board, is the best way to measure differential mode or just single but referenced to REF2.5 through other AIN pin?

    Many thanks in advance,

    Christoph

Reply
  • Hi Edvin,

    thank you for your digging. I was  digging to a bit in VS Code debugger SDK Connect 1.9.1 on nRF5340DK with example code 

    https://github.com/too1/ncs-peripheral-uart-adc/tree/d575cdb9a2e0d7e5f0984a6a228bcb0d3a6f1a7c

    The only thing I had to chang for proper build and flash was the LOG_WRN() to simple printk(), afterwards got ADC raw value: 426 , 425 or 427

    I built up some voltagefollower opamp circuit and adjust (by poti VDD to GND) the output to 2.5V and measured with my multimeter.

    Should be 512 by 10bit resolution, so i changed ADC definitions to ADC_GAIN_1 and ADC_REFERENCE to ADC_REF_VDD_1.

    Now adc_read() output err is -22 and raw value is 0

    By digging I found 

    	switch (channel_cfg->reference) {
    	case ADC_REF_INTERNAL:
    		config.reference = NRF_SAADC_REFERENCE_INTERNAL;
    		break;
    	case ADC_REF_VDD_1_4:
    		config.reference = NRF_SAADC_REFERENCE_VDD4;
    		break;
    	
    	default:
    		printk("Selected ADC reference is not valid\n");		//LOG_ERR
    		return -EINVAL;
    	}

    wanted to write the case for ADC_REF_VDD_1 by myself but in the nrf_saadc.h file

    /** @brief Reference selection for the analog-to-digital converter. */
    typedef enum
    {
        NRF_SAADC_REFERENCE_INTERNAL = SAADC_CH_CONFIG_REFSEL_Internal, ///< Internal reference (0.6 V).
        NRF_SAADC_REFERENCE_VDD4     = SAADC_CH_CONFIG_REFSEL_VDD1_4    ///< VDD/4 as reference.
        
    } nrf_saadc_reference_t;

    also no definition in the typdef enum ... why is this? Do I write all by myself or is ther better example ?

    My purpose: I have some analog signal amplification PCB and would like to digitize by nRF controller and send by BLE. The signal should be sampled by around 10-20us (10kHz of interrest, nyquist and so on). I would appreciate so much for some example code Slight smile

    would like to differentialy measure the signal to REF2.5 from the opamp pcb board, is the best way to measure differential mode or just single but referenced to REF2.5 through other AIN pin?

    Many thanks in advance,

    Christoph

Children
Related