NETCPU timer interrupt issues

Hi,

I have an issue with interrupts on TIMER1 on nrf5340 NETCPU. My setup involves 2 timers that are linked via DPPI, TIMER2 counting microseconds and TIMER1 counting milliseconds. I also have 2 DPPI channels routed via IPC, one each way. The IPC events works, so no issue there. However, I am unable to get an interrupt on capture on TIMER1. A capture is made, and the value in the corresponding CC reg is updated. But nothing happens in the EVENTS_COMPARE register, and no interrupt is generated. On TIMER2 it works just fine. Any idea what is wrong? Just to be super clear: the same event and the same setup fires the interrupt for TIMER2 as expected, but for TIMER1 there is no interrupt.

On a related note: On TIMER2 I found that I had to write the corresponding CC reg to clear the interrupt. I write EVENTS_CAPTURE to 0, and read it back. In addition I also tried to read the CC. Only when I added a write to CC did the interrupt clear. I write 0xffffffff, which is the  only value I have tested. Any idea what this is about?

Device marking is QKAAD0 (I think, small letters...).

A bit of code to describe my setup:

// Set up IPC, DPPI and subscribe to capture
NRF_IPC->PUBLISH_RECEIVE[I2S_FRAME_TICK_IPC_CHANNEL] = I2S_FRAME_TICK_DPPI_CHANNEL | (1 << 31);
NRF_IPC->RECEIVE_CNF[I2S_FRAME_TICK_IPC_CHANNEL] = (1 << I2S_FRAME_TICK_IPC_CHANNEL);
NRF_DPPIC->CHENSET = (1 << I2S_FRAME_TICK_DPPI_CHANNEL);
NRF_TIMER1->SUBSCRIBE_CAPTURE[FRAME_TICK_TS_CC] = I2S_FRAME_TICK_DPPI_CHANNEL | (1 << 31);
NRF_TIMER2->SUBSCRIBE_CAPTURE[FRAME_TICK_HS_CC] = I2S_FRAME_TICK_DPPI_CHANNEL | (1 << 31);
NRF_TIMER2->INTENSET = 1 << (FRAME_TICK_HS_CC + TIMER_INTENSET_COMPARE0_Pos);
NRF_TIMER1->INTENSET = 1 << (FRAME_TICK_TS_CC + TIMER_INTENSET_COMPARE0_Pos);
IRQ_DIRECT_CONNECT(TIMER2_IRQn, 2, frame_tick_handler, 0);
irq_enable(TIMER2_IRQn);
IRQ_DIRECT_CONNECT(TIMER1_IRQn, 0, frame_tick_handler2, 0);
irq_enable(TIMER1_IRQn);

/* Count / timestamp timer */
NRF_TIMER1->TASKS_STOP = 1;
NRF_TIMER1->TASKS_CLEAR = 1;
NRF_TIMER1->PRESCALER = 0;
NRF_TIMER1->MODE = TIMER_MODE_MODE_Counter << TIMER_MODE_MODE_Pos;
NRF_TIMER1->BITMODE = TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos;
NRF_TIMER1->TASKS_START = 1;    

/* Publish the capture compare match on the count (ms) timer to dppi */
NRF_TIMER1->PUBLISH_COMPARE[0] = TIMESTAMP_TO_IPC_CC_DPPI_CHANNEL | (1 << 31);

/* and subscribe ipc channel 8 to the same channel */
NRF_IPC->SUBSCRIBE_SEND[START_EVENT_IPC_CHANNEL] = TIMESTAMP_TO_IPC_CC_DPPI_CHANNEL | (1 << 31);
NRF_IPC->SEND_CNF[START_EVENT_IPC_CHANNEL] = (1 << START_EVENT_IPC_CHANNEL);

/* Aaand enable dppi channel */
NRF_DPPIC->CHENSET = (1 << TIMESTAMP_TO_IPC_CC_DPPI_CHANNEL);

HS_TIMER->PUBLISH_COMPARE[0] = (HS_TO_TIMESTAMP_COUNT_DPPI_CHANNEL) | (1 << 31);
NRF_TIMER1->SUBSCRIBE_COUNT = (HS_TO_TIMESTAMP_COUNT_DPPI_CHANNEL) | (1 << 31);
NRF_DPPIC->CHENSET = (1 << HS_TO_TIMESTAMP_COUNT_DPPI_CHANNEL);

NRF_TIMER2->TASKS_STOP = 1;
NRF_TIMER2->TASKS_CLEAR = 1;
NRF_TIMER2->PRESCALER = HS_TIMER_PRESCALER;
NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos;
NRF_TIMER2->CC[0] = TIME_SYNC_TIMER_MAX_VAL;
NRF_TIMER2->CC[1] = 0xFFFFFFFF;
NRF_TIMER2->CC[2] = 0xFFFFFFFF;
NRF_TIMER2->CC[3] = 0xFFFFFFFF;
NRF_TIMER2->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk | TIMER_SHORTS_COMPARE2_CLEAR_Msk;
NRF_TIMER2->TASKS_START = 1;

Parents
  • I am not aware of any issue with the hardware timers that should explain why they behave differently, based on your last comment I think you might have found the problem.

    Kenneth

  • No, my last comment is not a fix, it was simply about your readability.

    Even if I remove the IPC/DPPI stuff for triggering the interrupt, and do a NRF_TIMER1->TASKS_CAPTURE[n] the interrupt will only run execute for TIMER2. I've also tried to run it in normal mode (not counter mode) and without the DPPI chaining of timers.

    I also checked the relevant isr_tables.c to see that my ISR is included.

    Any ideas as to next steps?

  • I will likely not have time to look into this until I am back from vacation in about 3 weeks time.

    I did quickly glance at the blinky example you provided, I found it a bit strange that you in your isr2 cleared both MS_TIMER and US_TIMER EVENTS_COMPARE event, while in isr1 you cleared MS_TIMER EVENTS_COMPARE two times. 

    There is no check in your isr handlers to check which compare event triggered the interrupt, and you should only need to clear the event for the timer that triggered the interrupt before you exit the interrupt handler.

    I notice you are executing capture tasks in main, if you need those to execute straight after eachother I would recommend that you add a disable/enable interrupts around them. If not you can get some race condition where there is an interrupt between the two. The capture task doesn't trigger the interrupt, it only copy the timer's count value to the corresponding CC register. 

    Best regards,
    Kenneth

  • Regarding double MS_TIMER EVENTS clearing, yes that is an oversight. But it is the ISR that uses MS_TIMER, so it does not matter if I clear it twice. I have amended my example, and attached it again.

    No, there is no check for which compare. As long as my issue is that the interrupts don't fire properly, I don't care about which CC. This code is an example to reproduce the issue in the simplest way, not my production code. This is also why I execute the capture task from main. I am sure the result would be the same if I used e.g. a work-queue, or routed the signal via IPC and DPPI from the appcore.

    Regarding Capture interrupt. You say that the task doesn't trigger the interrupt, and I see that the INTENSET register says "compare." But surely the interrupt is supposed to also trigger on a capture? There are so many cases where you want to capture something _and_ be notified about it. It does trigger on timer2, so that indicates that this functionality is available.

    Could this ticket be transferred to someone who is not vacationing? I appreciate that it is summer holidays, but it's been 17 days since I submitted, and counting another 21 it will be 38 days without anything more than scratching the surface of my issue. 

    blinky2.zip

  • Hi again,

    peran said:
    But surely the interrupt is supposed to also trigger on a capture? There are so many cases where you want to capture something _and_ be notified about it. It does trigger on timer2, so that indicates that this functionality is available.

    I see your point, but I would not rely on this, since by the time you update CC register the counter value might have incremented at the same time, so I expect there will be corner cases here where there is no interrupt from this operation. If you need an interrupt, you may trigger the EGU interrupt instead (which can trigger an event that also can be used to trigger capture on both timers if you want):
    https://infocenter.nordicsemi.com/topic/ps_nrf5340/egu.html

    peran said:
    Could this ticket be transferred to someone who is not vacationing? I appreciate that it is summer holidays, but it's been 17 days since I submitted, and counting another 21 it will be 38 days without anything more than scratching the surface of my issue.

    I see your point here also, the problem the last 2 weeks have been low staff due to vacation, the next 2 and half week I am taking my vacation. But I can see if someone can fill in next week where there are more people back.

    Best regards,
    Kenneth

  • Reg capture and interrupt. I am not 100% sure I understand, but are you saying that interrupts are not available on capture, and that my interrupts are generated from a compare match on the captured value? 

    I'll check out the EGU. 

  • peran said:
    but are you saying that interrupts are not available on capture, and that my interrupts are generated from a compare match on the captured value? 

    Yes, the intention is simply something like:

    NRF_TIMER->TASKS_CAPTURE[0] = 1;
    return NRF_TIMER->CC[0];

Reply Children
No Data
Related