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

TIMER1 with PPI to GPIOTE

I'm trying to repeatedly toggle a GPIOTE on every CC[0] compare within the time period set by CC[1]. CC[1] runs multiple times. Every time CC[1] is reached I want to stop the CC[0] compare, check if I've sent a certain number of toggles and if so, stop TIMER1, else I'll re-enable the CC[0] compare and continue running.

I'm having a problem where the GPIOTE occasionally toggles after the final CC[1] compare occurs and I have an extra pulse being sent. It seems like the PPI is not being disabled quickly enough. I also have the S110 soft device enabled, but I don't see how that could affect it.

Here's my code. Any ideas what could be wrong?

Init Code:

NRF_TIMER1->TASKS_CLEAR = 1;
NRF_TIMER1->CC[0] = sub_period;
NRF_TIMER1->CC[1] = period;
NRF_TIMER1->MODE = (TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos);
NRF_TIMER1->PRESCALER = (0 << TIMER_PRESCALER_PRESCALER_Pos);
NRF_TIMER1->BITMODE = (TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos);
NRF_TIMER1->INTENSET = TIMER_INTENSET_COMPARE0_Msk | TIMER_INTENSET_COMPARE1_Msk;
NRF_TIMER1->SHORTS = (TIMER_SHORTS_COMPARE1_CLEAR_Enabled << TIMER_SHORTS_COMPARE1_CLEAR_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->CH[1].EEP = (uint32_t)(&NRF_TIMER1->EVENTS_COMPARE[1]);
NRF_PPI->CH[1].TEP = (uint32_t)(&NRF_GPIOTE->TASKS_OUT[0]);
nrf_gpiote_task_config(0, TX_OUT, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW);

NRF_PPI->CHENSET = (PPI_CHEN_CH0_Enabled << PPI_CHEN_CH0_Pos)
                  | (PPI_CHEN_CH1_Enabled << PPI_CHEN_CH1_Pos);

err_code = sd_nvic_SetPriority(TIMER1_IRQn, 3);
APP_ERROR_CHECK(err_code);
err_code = sd_nvic_ClearPendingIRQ(TIMER1_IRQn);
APP_ERROR_CHECK(err_code);
err_code = sd_nvic_EnableIRQ(TIMER1_IRQn);
APP_ERROR_CHECK(err_code);

Interrupt:

void TIMER1_IRQHandler() {
    NRF_TIMER1->EVENTS_COMPARE[0] = 0;
    if (NRF_TIMER1->EVENTS_COMPARE[1]) {
        NRF_TIMER1->EVENTS_COMPARE[1] = 0;
        NRF_TIMER1->INTENCLR = TIMER_INTENCLR_COMPARE0_Msk;
        timer_check();
    }
    NRF_TIMER1->EVENTS_COMPARE[2] = 0;
    NRF_TIMER1->EVENTS_COMPARE[3] = 0;
 }

Check if done toggling:

void timer_check() {
    if (--remainingToggles == 0) {
        NRF_PPI->CHENCLR = (PPI_CHEN_CH0_Disabled << PPI_CHEN_CH0_Pos)
                 | (PPI_CHEN_CH1_Disabled << PPI_CHEN_CH1_Pos);
        nrf_gpiote_unconfig(0);
        NRF_TIMER1->TASKS_SHUTDOWN = 1;
        sd_nvic_DisableIRQ(TIMER1_IRQn);
        sd_nvic_ClearPendingIRQ(TIMER1_IRQn);
    }
    else {
        NRF_TIMER1->INTENSET = TIMER_INTENSET_COMPARE0_Msk;
    }
}

Any advice is greatly appreciated!

Parents Reply Children
Related