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

  • Hello Stefan,

    Thanks for the link. One more thing though, I did manage to get the PWM on compare 0 to work fine, however I tried in parallel to run an interrupt on Compare 1 every 10msec and that does not work. The interrupt is not entered and my PWM is 20msec. What am I getting wrong?

    // 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
    
    // Init OC0 PWM
    NRF_TIMER2->CC[0] = 50;
    PWM_TIMER->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);
    
    // Enable OC1 interrupt on TIMER2
    NRF_TIMER2->CC[1] = 10000;
    PWM_TIMER->SHORTS = (TIMER_SHORTS_COMPARE1_CLEAR_Enabled << TIMER_SHORTS_COMPARE1_CLEAR_Pos);
    NVIC_EnableIRQ(TIMER2_IRQn);
    
    // Start TIMER2
    NRF_TIMER2->TASKS_START = true;
    

    Interrupt :

    void TIMER2_IRQHandler(void)
    {
    
        if (NRF_TIMER2->EVENTS_COMPARE[1] != 0)
        {
            NRF_TIMER2->EVENTS_COMPARE[1] = 0; // Reset event
    
           // Code to execute
    
        }
    }
    

    Regards Phil

Related