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

How to use multiple timers

I have a device that I need to control, that needs 2 different square wave signals of different frequencies (although they may be multiples of each other), one at around 4 MHz and one at 10 KHz. Additionally (while the other two are running in the background) I need to communicate to the device with SPI upon an interrupt on a separate pin. To make matters worse, I will also need the SoftDevice for communications via BLE.

I have read that the nRF51822 only comes with 3 timers (one of which is reserved for th SoftDevice). Is there still a way to use one timer for multiple tasks?

Parents
  • Sadly I couldn't figure out a way to do it with one timer without involving ISR's. You cannot do ISR's at these frequencies so the only solution was to use two timers.

    But the below code gives you precisely what you wanted. The 4MHz signal was a little rounded. It could be my scope probes or you may want to try putting the gpio into high drive. It was still a pretty decent square wave.

    I lashed the timers together in PPI so they would always be synchronous. Since you were trying it without the SD, I assumed it was gone and started HF_EXT manually. I just put the code in the blinky shell from the examples to have an easy project to start from. I chose gpio that were far enough apart on the dk so that I could attach scope probes.

    Have fun!

    int main(void)
    {
        /* Configure board. */
        NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_HFCLKSTART    = 1;
    
    /* Wait for the external oscillator to start up */
    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
    {
        // Do nothing.
    }
    
            NRF_TIMER1->TASKS_STOP        = 1;                      // Stop timer, if it was running
    NRF_TIMER1->TASKS_CLEAR       = 1;
    NRF_TIMER1->MODE              = TIMER_MODE_MODE_Timer;  // Timer mode (not counter)
    NRF_TIMER1->EVENTS_COMPARE[0] = 0;                      // clean up possible old events
    NRF_TIMER1->EVENTS_COMPARE[1] = 0;
    NRF_TIMER1->EVENTS_COMPARE[2] = 0;
    NRF_TIMER1->EVENTS_COMPARE[3] = 0;
    
            NRF_TIMER2->TASKS_STOP        = 1;                      // Stop timer, if it was running
    NRF_TIMER2->TASKS_CLEAR       = 1;
    NRF_TIMER2->MODE              = TIMER_MODE_MODE_Counter;  // Counter mode (not Timer)
    NRF_TIMER2->EVENTS_COMPARE[0] = 0;                      // clean up possible old events
    NRF_TIMER2->EVENTS_COMPARE[1] = 0;
    NRF_TIMER2->EVENTS_COMPARE[2] = 0;
    NRF_TIMER2->EVENTS_COMPARE[3] = 0;
    
    
        NRF_GPIOTE->CONFIG[0] =((GPIOTE_CONFIG_MODE_Task       << GPIOTE_CONFIG_MODE_Pos)
                                |(4                         << GPIOTE_CONFIG_PSEL_Pos)
                                |(GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos)
                                |(GPIOTE_CONFIG_OUTINIT_Low     << GPIOTE_CONFIG_OUTINIT_Pos));
    
        NRF_GPIOTE->CONFIG[1] =((GPIOTE_CONFIG_MODE_Task       << GPIOTE_CONFIG_MODE_Pos)
                                |(7                         << GPIOTE_CONFIG_PSEL_Pos)
                                |(GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos)
                                |(GPIOTE_CONFIG_OUTINIT_Low     << GPIOTE_CONFIG_OUTINIT_Pos));
    
    
        NRF_PPI->CH[0].EEP  = (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[0];
        NRF_PPI->CH[0].TEP  = (uint32_t)&NRF_GPIOTE->TASKS_OUT[0];
    		NRF_PPI->FORK[0].TEP = (uint32_t)&NRF_TIMER2->TASKS_COUNT;
    		
    		NRF_PPI->CH[1].EEP  = (uint32_t)&NRF_TIMER2->EVENTS_COMPARE[0];
        NRF_PPI->CH[1].TEP  = (uint32_t)&NRF_GPIOTE->TASKS_OUT[1];
    
    
        NRF_PPI->CHEN       = (PPI_CHEN_CH0_Enabled << PPI_CHEN_CH0_Pos)|(PPI_CHEN_CH1_Enabled << PPI_CHEN_CH1_Pos);
    
        NRF_TIMER1->SHORTS      = (1 << TIMER_SHORTS_COMPARE0_CLEAR_Pos); 
        NRF_TIMER1->PRESCALER   = 0; 
        NRF_TIMER1->CC[0]       = 2;   
    		
    		NRF_TIMER2->SHORTS      = (1 << TIMER_SHORTS_COMPARE0_CLEAR_Pos); 
        NRF_TIMER2->PRESCALER   = 0; 
        NRF_TIMER2->CC[0]       = 400;   
    		
        NRF_TIMER2->TASKS_START = 1;
    		NRF_TIMER1->TASKS_START = 1;
    		
    		while (1)
    {
        // Do nothing.
    }
    
    }
    
  • The single timer approach just doesn't work because the logic didn't work out. Since they are different periods, you use the shorts to clear the counter, and there is only one counter you would need to advance the 4MHz clock CC register constantly so two timers was the way to go.

    I didn't notice you were using nRF51 which doesn't have the fork. As long as you start the two timers sequentially in code, they should start on the same Pclk cycle and stay in sync. Using the fork was a way to ensure this was always true.

    Alternatively you could use a third PPI channel tied to a duplicate event on timer 1 to drive timer 2 as a counter(ie, set cc1 on timer 1 to 2 and attach its event to drive timer 2 counter). The downside is timer2 would be delayed by one Pclk.

    Or, you could dig into the PWM core and make it do constant duty output. Should be straightforward.

    I'm glad it worked out!

Reply
  • The single timer approach just doesn't work because the logic didn't work out. Since they are different periods, you use the shorts to clear the counter, and there is only one counter you would need to advance the 4MHz clock CC register constantly so two timers was the way to go.

    I didn't notice you were using nRF51 which doesn't have the fork. As long as you start the two timers sequentially in code, they should start on the same Pclk cycle and stay in sync. Using the fork was a way to ensure this was always true.

    Alternatively you could use a third PPI channel tied to a duplicate event on timer 1 to drive timer 2 as a counter(ie, set cc1 on timer 1 to 2 and attach its event to drive timer 2 counter). The downside is timer2 would be delayed by one Pclk.

    Or, you could dig into the PWM core and make it do constant duty output. Should be straightforward.

    I'm glad it worked out!

Children
No Data
Related