|
EDMA |
Top Previous Next |
|
This section assumes you are familiar with the operation of the C6000 EDMA channels, in particular, the way in which EDMA transfers can be synchronised. The Diamond kernel manages the available EDMA 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 DMA operation, and return the channels to the kernel. Holding on to EDMA 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 EDMA to copy Frames blocks of 8 32-bit words from a device FIFO to memory at Buffer. The code assumes that the device asserts EXT_INT4 when it has 8 words available. The code does no error checking to keep it simple.
#include <edma.h> ¤1 #include <ext_int.h>
struct EDmaControl *C = EDMA_CTRL; // EDMA control registers SC6xEDMAChannel *channel; EDMA_REG *dma; SC6xEDMA *EdmaI; SC6xExt_Int *Ext_IntI;
EdmaI = SC6xKernel_LocateInterface(_kernel, SIID_SC6xEDMA); ¤2 Ext_IntI = SC6xKernel_LocateInterface(_kernel, SIID_SC6xExt_Int); ¤2
SC6xExt_Int_Claim(Ext_IntI, 4); // claim EXT_INT 4 ¤3
dma = SC6xEDMA_Claim(EdmaI, 4, &channel); ¤4
SC6xEDMA_FlushCache(EdmaI, 1, Frames*8*sizeof(int), Buffer); dma->opt = EDMA_2DS(1) | EDMA_LINK(1) | EDMA_TCINT(1) | EDMA_PRI(1) | EDMA_SUM(1) | EDMA_DUM(1) | EDMA_TCC(4); dma->cnt = ((Frames-1)<<16) + 8; dma->dst = Buffer; // destination buffer dma->src = DEVICE_FIFO; // device data address dma->idx = 0; dma->rld = EDMA_LINK_OFFSET(EDMA_NULL_PARAM);
C->ECR = 1<<4; // clear any pending events EnableMyDevice(); // for synchronisation SC6xEDMAChannel_StartWait(channel); // do the transfer ¤5 DisableMyDevice();
SC6xEDMAChannel_Release(channel); ¤6 SC6xExt_Int_Release(Ext_IntI, 4);
There are several things to notice about this code:
There is no obligation to use SC6xEDMAChannel_StartWait—it is provided to make handling EDMA interrupts easier—but you are free to wait for EDMA completion either by polling (certainly not recommended) or waiting for the interrupt yourself with (SC6xEDMAChannel_AwaitInterrupt). The only mandatory step is to claim the EDMA 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 or link.h call in some other task or thread, and the kernel then decides to service that call using the same EDMA channel that you are already using for something else.
|