The interrupt timing of IRQ_DIRECT_CONNECT is different from expected.

Hello,

Currently, I am creating firmware that generates an IRQ_DIRECT_CONNECT interrupt at the timing when SPIM4 transfer is completed (ENDTX).

However, the interrupt timing is not at ENDTX but near the start of SPIM4 operation.

Since an interrupt occurs at the start, the current process is waiting for the ENDTX event within the interrupt. How should I set it to generate an interrupt at ENDTX?

IRQ_DIRECT_CONNECT and irq_enable settings:

IRQ_DIRECT_CONNECT(SPIM4_IRQn, 0,spim4_event_handler,IRQ_ZERO_LATENCY);
irq_enable(SPIM4_IRQn);

Interrupt handler settings:

static void spim4_event_handler(nrfx_spim_evt_t const*p_event, void *p_context)
{	
	while(NRF_SPIM4->EVENTS_ENDTX == 0){;}
	NRF_SPIM4 -> EVENTS_ENDTX = 0x00000000; 
}

Register settings before data transfer:

NRF_SPIM4 -> INTENCLR = 0x00080152;
NRF_SPIM4 -> INTENSET = 0x00000100;

Register settings after data transfer:

NRF_SPIM4 -> INTENCLR = 0x00000100;

best regard,

  • I would suggest that the ENDTX works as documented, but that the interrupt handler above is incorrectly written. The reason "the interrupt timing is not at ENDTX but near the start of SPIM4 operation" is likely to be that the clear of the event occurs from the previous SPIM4 transfer event, not the current transfer event, or ENDTX is triggered when a short TXD MAXCNT is exhausted in a longer SPIM4 transaction. Try changing this:

    static void spim4_event_handler(nrfx_spim_evt_t const*p_event, void *p_context)
    {	
    	while(NRF_SPIM4->EVENTS_ENDTX == 0){;}
    	NRF_SPIM4 -> EVENTS_ENDTX = 0x00000000; 
    }

    to this:

    // Handle and clear all triggering events
    static void spim4_event_handler(nrfx_spim_evt_t const*p_event, void *p_context)
    {	
    	if(NRF_SPIM4->EVENTS_ENDTX)
    	{
    	    NRF_SPIM4->EVENTS_ENDTX = 0;
    	}
    }

    For testing, one might test and clear every possible event in case there is some coding error, even though only ENDTX is required. In some ways ENDTX is not always the best choice, as incoming RX bytes beyond the active TX bytes (ie when sending shorter Tx then Rx using ORC padding bytes); END might be a safer choice.

    NRF_SPIM4 -> INTENSET = 0x00000040;
    // Handle and clear all triggering events
    static void spim4_event_handler(nrfx_spim_evt_t const*p_event, void *p_context)
    {	
    	if(NRF_SPIM4->EVENTS_END)
    	{
    	    NRF_SPIM4->EVENTS_END = 0;
    	}
    }

    "ORC: Byte transmitted after TXD.MAXCNT bytes have been transmitted in the case when RXD.MAXCNT is greater than TXD.MAXCNT" Note ENDTX is triggered when TXD MAXCNT is exhausted, not when SPIM4 transfer ends; perhaps try END instead.

  • Hello,

    Thank you for your reply.

    I modified the program as you pointed out, but as shown below, there was no change between before and after the modification.

    before:

    after:

    The timing at which Main loop processing finished is different from the timing at which interrupt processing finished.
    However, interrupt processing starts near the end.

    best regard,

  • Above:

    The timing at which Main loop processing finished is different from the timing at which interrupt processing finished.

    but correctly:

    The timing at which Main loop processing finished is different from the timing at which interrupt processing starts.

    Also, I feel it is strange that the Main loop ends around the start of SPIM4.

  • Neither trace above shows the problem described we were trying to fix:

    "However, the interrupt timing is not at ENDTX but near the start of SPIM4 operation. Since an interrupt occurs at the start, the current process is waiting for the ENDTX event within the interrupt. How should I set it to generate an interrupt at ENDTX?"

    Both traces look correct regarding the SPIM4 data transfer and the following event and consequential SPIM4 interrupt. Timing of the main loop pin toggle is quite separate; main loop will run on every event which will include wakeup on SPIM4 event, and Zephyr/RTOS threads (if any) and any other enabled event/interrupt. It is not clear what problem you are looking at.

    The start of the interrupt looks like it takes a long time to begin, but that is wholly dependent on the Zephyr/OS/sleep wake code and other higher-priority interrupts; maybe share the wakeup code ...

  • Hello,


    Sorry, I didn't explain it enough.


    The program is performing the following actions:
    1.Main loop (red line) constantly switching GPIO for testing purposes.
    2.I am trying to generate an interrupt process (blue line) at SPIM4's ENDTX.
    3. GPIO is set to "0" at the beginning of interrupt processing and set to "1" at the end of interrupt processing.


    The problem with this program is that the interrupt processing starts near the start of SPIM4's operation, not at ENDTX.
    This can be confirmed by the fact that GPIO switching disappears in the Main loop.
    For this reason, we have temporarily included a process to wait for ENDTX in the interrupt process.

    Also, I set GPIO to "0" before waiting for ENDTX in the interrupt process, but I am also concerned that it starts around ENDTX.
    I think the delay from when an interrupt occurs to the start of processing is long.

    Just to confirm, is it correct for SPIM4's ENDTX interrupt processing to always start from the SPIM4's start point?

    best regard,

Related