📄 chained_dma.c
字号:
/*********************************************************************************
Copyright(c) 2004 Analog Devices, Inc. All Rights Reserved.
This software is proprietary and confidential. By using this software you agree
to the terms of the associated Analog Devices License Agreement.
***********************************************************************************
Description:
This example performs a 1-dimensional DMA operation from memory to memory (without
using the memory-to-memory system services API). This differs from normal peripheral
DMA operations because memory DMA operations require 2 channels (one to get the
source memory and one to place into the destination memory).
Memory is copied from one location in SDRAM to another SDRAM location using a chain
of buffer descriptors. Chaining buffers this way is a common method of doing DMA.
When the DMA completes successfully, the LEDs will cycle slowly. If there is an
error anywhere, all the LEDs will light up.
You can adjust the number of BUFFERS, the number of ELEMENTS in each buffer, and the
number of BYTES_PER_ELEMENT below. Keep in mind that you can easily go beyond
the amount of SDRAM memory in the EZ-Kit.
NOTE: IN NORMAL DMA OPERATIONS, YOU WILL ONLY USE ONE CHANNEL. WE USE 2 CHANNELS
HERE BECAUSE IT'S NEEDED FOR MEMORY-TO-MEMORY DMA. There is a separate (and much
simpler) API for doing memory-to-memory DMA. This is just an example.
$RCSfile: chained_DMA.c,v $
$Revision: 1.3 $
$Data: $
Revision History:
*********************************************************************
Include files
*********************************************************************/
#include <services/services.h> // system service includes
#include <drivers/adi_dev.h> // device drivers includes
#include "ezkitutilities.h" // basic utilities for the EZ-Kit board
/*********************************************************************
Enumerations and defines
*********************************************************************/
#define BUFFERS 5 // number of descriptors in the chain (limited only by memory)
#define ELEMENTS 20 // number of words of data per descriptor ( > 1)
#define BYTES_PER_ELEMENT 4 // number of bytes in each word (1, 2, or 4)
// Define some space in SDRAM for memory DMAs
#define SDRAM_DATA_START 0x00001000 // We use SDRAM data starting at this address
#define SOURCE_DATA_START SDRAM_DATA_START
#define DESTINATION_DATA_START (SDRAM_DATA_START + (BUFFERS * ELEMENTS * BYTES_PER_ELEMENT))
/*********************************************************************
Data Structures
*********************************************************************/
/*********************************************************************
Static data
*********************************************************************/
// The DMA can hook error handlers, so we should have one secondary handler per DMA channel
static u8 InterruptManagerStorage[ADI_INT_SECONDARY_MEMORY * 2];
// Descriptors contain information about what to copy. In this example,
// we chain multiple descriptors together so all of them are executed
// by the Blackfin DMA engine.
static ADI_DMA_DESCRIPTOR_LARGE DestinationBuffers[BUFFERS]; // descriptors where data is written to
static ADI_DMA_DESCRIPTOR_LARGE SourceBuffers[BUFFERS]; // descriptors where data is written from
// DMA Manager data (base memory + memory for 2 DMA channels, since memory DMA requires 2)
static u8 DMAMgrData[ADI_DMA_BASE_MEMORY + (ADI_DMA_CHANNEL_MEMORY * 2)];
static ADI_DMA_MANAGER_HANDLE DMAManagerHandle; // handle for the whole DMA manager
ADI_DMA_CHANNEL_HANDLE dma_s0_chan_handle; // source DMA channel handle
ADI_DMA_CHANNEL_HANDLE dma_d0_chan_handle; // destination DMA channel handle
// Deferred Callback Manager data (memory for 1 service plus 1 posted callbacks)
static u8 DCBMgrData[ADI_DCB_QUEUE_SIZE + ADI_DCB_ENTRY_SIZE];
static ADI_DCB_HANDLE CallbackHandle; // handle to the callback service
static u8 CallbackQueue[ADI_DCB_ENTRY_SIZE*10]; // callback queue
volatile u32 DmaDoneFlag = 0; // flag between callback and main
/*********************************************************************
prototypes
*********************************************************************/
char get_random_char(void);
/*********************************************************************
test code
*********************************************************************/
// Exception handler to catch exceptions which can occur when you do something wrong
static ADI_INT_HANDLER(ExceptionHandler)
{
ezErrorCheck(1);
return(ADI_INT_RESULT_PROCESSED);
}
// Hardware error handler to catch problems with the hardware.
static ADI_INT_HANDLER(HWErrorHandler)
{
ezErrorCheck(1);
return(ADI_INT_RESULT_PROCESSED);
}
// This routine simple generates random characters
static char get_random_char() {
char x;
x = rand() % 26;
x += 'a';
return x;
}
/*********************************************************************
*
* Function: callback
*
*********************************************************************/
static void Callback( // callback function called by DCB
void *AppHandle,
u32 Event,
void *pArg)
{
switch(Event) {
case ADI_DMA_EVENT_DESCRIPTOR_PROCESSED:
DmaDoneFlag = 1; // Tell main() that the DMA is done.
break;
case ADI_DMA_EVENT_INNER_LOOP_PROCESSED: // this is only used with 2-D DMA
ezErrorCheck(1);
break;
case ADI_DMA_EVENT_OUTER_LOOP_PROCESSED: // we're not using this feature of DMA
ezErrorCheck(1);
break;
case ADI_DMA_EVENT_ERROR_INTERRUPT: // this is a common error when debugging DMA applications
ezErrorCheck(1); // <--- you might want to set a breakpoint here
break;
default: // unexpected events
ezErrorCheck(1);
break;
}
}
//
// Set up the inbound and outbound buffers based on
// the specified parameters.
//
void buffer_setup(
int buffs, // number of buffers (descriptors) to use in each direction
int elements, // number of elements in each buffer (descriptor)
int bytes_per_element) // number of bytes in each element (1, 2, or 4)
{
ADI_DMA_CONFIG_REG config;
int i, j, k;
int data_index;
u8 *pTemp;
void *debug;
// Set up the configuration register for DMA. Some of the bits
// are set up by the DMA manager which will over-write anything
// you place in them, so watch out for that.
//
// config.b_DMA_EN set by DMA manager
if(bytes_per_element == 1) { // careful not to confuse 0,1,2 values with 1, 2, and 4 bytes
config.b_WDSIZE = 0; // 0=8bits (1 byte)
} else if(bytes_per_element == 2) {
config.b_WDSIZE = 1; // 1=16bits (2 bytes)
} else if(bytes_per_element == 4) {
config.b_WDSIZE = 2; // 2=32bits (4 bytes)
} else {
ezErrorCheck(1);
}
config.b_DMA2D = 0; // 0 = 1-dimensional DMA, 1 = 2-dimensional DMA
// config.b_RESTART set by DMA manager
// config.b_DI_SEL set by DMA manager
// config.b_DI_EN set below (for both source and destination)
// config.b_NDSIZE set by DMA manager
// config.b_FLOW set by DMA manager
config.b_WNR = 1; // 0 = memory read, 1 = memory write
for (i = 0; i < buffs; i++) { // set up all the buffers (descriptors) for writing TO memory
DestinationBuffers[i].StartAddress = (void *)(DESTINATION_DATA_START * i * ELEMENTS * BYTES_PER_ELEMENT); // SDRAM
DestinationBuffers[i].Config = config; // the config register we set up earlier
DestinationBuffers[i].XCount = elements;
DestinationBuffers[i].XModify = bytes_per_element;
DestinationBuffers[i].YCount = 1; // this is for 2-dimensional DMA only
DestinationBuffers[i].YModify = 1; // this is for 2-dimensional DMA only
if (i == (buffs-1)) {
DestinationBuffers[i].CallbackFlag = TRUE; // interrupt on the last descriptor only
DestinationBuffers[i].pNext = NULL; // the last descriptor always points to zero!
} else {
DestinationBuffers[i].CallbackFlag = FALSE; // don't interrupt on intermediate descriptors
DestinationBuffers[i].pNext = &DestinationBuffers[i+1]; // point to the next buffer in the chain
}
}
// The source uses slightly different config register settings
config.b_WNR = 0; // 0=memory read, 1=memory write
config.b_DI_EN = 0; // don't interrupt on outbound data
for (i = 0; i < buffs; i++) { // set up all the buffers (descriptors) for writing FROM memory
SourceBuffers[i].StartAddress = (void *)(SOURCE_DATA_START * i * ELEMENTS * BYTES_PER_ELEMENT); //SDRAM
SourceBuffers[i].Config = config; // the config register we set up earlier
SourceBuffers[i].XCount = elements;
SourceBuffers[i].XModify = bytes_per_element;
SourceBuffers[i].YCount = 1; // this is for 2-dimensional DMA only
SourceBuffers[i].YModify = 1; // this is for 2-dimensional DMA only
if (i == (buffs-1)) // Notice we only use interrupts in the destination DMA
SourceBuffers[i].pNext = NULL; // the last descriptor always points to zero!!
else
SourceBuffers[i].pNext = &SourceBuffers[i+1]; // point to the next buffer in the chain
pTemp = (u8 *)SourceBuffers[i].StartAddress; // Now we write some sample data into the source memory
for(j=0; j<elements; j++) { // which will be copied over to the destination memory.
for(k=0; k<bytes_per_element; k++) {
*pTemp++ = get_random_char();
}
}
}
}
/*********************************************************************
*
* Function: main
*
*********************************************************************/
void main(void) {
ADI_DEV_CMD_VALUE_PAIR *pCommandPair;
u32 i, j;
u32 ResponseCount;
ADI_DEV_1D_BUFFER *pOutboundBuffer;
ADI_DEV_1D_BUFFER *pFirstBuffer;
unsigned int Flag;
char* TmpPtr;
u8 *pSource;
u8 *pDestination;
// initialize the EZ-Kit
ezInit(1);
// initialize interrupt manager
ezErrorCheck(adi_int_Init(InterruptManagerStorage, sizeof(InterruptManagerStorage), &ResponseCount, NULL));
// we're not bothering to check ResponseCount
// hook the hardware error
ezErrorCheck(adi_int_CECHook(5, HWErrorHandler, NULL, FALSE));
// hook the exception interrupt
ezErrorCheck(adi_int_CECHook(3, ExceptionHandler, NULL, FALSE));
// initialize callbacks
ezErrorCheck(adi_dcb_Init(DCBMgrData, sizeof(DCBMgrData), &ResponseCount, NULL)); // we're not bothering to check ResponseCount
// create a callback queue
ezErrorCheck(adi_dcb_Open(ik_ivg14, CallbackQueue, sizeof(CallbackQueue), &ResponseCount, &CallbackHandle)); // we're not bothering to check ResponseCount
//Initialize the flag service, memory is not passed because callbacks are not being used
ezErrorCheck(adi_flag_Init(NULL, 0, &ResponseCount, NULL));
//Initialize all LEDS
for (i = EZ_FIRST_LED; i < EZ_NUM_LEDS; i++){
ezInitLED(i);
}
// initialize the DMA manager
ezErrorCheck(adi_dma_Init(DMAMgrData, sizeof(DMAMgrData), &ResponseCount, &DMAManagerHandle, NULL)); // we're not bothering to check ResponseCount
// setup the descriptors and data
buffer_setup(BUFFERS, ELEMENTS, BYTES_PER_ELEMENT);
#if defined(__ADSPBF561__)
// open the source DMA channel
ezErrorCheck( adi_dma_Open(DMAManagerHandle, ADI_DMA_MDMA1_S0, (void *)0, &dma_s0_chan_handle, ADI_DMA_MODE_DESCRIPTOR_LARGE, CallbackHandle, Callback));
// open the destination DMA channel
ezErrorCheck( adi_dma_Open(DMAManagerHandle, ADI_DMA_MDMA1_D0, (void *)0, &dma_d0_chan_handle, ADI_DMA_MODE_DESCRIPTOR_LARGE, CallbackHandle, Callback));
#else // The other processors use the same names for the DMA channels
// open the source DMA channel
ezErrorCheck( adi_dma_Open(DMAManagerHandle, ADI_DMA_MDMA_S0, (void *)0, &dma_s0_chan_handle, ADI_DMA_MODE_DESCRIPTOR_LARGE, CallbackHandle, Callback));
// open the destination DMA channel
ezErrorCheck( adi_dma_Open(DMAManagerHandle, ADI_DMA_MDMA_D0, (void *)0, &dma_d0_chan_handle, ADI_DMA_MODE_DESCRIPTOR_LARGE, CallbackHandle, Callback));
#endif
// queue the source descriptors first (normal DMA operations only use 1 channel)
ezErrorCheck( adi_dma_Queue( dma_s0_chan_handle, (ADI_DMA_DESCRIPTOR_HANDLE)&SourceBuffers[0]));
// queue the destination descriptors
ezErrorCheck( adi_dma_Queue( dma_d0_chan_handle, (ADI_DMA_DESCRIPTOR_HANDLE)&DestinationBuffers[0]));
// start the DMA transfer at the source side first (normal DMA operations only use 1 channel)
ezErrorCheck( adi_dma_Control( dma_s0_chan_handle, ADI_DMA_CMD_SET_DATAFLOW, (void *)TRUE));
// start the DMA transfer at the destination side
ezErrorCheck( adi_dma_Control( dma_d0_chan_handle, ADI_DMA_CMD_SET_DATAFLOW, (void *)TRUE));
while(DmaDoneFlag == 0); // Wait for the DMA to finish
// shut off the source DMA channel
ezErrorCheck( adi_dma_Control( dma_s0_chan_handle, ADI_DMA_CMD_SET_DATAFLOW, (void *)FALSE));
// shut off the destination DMA channel
ezErrorCheck( adi_dma_Control( dma_d0_chan_handle, ADI_DMA_CMD_SET_DATAFLOW, (void *)FALSE));
// close the destination DMA channel
ezErrorCheck( adi_dma_Close( dma_d0_chan_handle, TRUE));
// close the source DMA channel
ezErrorCheck( adi_dma_Close( dma_s0_chan_handle, TRUE));
// Successful DMA transfer? Let's check if it worked...
for(i=0; i<BUFFERS; i++) {
pSource = (u8 *)(SOURCE_DATA_START * i * ELEMENTS * BYTES_PER_ELEMENT);
pDestination = (u8 *)(DESTINATION_DATA_START * i * ELEMENTS * BYTES_PER_ELEMENT);
for(j=0; j<(ELEMENTS*BYTES_PER_ELEMENT); j++) {
if( *pSource++ != *pDestination++ ) {
ezErrorCheck(1);
}
}
}
for(i=0; i<30; i++) {
ezCycleLEDs();
ezDelay(100);
}
ezTurnOffAllLEDs();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -