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

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!

Parents
  • 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);

Reply
  • 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);

Children
No Data
Related