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