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:

 


¤1

edma.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 EDMA 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 pointers once on program startup.


¤3

The code is using an external interrupt line (EXT_INT4), so it needs to claim that interrupt line from the kernel to prevent it being used elsewhere. You do not need to claim an external interrupt line if you are using devices that have dedicated interrupt lines, for example, the McBSP devices which use interrupts 1215).


¤4

SC6xEDMA_Claim actually claims the channel (DMA4). It returns a pointer to the corresponding EDMA 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.


¤5

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


¤6

SC6xEDMAChannel_Release informs the kernel that a previously claimed EDMA 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 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.