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!