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

Confused about GPIOTE: pin toggle and interrupt latency

Hi,

I have a pretty simple problem but I can't get it right. This is what I want to do:

T=000, PIN_x = 0
T=004, PIN_x = 1
T=100, call a routine
T=543, Start over (T=544=0)

(T is in cycles, 8MHz)

It seems like using PPI and GPIOTE is the correct way for this?

  1. Will the PIN toggle at EXACT the correct time? (T=0 and T=40)
  2. At what time will my first instruction in the routine be called? (is it 100 - latency?)
  3. Do the CPU have to do something for resetting the timer?

Using NRF51822

Thanks

  • Clarify

    T=000, PIN_x = 0

    T=040, PIN_x = 1

    T=100, call a routine

    T=543, start over

    T=544=0

  • Yes, PPI and GPIOTE would be the correct way for this.

    You can use three compare registers for this, and set the prescaler to 1 (8MHz):

    NRF_TIMER0->PRESCALER = 1;
    NRF_TIMER0->CC[0] = 40;
    NRF_TIMER0->CC[1] = 100;
    NRF_TIMER0->CC[2] = 544;
    

    Use shorts to clear timer on CC[2]. Timer becomes zero right away so it will start to count on 1 next cycle.

    NRF_TIMER0->SHORTS = TIMER_SHORTS_COMPARE2_CLEAR_Enabled << TIMER_SHORTS_COMPARE2_CLEAR_Pos;
    

    You can then use CC[2] = 544 to toggle the PIN (as in your T=000, PIN_x = 0), and CC[0] = 40 to toggle the pin again (as in your T=040, PIN_x = 1). Do this with PPI and GPIOTE:

    NRF_GPIOTE->CONFIG[0] = (3 << 0) | (PIN1 << 8) | (3 << 16) | (1 << 20); //Task mode, PIN1, Toggle, init: 1
    NRF_PPI->CHENSET = 0x3; //enable two channels
    NRF_PPI->CH[0].EEP = (uint32_t) &NRF_TIMER0->EVENTS_COMPARE[2];
    NRF_PPI->CH[0].TEP = (uint32_t) &NRF_GPIOTE->TASKS_OUT[0];
    NRF_PPI->CH[1].EEP = (uint32_t) &NRF_TIMER0->EVENTS_COMPARE[0];
    NRF_PPI->CH[1].TEP = (uint32_t) &NRF_GPIOTE->TASKS_OUT[0];
    

    And yes, the time when this happen will be within the 8MHz clock cycle specified in the CC register (T=544/0 and T=40)

    Enable interrupt for the CC[1] register:

    NVIC_EnableIRQ(TIMER0_IRQn);
    NRF_TIMER0->INTENSET = (1 << 17);
    

    Now you can do CPU stuff in the TIMER0_IRQHandler()

    void TIMER0_IRQHandler(void){
        if(NRF_TIMER0->EVENTS_COMPARE[1]){
            NRF_TIMER0->EVENTS_COMPARE[1] = 0;
            do_stuff();
        }
    }
    

    The CPU would then start executing at T=100 + latency. Since the HF clock and 1.2V peripheral regulator is already running (because of TIMER) the only thing that is started is the 1.7V regulator which takes ~2us to startup (table 32 Power management in the PS). So then T = 100 cycles + 2us.

    Clear and start timer after init:

    NRF_TIMER0->TASKS_CLEAR = 1;
    NRF_TIMER0->TASKS_START = 1;
    
Related