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?

  • You should make the prescaler as big as possible. There is a minimum number of cycles though between clear and cc. I think it is 2 or 3 cycles. You may have to run with prescaler equal to zero.

  • Thanks AmbystomaLabs, your comments have been incredibly helpful! I got it working with the following minimal code (not worrying about SoftDevice and the like at the moment).

    int main(){
        sd_clock_hfclk_request();
        NRF_TIMER1->SHORTS      = (1 << TIMER_SHORTS_COMPARE0_CLEAR_Pos); 
        NRF_TIMER1->PRESCALER   = 0; 
        NRF_TIMER1->CC[0]       = 1;   
        NRF_TIMER1->TASKS_START = 1;
        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->CHEN       = (PPI_CHEN_CH0_Enabled << PPI_CHEN_CH0_Pos);
      
        NRF_GPIOTE->CONFIG[0] =((GPIOTE_CONFIG_MODE_Task       << GPIOTE_CONFIG_MODE_Pos)
                                |(6                         << GPIOTE_CONFIG_PSEL_Pos)
                                |(GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos)
                                |(GPIOTE_CONFIG_OUTINIT_Low     << GPIOTE_CONFIG_OUTINIT_Pos));
    }
    
  • That is good news.

    The only difference between SD version and your version above is the PPI assignments and channel enable. With the SD running it will write over the PPI registers so you have to use the API command.

    Great work! Make sure to share the knowledge next time the question comes up in the devzone.

  • I'm currently trying to get the second (slower) signal running. In theory, I should be able to set CC[1]=100, set PPI Channel 1 to EVENTS_COMPARE[1] and copy the GPIOTE config for a different pin to CONFIG[1], right? For some reason, it does not work :(

  • 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.
    }
    
    }
    
Related