This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Problem running a 10kHz PWM on a Timer

Hi,

I am trying to obtain a 10khz PWM (50%) on an output using Timer2 (see code below). It is working fine up to around 500Hz (2msec), above that (1kHz) I am getting only sporadic PWM bursts, PWM will run up to advertising then will stop, then timer has to overun to startPWM again.

As mentioned, I have S110 advertising running in background, I am certain that I am missing the Timer2 interrupt to update Compare 0 because advertising interrupt is in higer priority.

My question is, how can I easily output a 10kHz PWM without needing to enter an interrupt by software to update an output compare register?

Here's the code:

GPIOTE init:

// Configure GPIOTE channel 0 to toggle the PWM pin state
    nrf_gpiote_task_config(0, LED_6, NRF_GPIOTE_POLARITY_TOGGLE, RF_GPIOTE_INITIAL_VALUE_LOW);

PPI init:

// Configure PPI channel 0 to toggle PWM_OUTPUT_PIN on every TIMER2 COMPARE[0] match.
NRF_PPI->CH[0].EEP = (uint32_t)&NRF_TIMER2->EVENTS_COMPARE[0];
NRF_PPI->CH[0].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[0];

// Enable PPI channel 0.
NRF_PPI->CHEN = (PPI_CHEN_CH0_Enabled << PPI_CHEN_CH0_Pos);

Timer init + start:

 // Init TIMER2 for 10kHz PWM
NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer;			// Set the timer in Counter Mode
NRF_TIMER2->TASKS_CLEAR = 1;						// Clear the tasks first to be usable for later
NRF_TIMER2->PRESCALER = 4;							// 2^PRESCALER (values authorized 1 to 9) 4 : 16MHz / 16 = 10MHz
NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit;	//Set counter to 16 bit resolution
NRF_TIMER2->CC[0] = 50;

// Enable OC1 interrupt on TIMER2
NRF_TIMER2->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;
NVIC_EnableIRQ(TIMER2_IRQn);

// Start TIMER2
NRF_TIMER2->TASKS_START = true;

The interrupt:

void TIMER2_IRQHandler(void)
{
	
	if (NRF_TIMER2->EVENTS_COMPARE[0] != 0)
	{
		NRF_TIMER2->EVENTS_COMPARE[0] = 0; // Reset event
		
		// Set next compare in 50nsec
		NRF_TIMER2->CC[0] += 50;
			
	}
}

Thanks for any help on this.

Phil

Parents
  • Hi Phil,

    You can totally get rid of the interrupt handler if you don't want to change the desired frequency on the fly.

    This can be done by setting the SHORT register.

    Add one more line in Timer init function,

    PWM_TIMER->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);
    

    This enables the timer to clear the internal counter to 0 when it reaches CC[0].

    Hope this will help.

    Tony

Reply
  • Hi Phil,

    You can totally get rid of the interrupt handler if you don't want to change the desired frequency on the fly.

    This can be done by setting the SHORT register.

    Add one more line in Timer init function,

    PWM_TIMER->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);
    

    This enables the timer to clear the internal counter to 0 when it reaches CC[0].

    Hope this will help.

    Tony

Children
Related