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:

 


¤1

edma3.h declares the kernel functions used in the rest of the code and creates a reference, _kernel, to kernel data structures. It also contains a typedef for a structure type, EDMA_REG, which can be used to access the EDMA3 transfer parameters, plus macros for accessing the various fields within the EDMA registers. EDMA_CTRL is also defined to be a pointer to the hardware’s block of EDMA control registers


¤2

Production code would not call SC6xKernel_LocateInterface for every transfer but would initialise the interface pointer once on program startup.


¤3

SC6xEDMA_Claim actually claims the channel (DMA #52 corresponding to the synchronisation event, GPIO event 4). It returns a pointer to the corresponding EDMA3 transfer parameters, or NULL if the requested DMA engine cannot be allocated (because it is already claimed by another thread or by the kernel for an inter-processor link communication). Using this pointer, the example code then fills in the required values. If SC6xEDMA_Claim succeeds, it returns an SC6xEDMAChannel pointer via its final argument. This pointer refers to a software structure in the kernel that describes the allocated DMA channel.


¤4

Beware: the C6000 cache cannot maintain coherence with external memory used in EDMA3 transfers. You must explicitly flush the cache when necessary to ensure correct operation.


¤5

SC6xEDMAChannel_StartWait is one of the functions that can be applied to such an EDMA3 channel pointer. It sets up the various EDMA3 control registers needed to control the transfer and then suspends the calling thread until the EDMA3 channel interrupts at the end of the block. While the thread is suspended and the EDMA3 operation is executing, other threads can continue to execute on the CPU. The kernel catches the EDMA3 completion interrupt, resumes the suspended thread and returns control to the caller.


¤6

SC6xEDMAChannel_Release informs the kernel that a previously claimed EDMA3 channel is no longer required and can be returned to the kernel’s pool of free channels.

 

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.