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

Sampling SAADC channels at different rate

There have been a couple of questions asked that are similar to my question but in the interest of getting more clarity I am asking a new one as others have had accepted answers.

The relevant questions are here and here

Essentially, using the scan mode of SAADC on nRF52, is it possible to sample two inputs at different sampling frequencies? Assume that I want channel0 sampled at 500Hz and channel1 at 2Hz. What is the best way forward without adding to the current consumption?

In the accepted answer of this question, it is said that using PSELP to enable/disable channel and configuring RESULT.MAXCNT is one way. Is it possible to have a code snippet or pseudocode explaining this?

  • I will see if I can throw together an example. The below preudocode should show the concept and how it can be implemented:

    #define CHANNEL_0_SAMPLE_FREQUENCY 500
    #define CHANNEL_1_SAMPLE_FREQUENCY 2
    
    #define SAMPLES_IN_BUFFER CHANNEL_0_SAMPLE_FREQUENCY + CHANNEL_1_SAMPLE_FREQUENCY
    
    uint32_t sample_count = 0;
    
    void saadc_sample(){
    
        NRF_SAADC->TASKS_START = 1;
        while (NRF_SAADC->EVENTS_STARTED == 0);
        NRF_SAADC->EVENTS_STARTED = 0;
    
        NRF_SAADC->TASKS_SAMPLE = 1;
        while (NRF_SAADC->EVENTS_END == 0);
        NRF_SAADC->EVENTS_END = 0;
    }
    
    rtc0_handler()
    {
    	saadc_sample();
    	
    	if (sample_count == max(CHANNEL_0_SAMPLE_FREQUENCY,CHANNEL_1_SAMPLE_FREQUENCY)/min(CHANNEL_0_SAMPLE_FREQUENCY,CHANNEL_1_SAMPLE_FREQUENCY)-1)
    	{
    		NRF_SAADC->CH[1].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput1 << SAADC_CH_PSELP_PSELP_Pos;
    	}
    	
    	if(sample_count == max(CHANNEL_0_SAMPLE_FREQUENCY,CHANNEL_1_SAMPLE_FREQUENCY)/min(CHANNEL_0_SAMPLE_FREQUENCY,CHANNEL_1_SAMPLE_FREQUENCY))
    	{
    		NRF_SAADC->CH[1].PSELP = SAADC_CH_PSELN_PSELN_NC << SAADC_CH_PSELP_PSELP_Pos;
    		sample_count = 0;
    	}
    	
    	sample_count++;
    }
    
    saadc_init()
    {
    
    	// Configure SAADC channel 0 
    	
    	NRF_SAADC->CH[0].CONFIG = (
    		SAADC_CH_CONFIG_BURST_Enabled << SAADC_CH_CONFIG_BURST_Pos |
    		SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos |
    		SAADC_CH_CONFIG_TACQ_10us << SAADC_CH_CONFIG_TACQ_Pos |
    		SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_TACQ_Pos |
    		SAADC_CH_CONFIG_GAIN_Gain1_4 << SAADC_CH_CONFIG_GAIN_Pos |
    		SAADC_CH_CONFIG_RESN_Bypass << SAADC_CH_CONFIG_RESN_Pos |
    		SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESP_Pos );
    
    	NRF_SAADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput0 << SAADC_CH_PSELP_PSELP_Pos;
    	NRF_SAADC->CH[0].PSELN = SAADC_CH_PSELN_PSELN_NC << SAADC_CH_PSELN_PSELN_Pos;
    	
    	// Configure SAADC channel 1, but leave it not connected
    	
    	NRF_SAADC->CH[1].CONFIG = (
    		SAADC_CH_CONFIG_BURST_Enabled << SAADC_CH_CONFIG_BURST_Pos |
    		SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos |
    		SAADC_CH_CONFIG_TACQ_10us << SAADC_CH_CONFIG_TACQ_Pos |
    		SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_TACQ_Pos |
    		SAADC_CH_CONFIG_GAIN_Gain1_4 << SAADC_CH_CONFIG_GAIN_Pos |
    		SAADC_CH_CONFIG_RESN_Bypass << SAADC_CH_CONFIG_RESN_Pos |
    		SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESP_Pos );
    
    	
    	NRF_SAADC->CH[1].PSELP = SAADC_CH_PSELP_PSELP_NC << SAADC_CH_PSELP_PSELP_Pos;
    	NRF_SAADC->CH[1].PSELN = SAADC_CH_PSELN_PSELN_NC << SAADC_CH_PSELN_PSELN_Pos;
    	
    	/* Number of Sample Count*/
        NRF_SAADC->RESULT.MAXCNT = SAMPLES_IN_BUFFER;
    }
    
    rtc_init()
    {
    	// Configure RTC to run at sample rate of fastest SAADC channel 
    }
    
    
    main () 
    {
    	saadc_init();
    	rtc_init();
    	
    	while(1)
    	{
    		// Make sure any pending events are cleared
    		__SEV();
    		__WFE();
    		// Enter System ON sleep mode
    		__WFE();  
    	}
    }
    
  • Thanks for this. I am going to try and integrate this in my existing code and report back soon.

  • Does the ADC buffer size needs to be changed when modifying PSELP in the rtc0_handler?

  • As you see in the code, the buffer size is set to the 502 (addition of the two sample rates). The buffer will then be filled every second and you do not need to change it when enabling/disabling the second channel.

Related