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

Jitter on Timer1+PPI+GPIOTE?

I need to implement a 4kHz signal to drive a buzzer on a custom board of nRF51822 with external 16MHz and 32kHz crystal.

I am using Timer1+PPI+GPIOTE to generate this 4kHz signal.

Unfortunately there is sound distortion issue.

Measured by CRO, the 4kHz signal is jittering by 30us.

Below is the code I used to setup TIMER1 + PPI + GPIOTE.

Is there any thing I have missed to generate a stable 4kHz signal?

Thanks.

void timer_event_handler(nrf_timer_event_t event_type, void * p_context){		//For init only
}

void app_buzzer_init(){
	uint32_t err_code;
	uint32_t ret;
	uint32_t time_ticks;

	nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(NRF_GPIOTE_INITIAL_VALUE_LOW);
	
	err_code = nrf_drv_gpiote_out_init(BUZZER_PIN_0, &config);
	APP_ERROR_CHECK(err_code);
		
	err_code = nrf_drv_timer_init(&timer1, NULL, timer_event_handler);
	APP_ERROR_CHECK(err_code);

	time_ticks = (16000000 / m_main_params.buzzer_freq) / 2;
	nrf_drv_timer_extended_compare(&timer1, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);
	
	err_code = nrf_drv_ppi_init();
	APP_ERROR_CHECK(err_code);

	// Configure 1nd available PPI channel
	err_code = nrf_drv_ppi_channel_alloc(&ppi_channel1);
	APP_ERROR_CHECK(err_code);
	err_code = nrf_drv_ppi_channel_assign(ppi_channel1,
										  nrf_drv_timer_event_address_get(&timer1, NRF_TIMER_EVENT_COMPARE0),
										  nrf_drv_gpiote_out_task_addr_get(BUZZER_PIN_0));
	APP_ERROR_CHECK(err_code);
	
	// Enable both configured PPI channels
	err_code = nrf_drv_ppi_channel_enable(ppi_channel1);
	APP_ERROR_CHECK(err_code);
	
	nrf_drv_gpiote_out_task_enable(BUZZER_PIN_0);
	
	nrf_drv_timer_disable(&timer1);	
}

void buzzer_service(){
	if (m_main_flag.buzzer_flag){
	    //edited: 2018/8/22
	    //=========Adding this part seems no change=========
	    NRF_CLOCK->TASKS_HFCLKSTART = 1;
        /* Wait for the external oscillator to start up */
        while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
        NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
        //==================================================
        
		nrf_drv_gpiote_out_task_enable(BUZZER_PIN_0);
		nrf_drv_timer_enable(&timer1);
	}else{
		nrf_drv_gpiote_out_task_disable(BUZZER_PIN_0);
		nrf_drv_timer_disable(&timer1);
	}
}

Board A, good sound and no jittering:

Board B, distorted sound with jittering (yellow marked = 30us):

Parents
  • Hi,

    Can you show a screenshot of the jitter?

    What SDK are you using?

    Are you really using a 12 MHz crystal or is that a typo? nRF51 only supports 16 or 32 MHz crystals. 

    I tested your code and was caught off guard by this bug/feature. With SDK 12.3.0 you are not allowed to pass NULL as config parameter to nrf_drv_timer_init() (even though it says so in the documentation). The result of passing NULL is a randomly configured timer.

    Anyway, after configuring the timer correctly I'm seeing a jitter of max 0.1 us and about 0.35 % error on the frequency. Note that to get an as accurate clock as possible you need to explicitly turn on the HF crystal using the NRF_CLOCK->TASKS_HFCLKSTART task or sd_clock_hfclk_request() if you are using a Softdevice. Otherwise the Timer will use the internal RC Oscillator which has a typical accuracy of only ~5 %. 

  • I am using SDK v11.0 and softdevice S130 v2.0.0.

    I am sorry it is a typo that the crystal used should be 16MHz.

    I added HFCLKSTART task as shown below, however I did not see any big different:

    void buzzer_service(){
    	if (m_main_flag.buzzer_flag){
    	    NRF_CLOCK->TASKS_HFCLKSTART = 1;
            /* Wait for the external oscillator to start up */
            while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
            NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    	
    		nrf_drv_gpiote_out_task_enable(BUZZER_PIN_0);
    		nrf_drv_timer_enable(&timer1);
    	}else{
    		nrf_drv_gpiote_out_task_disable(BUZZER_PIN_0);
    		nrf_drv_timer_disable(&timer1);
    	}
    }

    I will update this post to include screenshots.

Reply
  • I am using SDK v11.0 and softdevice S130 v2.0.0.

    I am sorry it is a typo that the crystal used should be 16MHz.

    I added HFCLKSTART task as shown below, however I did not see any big different:

    void buzzer_service(){
    	if (m_main_flag.buzzer_flag){
    	    NRF_CLOCK->TASKS_HFCLKSTART = 1;
            /* Wait for the external oscillator to start up */
            while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
            NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    	
    		nrf_drv_gpiote_out_task_enable(BUZZER_PIN_0);
    		nrf_drv_timer_enable(&timer1);
    	}else{
    		nrf_drv_gpiote_out_task_disable(BUZZER_PIN_0);
    		nrf_drv_timer_disable(&timer1);
    	}
    }

    I will update this post to include screenshots.

Children
No Data
Related