Hi,
Anybody knows how to perform an EDMA link-to-self transfer using LLD? I'd just like to reload parameters automatically when its counters are exhausted.
Thanks in advance,
Gaston
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.
Hi,
Anybody knows how to perform an EDMA link-to-self transfer using LLD? I'd just like to reload parameters automatically when its counters are exhausted.
Thanks in advance,
Gaston
You will have to share a lot more about what you want to do. The right answer is probably "don't do it", you should use a Link Param set to restore the settings.
In most cases, once the "counters are exhausted", the state of the Param set is not want you want to restore from.
To use a Link Param set, follow one of the examples and make a copy of the Channel's Param set and put it into the Link Param set. This way, every time you finish the transfer completely, it can link to the Link set to copy the same values back to the Channel's Param set.
Ok, I'm trying to perform a McASP transfer using EDMA3 LLD and I can check a successful single transfer to buffer1.
Then, I configured the EDMA3
to perform a ping-pong transfer in order to process buffer1 and buffer2 alternately. I also use a callback1 function for transfer complete detection by means of while(irqRaised1 == 0u) loop and next forced irqRaised1 to 0. It woks fine just one time. After this, execution remains in a edma3 library function and does not return to main. What am I doing
wrong?
// Set B count reload as B count.
BRCnt = bcnt;
// Channel setup
tcc = EDMA3_DRV_TCC_ANY;
// AREVT1 McASP1 Receive Event
chId = 2;
// Request any DMA channel and any TCC with callback function
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_requestChannel (hEdma, &chId, &tcc,
(EDMA3_RM_EventQueue)0,
&callback1, NULL);
// If successful, allocate the two link channels.
if (edmaResult == EDMA3_DRV_SOK)
{
ch1Id = EDMA3_DRV_LINK_CHANNEL;
edmaResult = EDMA3_DRV_requestChannel (hEdma, &ch1Id, &tcc,
(EDMA3_RM_EventQueue)0,
&callback1, NULL);
}
// Master channel Param Set----------------------------
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setSrcParams (hEdma, chId, (Uint32)(srcBuffer),
EDMA3_DRV_ADDR_MODE_INCR,
EDMA3_DRV_W32BIT);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setDestParams (hEdma, chId, (Uint32)(dstBuffer1),
EDMA3_DRV_ADDR_MODE_INCR,
EDMA3_DRV_W32BIT);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setSrcIndex (hEdma, chId, srcbidx, srccidx);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setDestIndex (hEdma, chId, desbidx, descidx);
if (edmaResult == EDMA3_DRV_SOK)
if (syncType == EDMA3_DRV_SYNC_A)
edmaResult = EDMA3_DRV_setTransferParams (hEdma, chId, acnt, bcnt, ccnt,
BRCnt, EDMA3_DRV_SYNC_A);
else
edmaResult = EDMA3_DRV_setTransferParams (hEdma, chId, acnt, bcnt, ccnt,
BRCnt, EDMA3_DRV_SYNC_AB);
if (edmaResult == EDMA3_DRV_SOK)
// Transfer complete interrupt enable/disable.
edmaResult = EDMA3_DRV_setOptField (hEdma, chId,
EDMA3_DRV_OPT_FIELD_TCINTEN, 1u);
if (edmaResult == EDMA3_DRV_SOK)
// Intermediate transfer complete interrupt enable/disable.
edmaResult = EDMA3_DRV_setOptField (hEdma, chId,
EDMA3_DRV_OPT_FIELD_ITCINTEN, 0u);
// 1st link channel Param Set----------------------------
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setSrcParams (hEdma, ch1Id, (Uint32)(srcBuffer),
EDMA3_DRV_ADDR_MODE_INCR,
EDMA3_DRV_W32BIT);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setDestParams (hEdma, ch1Id, (Uint32)(dstBuffer2),
EDMA3_DRV_ADDR_MODE_INCR,
EDMA3_DRV_W32BIT);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setSrcIndex (hEdma, ch1Id, srcbidx, srccidx);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setDestIndex (hEdma, ch1Id, desbidx, descidx);
if (edmaResult == EDMA3_DRV_SOK)
if (syncType == EDMA3_DRV_SYNC_A)
edmaResult = EDMA3_DRV_setTransferParams (hEdma, ch1Id, acnt, bcnt, ccnt,
BRCnt, EDMA3_DRV_SYNC_A);
else
edmaResult = EDMA3_DRV_setTransferParams (hEdma, ch1Id, acnt, bcnt, ccnt,
BRCnt, EDMA3_DRV_SYNC_AB);
if (edmaResult == EDMA3_DRV_SOK)
// Transfer complete interrupt enable/disable.
edmaResult = EDMA3_DRV_setOptField (hEdma, ch1Id,
EDMA3_DRV_OPT_FIELD_TCINTEN, 1u);
if (edmaResult == EDMA3_DRV_SOK)
// Intermediate transfer complete interrupt enable/disable.
edmaResult = EDMA3_DRV_setOptField (hEdma, ch1Id,
EDMA3_DRV_OPT_FIELD_ITCINTEN, 0u);
// Link channels
if (edmaResult == EDMA3_DRV_SOK)
{
edmaResult = (
(EDMA3_DRV_linkChannel (hEdma, chId, ch1Id))
||
(EDMA3_DRV_linkChannel (hEdma, ch1Id, chId))
);
}
// Interrupt Clear Register
Edma3Regs->ICR = 0x00000004;
// Secondary Event Clear Register
Edma3Regs->SECR = 0xFFFFFFFF;
// Now enable the transfer
Edma3Regs->EESR = 0x00000004;
In the Training section of TI.com, there is a training video set for the C6474. There is one module there, EDMA3/QDMA/IDMA, which will apply directly to your current situation. You can find the complete video set at http://focus.ti.com/docs/training/catalog/events/event.jhtml?sku=OLT110002 . Then click on the EDMA3/QDMA/IDMA module to go through that specific module. There are details that differ between the C6474's EDMA3 and the OMAPL137's EDMA3, like number of channels and number of Transfer Controllers, but the majority of the module will be common to any EDMA3 implementation. You should go through the whole module, but the 4th major bullet section "Example #2 - Multiple Block Transfer" will show you how to implement Ping-Pong buffers. It does not use LLD, so the coding examples will not apply for you, but the concepts will be easy for you to move over to LLD once you see how it is done.
Gaston said:// Link channels
if (edmaResult == EDMA3_DRV_SOK)
{
edmaResult = (
(EDMA3_DRV_linkChannel (hEdma, chId, ch1Id))
||
(EDMA3_DRV_linkChannel (hEdma, ch1Id, chId))
);}
I recommend against this programming technique. You are counting on the return code specifically being 0 for SOK, which it is, but there is no reason to expect either linkChannel call to return a different result than the other.
Gaston said:// Interrupt Clear Register
Edma3Regs->ICR = 0x00000004;
// Secondary Event Clear Register
Edma3Regs->SECR = 0xFFFFFFFF;
// Now enable the transfer
Edma3Regs->EESR = 0x00000004;
I know I should not be critiquing your code, but I am surprised that after using all the LLD calls for everything, now you switch to direct register writes. Are there not LLD calls that can do some of these?
Also, I would recommend replacing the 0x4 constants for the ICR and EESR writes, instead using 1 << tcc and 1 << chId, respectively.
A rather revealing video, thanks! Then, ping-pong transfer sync AB works well and waits for completion by means of EDMA3_DRV_waitAndClearTcc function
Now, I would just like to know which buffer can be used to
process data. The application is for data analysis purposes. Therefore, I should have access to the ping-pong buffers
alternately for processing. How could I achieve this?
Regarding to the coding, I am open to any kind of improvement. So thanks for your comments. I just don't understand what do you means about SOK return code. I've copied this from LDD examples. Any suggestion?
// Set B count reload as B count.
BRCnt = bcnt;
// Channel setup
tcc = EDMA3_DRV_TCC_ANY;
// AREVT1 McASP1 Receive Event
chId = EDMA3_DRV_HW_CHANNEL_EVENT_2;
// Request any DMA channel and any TCC with callback function
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_requestChannel (hEdma, &chId, &tcc,
(EDMA3_RM_EventQueue)0,
NULL, NULL);
// If successful, allocate the two link channels.
if (edmaResult == EDMA3_DRV_SOK)
{
ch1Id = EDMA3_DRV_LINK_CHANNEL;
ch2Id = EDMA3_DRV_LINK_CHANNEL;
edmaResult = ((EDMA3_DRV_requestChannel (hEdma, &ch1Id, &tcc,
(EDMA3_RM_EventQueue)0,
NULL, NULL))
|| (EDMA3_DRV_requestChannel (hEdma, &ch2Id, &tcc,
(EDMA3_RM_EventQueue)0,
NULL, NULL)));
}
// Master channel Param Set----------------------------
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setSrcParams (hEdma, chId, (Uint32)(srcBuffer),
EDMA3_DRV_ADDR_MODE_INCR,
EDMA3_DRV_W32BIT);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setDestParams (hEdma, chId, (Uint32)(dstBuffer1),
EDMA3_DRV_ADDR_MODE_INCR,
EDMA3_DRV_W32BIT);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setSrcIndex (hEdma, chId, srcbidx, srccidx);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setDestIndex (hEdma, chId, desbidx, descidx);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setTransferParams (hEdma, chId, acnt, bcnt, ccnt,
BRCnt, EDMA3_DRV_SYNC_AB);
if (edmaResult == EDMA3_DRV_SOK)
// Transfer complete interrupt enable/disable.
edmaResult = EDMA3_DRV_setOptField (hEdma, chId,
EDMA3_DRV_OPT_FIELD_TCINTEN, 1u);
if (edmaResult == EDMA3_DRV_SOK)
// Intermediate transfer complete interrupt enable/disable.
edmaResult = EDMA3_DRV_setOptField (hEdma, chId,
EDMA3_DRV_OPT_FIELD_ITCINTEN, 0u);
// 1st link channel Param Set (Ping)----------------------
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setSrcParams (hEdma, ch1Id, (Uint32)(srcBuffer),
EDMA3_DRV_ADDR_MODE_INCR,
EDMA3_DRV_W32BIT);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setDestParams (hEdma, ch1Id, (Uint32)(dstBuffer1),
EDMA3_DRV_ADDR_MODE_INCR,
EDMA3_DRV_W32BIT);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setSrcIndex (hEdma, ch1Id, srcbidx, srccidx);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setDestIndex (hEdma, ch1Id, desbidx, descidx);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setTransferParams (hEdma, ch1Id, acnt, bcnt, ccnt,
BRCnt, EDMA3_DRV_SYNC_AB);
if (edmaResult == EDMA3_DRV_SOK)
// Transfer complete interrupt enable/disable.
edmaResult = EDMA3_DRV_setOptField (hEdma, ch1Id,
EDMA3_DRV_OPT_FIELD_TCINTEN, 1u);
if (edmaResult == EDMA3_DRV_SOK)
// Intermediate transfer complete interrupt enable/disable.
edmaResult = EDMA3_DRV_setOptField (hEdma, ch1Id,
EDMA3_DRV_OPT_FIELD_ITCINTEN, 0u);
// 2nd link channel Param Set (Pong)----------------------
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setSrcParams (hEdma, ch2Id, (Uint32)(srcBuffer),
EDMA3_DRV_ADDR_MODE_INCR,
EDMA3_DRV_W32BIT);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setDestParams (hEdma, ch2Id, (Uint32)(dstBuffer2),
EDMA3_DRV_ADDR_MODE_INCR,
EDMA3_DRV_W32BIT);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setSrcIndex (hEdma, ch2Id, srcbidx, srccidx);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setDestIndex (hEdma, ch2Id, desbidx, descidx);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_setTransferParams (hEdma, ch2Id, acnt, bcnt, ccnt,
BRCnt, EDMA3_DRV_SYNC_AB);
if (edmaResult == EDMA3_DRV_SOK)
// Transfer complete interrupt enable/disable.
edmaResult = EDMA3_DRV_setOptField (hEdma, ch2Id,
EDMA3_DRV_OPT_FIELD_TCINTEN, 1u);
if (edmaResult == EDMA3_DRV_SOK)
// Intermediate transfer complete interrupt enable/disable.
edmaResult = EDMA3_DRV_setOptField (hEdma, ch2Id,
EDMA3_DRV_OPT_FIELD_ITCINTEN, 0u);
// Link channels
if (edmaResult == EDMA3_DRV_SOK)
{
edmaResult = (
(EDMA3_DRV_linkChannel (hEdma, chId, ch2Id))
||
(EDMA3_DRV_linkChannel (hEdma, ch2Id, ch1Id))
||
(EDMA3_DRV_linkChannel (hEdma, ch1Id, ch2Id))
);
}
// enable tranfer!
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_enableTransfer (hEdma, chId,
EDMA3_DRV_TRIG_MODE_EVENT);
Gaston said:Now, I would just like to know which buffer can be used to process data. The application is for data analysis purposes. Therefore, I should have access to the ping-pong buffers alternately for processing. How could I achieve this?
After the first Transfer Completion Code is sent, you may use dstBuffer1 because it has been filled. Then after the next TCC is sent, you may use dstBuffer2. You will need to maintain a toggle flag that you change each time. For example,
void Tsk_DataProcessing()
{
int bPingPong = 0; // 0 == use Ping buffer, 1 == use Pong buffer
int *myDstBufPtr;
while (1)
{
[wait for TCC or interrupt or semaphore, as desired]
if ( bPingPong == 0 )
myDstBufPtr = dstBuffer1;
else
myDstBufPtr = dstBuffer2;
// toggle ping-pong flag
bPingPong ^= 1;
/*
process data in myDstBufPtr...
*/
}
}
Gaston said:Regarding to the coding, I am open to any kind of improvement. So thanks for your comments. I just don't understand what do you means about SOK return code. I've copied this from LDD examples.
Sorry, I had not been very familiar with the source for these examples, so I did not recognize it as being from our LLD example code.
Gaston said:if (edmaResult == EDMA3_DRV_SOK)
{
edmaResult = (
(EDMA3_DRV_linkChannel (hEdma, chId, ch2Id))
||
(EDMA3_DRV_linkChannel (hEdma, ch2Id, ch1Id))
||
(EDMA3_DRV_linkChannel (hEdma, ch1Id, ch2Id))
);
}
This code works only because EDMA3_DRV_SOK is defined to be 0. If it were defined to be any other value, this would not work. So this coding style does not allow for complete abstraction from the symbols to the code. I would prefer to see it written as
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_linkChannel (hEdma, chId, ch2Id);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_linkChannel (hEdma, ch2Id, ch1Id);
if (edmaResult == EDMA3_DRV_SOK)
edmaResult = EDMA3_DRV_linkChannel (hEdma, ch1Id, ch2Id);
But it all functions the same, and I do not have the Computer Science or Software Engineering credentials to argue the point with the authors. For me, it is just a personal preference, and not something for you to worry about since it comes from our example code.