Consecutive ADC PPI triggered by RTC1 offset problem - ADC event trigger on the wrong sample

Hi All

I am using S130, nRF51822, SDK12, My RTC1 compare events is connected by PPI to ADC, I have set it to generate an adc_ppi_event_handler after 6 consecutive compare events, or after 2 events of 3 consecutive samples (so I get 2 adc_ppi_event_handler events for 6 compare events), this usually works fine, I count the NRF_RTC1->EVENTS_COMPARE[2] at the RTC1_IRQHandler to see I get a total of 6 samples, expect to count 6 events from beginning of the process and I assure I counted until 6 when I get my adc_ppi_event_handler.

Lately I encounter a bug in which the ADC fails to properly get 6 sample counts at the point of adc_ppi_event_handler , I was able to recreate this and saw using a scope a change in behavior, the adc_ppi_event_handler event actually is triggered, for example, after the 5th compare events, sometimes there is a different offset, as if there was already one sample in the buffer when the process began. I recreated the problem by purposely interfering with the RTC-compare register during sampling process, I am not sure what causes those offset or interfere with the register when I am not the one generating the problem through a backdoor, it takes a lot of time for it to happen "naturally".

I would like to know 

1. if you have any idea of what causes it and how can I prevent it.

2. How can I reset the adc-ppi-rtc1 cycle, and eliminate this "offset".

Would appreciate any help, ideas and inputs

Thanks!

  • Hi,

    The only thing that comes to mind is that the ADC interrupt handler is not able to read out the result before the next sample is triggered by PPI, for instance if it is blocked by the softdevice.

    What is the sample interval? Can you post the code you used for configuring the ADC and PPI?

    Best regards,
    Jørgen

  • Hi Jørgen

    Thank you for your answer

    the sample interval is about 10msec.

    I am adding below some of the relevant code

    Aside for suggestion on possible cause, I would like to know how can I reset the process, buffer etc.., I am thinking about just resetting the ADC-PPI before every time I start sampling to make it more robust, I mean how do I reset the PPI to believe the buffer is empty and to assure starting from 0 every new 6 sample cycle.

    Thanks again and best regards

    Ron

    --------------------------

    This is the configuration code

    #define ADC_BUFFER_SIZE 								6  
    nrf_adc_value_t          		adc_buffer[ADC_BUFFER_SIZE];
    
    static void adc_ppi_config(void)
    {
        ret_code_t ret_code;
    	
        //Initialize ADC
        nrf_drv_adc_config_t config = NRF_DRV_ADC_DEFAULT_CONFIG;
        ret_code = nrf_drv_adc_init(&config, adc_ppi_event_handler);
        APP_ERROR_CHECK(ret_code);
    	
        m_channel_0_config.config.config.input = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD;
        m_channel_1_config.config.config.input = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD;	
        
        nrf_drv_adc_channel_enable(&m_channel_0_config);
        nrf_drv_adc_channel_enable(&m_channel_1_config);
        
    }
    
    void rtc1_cc_enable(void)
    {
    	
      NRF_RTC1->EVTENSET = RTC_EVTENSET_COMPARE0_Msk | RTC_EVTENSET_COMPARE1_Msk | RTC_EVTENSET_COMPARE2_Msk;
      NRF_RTC1->INTENSET = RTC_INTENSET_COMPARE0_Msk | RTC_EVTENSET_COMPARE1_Msk | RTC_EVTENSET_COMPARE2_Msk;
    	
      NVIC_ClearPendingIRQ(RTC1_IRQn);
      NVIC_EnableIRQ(RTC1_IRQn);
      NRF_RTC1->TASKS_START = 1;
    	
    }
    
    void adc_ppi_sampling_event_init(void)
    {
        ret_code_t err_code;
    	
        uint32_t timer_compare_event_addr = (uint32_t)&NRF_RTC1->EVENTS_COMPARE[2];	//connect adc ppi to rtc1 as clock source
        uint32_t adc_sample_event_addr = nrf_drv_adc_start_task_get();
    
        /* setup ppi channel so that timer compare event is triggering sample task in SAADC */
        err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
        APP_ERROR_CHECK(err_code);
        
        err_code = nrf_drv_ppi_channel_assign(m_ppi_channel, timer_compare_event_addr, adc_sample_event_addr);  //NRF_ADC->TASKS_START);
        APP_ERROR_CHECK(err_code);
    }
    
    void adc_ppi_sampling_event_enable(void)
    {
        ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);
        APP_ERROR_CHECK(err_code);
    }
    
    void adc_ppi_init(void)
    {
    	rtc1_cc_enable();
    	
        adc_ppi_sampling_event_init();
    	
        adc_ppi_config();
    	
        adc_ppi_sampling_event_enable();
    	
    	APP_ERROR_CHECK(nrf_drv_adc_buffer_convert(adc_buffer,ADC_BUFFER_SIZE));
    }

    And this is how I trigger the process

    #define ADC_PPI_RTC_INTERVAL 30
    
    void RTC1_IRQHandler(void)
    {
    	 NRF_RTC1->EVENTS_COMPARE[0] = 0;
    	 NRF_RTC1->EVENTS_COMPARE[1] = 0;
    	 NRF_RTC1->EVENTS_COMPARE[3] = 0;
    
    		if ((NRF_RTC1->EVENTS_COMPARE[2] != 0) && (rtc1_main_init_flag))
    		{
    
    				rtc1_c2_counter++;
    	
    				NRF_RTC1->EVENTS_COMPARE[2] = 0;
    			
    				if (rtc1_c2_counter >= ADC_BUFFER_SIZE)
    				{
    					rtc1_c2_counter = 0;
    				}			
    				else
    				{
    					NRF_RTC1->CC[2] = add_rtc_offset(0x20*10);
    				}
    		}
    		else
    		{
    			NRF_RTC1->EVENTS_COMPARE[2] = 0;
    		}	
    
        NRF_RTC1->EVENTS_TICK       = 0;
        NRF_RTC1->EVENTS_OVRFLW     = 0;
        
        // Check for expired timers
        timer_timeouts_check();
    }
    
    uint32_t add_rtc_offset(uint32_t offset)	
    {
    		uint32_t rtc_current;
    		uint32_t rtc_updated;
    
    		rtc_current = NRF_RTC1->COUNTER;
    	
    		if ((rtc_current + offset) > RTC1_MAX)
    		{
    			rtc_updated = offset - (RTC1_MAX - rtc_current) ;
    		}
    		else
    		{
    			rtc_updated = rtc_current + offset;
    		}
    					
    		return(rtc_updated);
    }
    
    void rtc1_ChanOffset(uint8_t chan, uint32_t offset)	
    {
    	NRF_RTC1->CC[chan] = add_rtc_offset(0x20*offset);
    	rtc1_c2_counter = 0;
    }
    
    rtc1_ChanOffset(2,ADC_PPI_RTC_INTERVAL);

  • Hi,

    PPI does not have any awareness of the state of the ADC buffers and sample counts, this is simply a hardware signal going from an EVENT generated by one peripheral to a TASK of another peripheral. 

    The ADC in nRF51 series ICs also does not have any buffering functionality for the ADC, every sample needs to be read out from the peripheral by the CPU, before the next sample can be started. Storing of multiple samples into a single buffer is handled by the ADC driver. 

    When you say "resetting the ADC-PPI before every time I start sampling", when exactly do plan to do this? Do you start the RTC at a given time to start sampling, i.e., it does not sample continuously into 6 sample buffers? There seems to be no APIs to stop an ongoing conversion in the ADC driver, but you can check nrf_drv_adc_is_busy() and then trigger nrf_drv_adc_sample() until you get the NRF_DRV_ADC_EVT_DONE event.

    Best regards,
    Jørgen

Related