⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chained_dma.c

📁 ADI公司blackfin DSP开发板BF533 EZ-KIT LITE附带的全部原代码
💻 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 + -