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.

RTOS/TMS320C6748: event combiner interrupt firing only once for EDMA3

Part Number: TMS320C6748
Other Parts Discussed in Thread: SYSBIOS

Tool/software: TI-RTOS

code gen tools 7.4.23

SYSBIOS 6.46.2.47

EDMA3LLD 2.12.0

Custom board

so here is what is going on. we are calling hEdma[0] = edma3init(0, &result); to initialize the EDMA3 and with that comes the setup with the event combiner and interrupts. i just started getting the EDMA3 to work with our McBSP setup. i seem to have everything set up right as the EDMA3 will channel sort and properly links in the ping pong buffers so it seems. it runs nonstop and memory is always moving. my problem is that my call back routine only gets called once for each channel (rx and tx) and then never again.

my main channel requested like this:

uint32_t MemcpychId = EDMA3_DRV_HW_CHANNEL_EVENT_5;
uint32_t tcc = EDMA3_DRV_TCC_ANY;

/* TRANSMIT */
result = EDMA3_DRV_requestChannel (hEdma[0], &MemcpychId, &tcc, (EDMA3_RM_EventQueue)0, &EDMAMcBSP1Txcallback, NULL);

and the link channels are requested like so:

uint32_t MemcpychIdtemp = EDMA3_DRV_LINK_CHANNEL;
tcc = EDMA3_DRV_TCC_ANY;

result = EDMA3_DRV_requestChannel(hEdma[0], &MemcpychIdtemp, &tcc, 0, &EDMAMcBSP1Txcallback, NULL);

so they all have the same call back function. they all are initialized for TCINT

result =  EDMA3_DRV_setOptField (hEdma[0], MemcpychId, EDMA3_DRV_OPT_FIELD_TCINTEN, EDMA3_DRV_TCINTEN_EN);

and

result =  EDMA3_DRV_setOptField (hEdma[0], McBSP1TxParamTable[count], EDMA3_DRV_OPT_FIELD_TCINTEN, EDMA3_DRV_TCINTEN_EN); //inside a for loop for the link channels

this is a similar problem that i have had with the event combiner when i tried to use it directly for the McBSP RRDY and XRDY interrupts. it would fire the interrupt once and then never again. up until now the only way to handle interrupts for the McBSP has been to set up the interrupts directly in the HWI module. 

my system IER is showing the proper interrupts are enabled, the GIE is enabled, my EER shows the events are enabled. my IFR is not showing anything.

is the event combiner not capable of handling interrupts like this? i know it works for basic memory copy without an issue with the EDMA3 and i have used it for other interrupts that don't fire so frequently like uart and LCD controller.

  • Hi,

    I've notified the RTOS team. They will post their feedback directly here.

    Best Regards,
    Yordan
  • so i can't find anything in any of the documentation about this (maybe i'm looking in the wrong spots?) but it seems once an EDMA transfer happens the interrupt gets cleared and it would APPEAR all EDMA3 interrupts are one shot only. is that right? the way around this (through trial and error) is to reload the tcc in the interrupt via the command:

    EDMA3_DRV_setOptField (hEdma[0], tcc, EDMA3_DRV_OPT_FIELD_TCC, tcc);

    is this the proper way to reload the interrupt? should i not need to do this? what is the correct way to reload the interrupt?
  • Cobsonchael,

    Although I cannot tell you the exact APIs to use or where an example would be, I do know about the EDMA3 module and how it interacts with the CPU.

    In the past when you had to setup the McBSP interrupts directly with the HWI module, you had a EDMA Dispatcher routine that would be triggered by the single interrupt from the EDMA3 module you were using. That Dispatcher would have to decide which IPR bit(s) needed to be serviced and would take care of clearing that IPR bit(s) and calling the service routine.

    Now, when you are trying to use the Event Combiner, there is one more level of logic that has to be considered. The same Dispatcher has to parse through the IPR bits to find the ones that are active and need servicing. If one or more of bits 0-3 are set, then the Event Combiner comes into play and has to be serviced with an extra level of parsing and clearing. If the clearing of ECM bits is not done correctly and completely, then it will likely never trigger another interrupt to the DSP.

    You can look at the bits in the ECM when you get to the state where no more interrupts are happening. If there are unmasked bits set in the ECM registers for your DMA events, but interrupts are not happening, then most likely the ECM is not being cleared correctly. The EDMA3 User Guide has a description of how it works and what needs to be done, and I feel strongly that the LLD has both an example and APIs to handle the use of the ECM, but I am more of a direct register user and not a power software pro. Sorry.

    Maybe someone from the RTOS group of someone who knows the LLD well will be able to point you there. Or maybe this gives you some ideas on where to look or what to look for in the examples and documentation.

    Regards,
    RandyP
  • thanks for the response RandyP.

    i have switched to the normal HWI module (No Event combiner at all) for the EDMA and still, just one-shot interrupt unless i reset the TCC. hopefully someone can come around shortly and let me know what i am doing wrong. i am using one interrupt calling lisrEdma3ComplHandler0 eventID 8. i looked at the mcbsp edma example and it doesn't seem like the call back function is doing anything special to the EDMA3 except maybe clearing error bits
  • There is no reason why the EDMA3_DRV_setOptField function call should affect interrupts. All it does is a read/modify/write on the .OPT register, which in your case is reading and then writing back the same value read. That is not going to clear any interrupt bits.

    What are you doing differently now than you were doing before with the McBSP, since it was working with the non-ECM method? In particular, look at which ISR function is assigned directly to the HWI and look for where the IPR bits are being tested and cleared.
  • the tcc gets cleared out of the channel when the interrupt happens, it seems. reloading it may have nothing to do with interrupt flags but it does give the channel a tcc number to handle when the transfer is complete. what i don't understand is why the tcc gets cleared upon a completed transfer.

    i think you misunderstand. we never use the EDMA for mcbsp before, we used the HWI module for the RRDY and XRDY events directly. this is our first go at using the EDMA for mcbsp

  • i figured it out. when i requested a channel i thought that if i set the "tcc" variable to the channel TCC that i was requesting (4 and 5) i thought it would assign that tcc to that channel automatically and when it linked it would automatically reload the tcc field. that was wrong. i had to manually set the TCC in the options of the link params for it to count. with that epiphany it works every time now
  • You are right, I totally misunderstood the past McBSP use.

    And that also means you are in the area that I am not an expert, the EDMA3 LLD and how to use it. I do know that the EDMA3 LLD includes a Resource Manager which also includes an Interrupt Manager. When you register a callback function with an LLD call, it puts that TCC and callback function into a table that is used when an interrupt occurs. You have to separately (I believe) assign that Interrupt Manager's dispatch function to the HWI that will be handling the EDMA3 interrupts. That dispatch function will (should) take care of clearing your IPR bits.

    Surely we have an example in the Processor SDK that shows how to setup the McBSP to use it with EDMA3 and interrupts. Are you using the Processor SDK?
  • Glad to hear you solved the problem. Great work!

    My reply above was posted after you said you solved the problem, so it was mostly useless. You have all the parts being used right, obviously since you have it working now. And thanks for letting us know and marking your post as the Answer!

    For most uses of DMA with streaming ports like McBSP, the EDMA3 PARAM will be setup with 3 PARAM sets being used: the primary one that is directly associated with the DMA channel, a 'ping' link PARAM set, and a 'pong' link PARAM set. Usually, the primary and 'ping' PSets will be identical and will have their LINK fields pointing to the 'pong' PSet; the 'pong' PSet will have its LINK field pointing to the 'ping' PSet.

    This configuration will allow you to never have any re-start interaction with the EDMA3. All you will have to do is respond to a completion interrupt to tell you to go off and process the data that just came in. Some users like to have a different TCC for the ping and pong sides so they know exactly which data they are working with - that method requires 2 callback functions that will be identical except for the buffer address that gets sent to the processing algorithm.

    Are you using the ping/pong system, or are you restarting the DMA from inside your ISR? The main reason for asking is that some of the LLD routines (like EDMA3_DRV_setOptField) are very time consuming because of the register read/write required inside that function. If there are more of those, the time can add up very quickly, and it is important to minimize what gets done and how much time gets used from within an ISR.

    Regards,
    RandyP
  • thanks for the follow up Randy

    i am using a ping/pong method with linked param sets. i am setting the TCC in the setup now, not the ISR. i likely wouldn't have this problem if i just did a getParam->setParam to copy the channels but since this is my first go-round with the EDMA and McBSP i kind of wanted to be explicit to get it to work first, then optimize it when it works. the only thing i am doing inside the ISR is a GetParam to see which buffer is loaded in the param so i know which way to set my pingpong variable before i issue a SWI. is there a better way to figure out ping vs pong?

  • Most of our ping/pong examples use a global/static variable that gets toggled each time the ISR is called. It is quick and easy, but it is open loop in terms of the possibility of getting out of sync with the DMA channel. But to get out of sync would mean missing an interrupt or EDMA3 event, which is a huge problem no matter what the software is doing.

    Any time you read a peripheral register like a PARAM or even IPR, you can count on it taking 20+ DSP clock cycles. So it is good to avoid any of those if possible. The only closed-loop method I can think of is the example I mentioned above where you would have a different TCC for the ping and pong sides so the ISR knows exactly which data being worked with.

    If the callback function can have an argument passed to it, you could make the callback function be SWI_post() and have the argument be either a ping or pong SWI name. Or you could do the same with a semaphore if you want to use a task instead of a SWI.