|
EDMA3 |
Top Previous Next |
|
This section assumes you are familiar with the operation of the C6000 EDMA3 channels, in particular, the way in which EDMA3 transfers can be synchronised. The Diamond kernel manages the available EDMA3 channels and dynamically allocates them to concurrently active inter-processor <chan.h> calls.
User code that wants to make direct use of the channels must claim them from the kernel, complete the DMA3 operation, and return the channels to the kernel. Holding on to EDMA3 channels can seriously affect the performance of other transfers, in particular, link operations.
Note that many of the functions described here need to be passed a pointer to the EDMA interface (SC6xEDMA *); this interface can be found using SC6xKernel_LocateInterface, as below.
The following code fragment illustrates using EDMA3 to copy 999 blocks of 8 32-bit words from a device FIFO to memory at Buffer. The code assumes that the device asserts GPIO event 4 when it has 8 words available; this will have been configured by device-specific code that is not relevant to this discussion. The code does no error checking to keep it simple.
#include <edma3.h> ¤1 #include <ext_int.h>
struct EDmaControl *C = EDMA_CTRL; // EDMA control registers SC6xEDMAChannel *channel; EDMA_REG *dma; SC6xEDMA *EdmaI;
EdmaI = SC6xKernel_LocateInterface(_kernel, SIID_SC6xEDMA); ¤2 Ext_IntI = SC6xKernel_LocateInterface(_kernel, SIID_SC6xExt_Int); ¤2
dma = SC6xEDMA_Claim(EdmaI, 52, &channel); ¤3
EDMA_FlushCache(EdmaI, 1, 999*8*sizeof(int), Buffer); ¤4
dma->bacnt = (999 <<16) | 4*8; // bcount=999, acount=8 words dma->bcrlink = 0xFFFF; dma->ccnt = 1; dma->opt = 0 // all bits zero except the following | EDMA_PRIV(1) // supervisor mode | EDMA_TCINTEN(1) // interrupt at end | EDMA_TCC(52); // to terminate this DMA transaction dma->src = DEVICE_FIFO; // depends on your device dma->dst = Buffer; dma->dsbidx = 4*8; // B index bytes: dst=32 src=0 bytes dma->dscidx = 4*8; // C index bytes: dst=32 src=0 bytes
EDMAChannel_ResetEvent(channel); EnableMyDevice(); // for synchronisation EDMAChannel_StartWait(channel); // do the transfer ¤5 DisableMyDevice();
SC6xEDMAChannel_Release(channel); ¤6
There are several things to notice about this code:
There is no obligation to use SC6xEDMAChannel_StartWait—it is provided to make handling EDMA3 interrupts easier—but you are free to wait for EDMA3 completion either by polling (certainly not recommended) or waiting for the interrupt yourself with (SC6xEDMAChannel_AwaitInterrupt). The only mandatory step is to claim the EDMA3 channel before attempting to touch the corresponding hardware. Failure to do so will result in mysterious hangs when your code clashes with a concurrent inter-processor chan.h call in some other task or thread, and the kernel then decides to service that call using the same EDMA3 channel that you are already using for something else.
|