This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

UPP Transmit DMA stall

We are programming a chain of UPP transmit transfers.  After two transfers are initially programmed, the ISR monitors the PEND bit to determine if the next transfer can be programmed.  All of the transfers are being programmed, however occasionally the last transfer never gets started.  The interrupt for the last transfer calls a callback that releases a mutex.  The code hangs waiting on the mutex for the last transfer.  The last transfer is programmed but never started by the UPP.

When stopped the address of the last transfer is present in registers UPID0 & UPIS0.  Writing a zero to UPID2 starts the last transfer, generates the interrupt, and the code continues as normal. 

The UPP port is programmed to honor WAIT and we have verified that WAIT is deasserted throughout all of the transfers. 

What is causing the UPP stall and what is the proposed workaround?

  • Hunter,

    Let me make sure that I understand the sequence of events:

    1. Start by programming 2 transfers (one active, one pending)
    2. In the ISR, program another transfer if PEND allows it
    3. This works fine for N transfers
    4. Transfer N + 1is programmed but fails to start
    5. Writing 0 to UPID2 (the whole register, not an individual field) causes transfer N + 1 to start

    Assuming that the above is correct, I have a few questions for you:

    How big (in bytes) are your transfers, and how fast are you operating the uPP channel (i.e. clock speed, data rate, word length)?  It may be possible that another transfer sometimes completes before you've exited the ISR/callback from the previous transfer.  You may be encountering a race condition, depending on how your ISR and callback functions are structured.  Have you accounted for that possibility in your code?

    How many transfers complete successfully before this problem occurs?  (e.g.. What is N, above?)  Is the number different each time you run, or does it consistently happen at a certain point?

  • Joe, thanks for the response.

    I think the problem is in software.  Right now the code is expecting to get an interrupt for every transfer, but as you suggest there is a possibility that two transfers have completed if the latency is great enough.  We are seeing this consistently happen when UART interrupts are coincident, which is exacerbating the problem. 

    Given the UPP keeps on processing transfers, what is the detection method for determining that two transfers have completed instead of one in the interrupt?   If PEND can be written multiple times then two completed?

    Also, I think the last transfer is completing since the line count is incremented to 2 in the status register (all transfers are line count 1).  I was fooled since the window address in the status register was reset to the beginning of the buffer, which would be correct for multiple line counts with a line offset of zero.  Correct?

  • Hunter Leland said:
    Given the UPP keeps on processing transfers, what is the detection method for determining that two transfers have completed instead of one in the interrupt?   If PEND can be written multiple times then two completed?

    That sounds like the easiest thing. 

    Are you using BIOS?  If so, in the HWI properties for the UPP interrupt I recommend going to the Dispatcher tab and selecting interrupt mask as "all" so that nothing pre-empts the UPP ISR.  That might help.

    Perhaps trying to figure out why the UART activity causes you to miss the interrupt might also be a good approach.  Are interrupts being disabled for a long period of time?

    There's also capability in the core/megamodule for detecting dropped interrupts.  If you map EVT96 to another one of the 12 core interrupts (INT4-INT15) then you could generate an interrupt telling you that you missed one.  You could put a little wrapper code in the ISR to clear out the error and then call your other code (assuming it uses dispatcher and not interrupt keyword).

     

  • Brad's suggestion to change HWI priorities such that nothing pre-empts uPP interrupts is a good idea.

    Also, you should definitely structure your uPP ISR in the form of a loop so that you catch multiple events if they happen before you can return from the ISR.  (There's an example ISR function in section 2.6.4 of the uPP user guide that shows how to do this.)  Since uPP is a high-speed peripheral with a single combined interrupt, it's pretty likely that you will mask some interrupts if you don't do this, even if uPP interrupts are the only interrupts in your system.  The faster your uPP clock and the shorter your transfers, the more likely it is that this will happen.

    Checking to see whether two transfers have completed since you last checked is a little bit tricky.  You can use the UPIS2.ACT bit to check whether any transfer is currently active (i.e. PEND = ACT = 0 means that both transfers have completed), but I'm not absolutely sure that ACT is high 100% of the time that a transfer is active.  It would probably be safer just to have something like this in your code:

    while (UPIS2.PEND == 0)
        program_transfer();

    Hope this helps.