📄 memdma_2d.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.
$RCSfile: memdma_2D.c,v $
$Revision: 1.3 $
$Date: 2007/06/25 15:31:17 $
***********************************************************************************
Please refer to the 'readme.txt' file for a description of the Interrupt Manager Examples.
*********************************************************************
Include files
*********************************************************************/
#include <services/services.h>
#include "ezkitutilities.h"
/*********************************************************************
Enumerations and defines
*********************************************************************/
#define MEMORY_COPY_SIZE_X 256 // number of bytes in X direction
#define MEMORY_COPY_SIZE_Y 128 // number of bytes in Y direction
#define SQUARE_MATRIX_SIZE 128 // dimensions for a square matrix
#define CALLBACK_QUEUE_SIZE 4
#define OUR_CLIENT_ID 54321 // this is for whatever this application wants, pick any number
/*********************************************************************
Data Structures
*********************************************************************/
// These are placed in SDRAM
section("sdram0") static u8 memory_buffer_source[MEMORY_COPY_SIZE_X][MEMORY_COPY_SIZE_Y];
section("sdram0") static u8 memory_buffer_destination[MEMORY_COPY_SIZE_X][MEMORY_COPY_SIZE_Y];
section("sdram0") static u8 memory_buffer_column[MEMORY_COPY_SIZE_X];
ADI_DMA_MANAGER_HANDLE DMA_Handle;
void *Channel_Handle;
/*********************************************************************
Static data
*********************************************************************/
// Callback manager necessary stuff
static ADI_DCB_HANDLE Callback_Handle;
static u8 Callback_Manager_Storage[ADI_DCB_QUEUE_SIZE];
static u8 Callback_Queue[ADI_DCB_ENTRY_SIZE * CALLBACK_QUEUE_SIZE];
// DMA manager necessary stuff (always need 2 channels for a memory copy)
static u8 DMA_Manager_Storage[ADI_DMA_BASE_MEMORY + ADI_DMA_CHANNEL_MEMORY*2];
// storage for interrupt manager data
static u8 IntMgrData[(2*ADI_INT_SECONDARY_MEMORY)];
// flag between main and the callback routine
// to indicate when the DMA is completed
volatile enum {
waiting_for_callback_to_happen,
callback_happened
} Callback_Flag;
/*********************************************************************
prototypes
*********************************************************************/
u32 CheckMemory(void);
void SetupMemory(void);
/*********************************************************************
test code
*********************************************************************/
static ADI_INT_HANDLER(Simple_Exception_Handler) {
ezErrorCheck(1);
return(ADI_INT_RESULT_PROCESSED);
}
static ADI_INT_HANDLER(Simple_Hardware_Error_Handler) {
ezErrorCheck(1);
return(ADI_INT_RESULT_PROCESSED);
}
void set_up_error_handling (void) {
// hook the exception interrupt
ezErrorCheck( adi_int_CECHook(3, Simple_Exception_Handler, NULL, FALSE) != ADI_INT_RESULT_SUCCESS);
// hook the hardware error
ezErrorCheck( adi_int_CECHook(5, Simple_Hardware_Error_Handler, NULL, FALSE) != ADI_INT_RESULT_SUCCESS);
}
/*********************************************************************
Static functions
*********************************************************************/
// This is the callback function for the DMA.
static void Memory_Callback(
void *AppHandle,
u32 Event,
void *pArg)
{
// watch for errors
if (Event == ADI_DMA_EVENT_ERROR_INTERRUPT) {
ezErrorCheck(1);
}
Callback_Flag = callback_happened;
}
//
// Initializes the source memory with a psuedo-random pattern.
// Also zeros out the destination memory.
static void SetupMemory() {
u32 x, y;
// set source buffer to our pseudo-random pattern...
// ...and set destination buffer to all zeros.
for( x=0; x<MEMORY_COPY_SIZE_X; x++) {
for( y=0; y<MEMORY_COPY_SIZE_Y; y++) {
memory_buffer_source[x][y] = rand()>>24; // get an 8-bit random number
memory_buffer_destination[x][y] = 0;
}
}
// clear out the column buffer in case we want to use it
for( x=0; x<MEMORY_COPY_SIZE_X; x++) {
memory_buffer_column[x] = 0;
}
}
//
// Check if the source memory was correctly copied to the destination.
// Return the result.
static u32 CheckMemory() {
u32 x, y;
for( x=0; x<MEMORY_COPY_SIZE_X; x++) {
for( y=0; y<MEMORY_COPY_SIZE_Y; y++) {
if( memory_buffer_source[x][y] != memory_buffer_destination[x][y]) {
return(1);
}
}
}
return(0);
}
/*********************************************************************
*
* Function: main
*
*********************************************************************/
void main(void) {
ADI_DMA_2D_TRANSFER src_info, dst_info;
u32 x, y;
int Result; // location to store result from system services calls
u32 Response_Count; // location to store result from system services calls
volatile u32 i; // "volatile" is used to avoid optimizing out a delay loop below.
// initialize the interrupt manager
ezErrorCheck(adi_int_Init(IntMgrData, sizeof(IntMgrData), &Response_Count, NULL));
// initialize EZ-Kit; power and EBIU services
ezInit(1);
// set up exception and error handlers
set_up_error_handling();
// initialize DMA
ezErrorCheck( adi_dma_Init(DMA_Manager_Storage, sizeof(DMA_Manager_Storage), &Response_Count, &DMA_Handle, NULL));
//Initialize the flag service, memory is not passed because callbacks are not being used
ezErrorCheck(adi_flag_Init(NULL, 0, &Response_Count, NULL));
//Initialize all LEDS
for (i = EZ_FIRST_LED; i < EZ_NUM_LEDS; i++){
ezInitLED(i);
}
// Dual core processors actually have different names for the memory DMA channels
// so we need to look at which processor we are using.
#if defined(__ADSPBF561__)
// dual core processors: use different streams for each core, which one to use for each core is arbitrary.
if( adi_core_id() == 0) {
ezErrorCheck( adi_dma_MemoryOpen(DMA_Handle, ADI_DMA_MDMA1_0, (void *)OUR_CLIENT_ID, &Channel_Handle, Callback_Handle));
} else {
ezErrorCheck( adi_dma_MemoryOpen(DMA_Handle, ADI_DMA_MDMA2_0, (void *)OUR_CLIENT_ID, &Channel_Handle, Callback_Handle));
}
#else
// single core processors
ezErrorCheck( adi_dma_MemoryOpen(DMA_Handle, ADI_DMA_MDMA_0, main, &Channel_Handle, Callback_Handle));
#endif
//
// First, copy a 1-byte wide, simple 2-D array without using callbacks
//
SetupMemory();
src_info.StartAddress = &memory_buffer_source[0][0];
src_info.XCount = MEMORY_COPY_SIZE_X;
src_info.XModify = 1; // typically the same as element width
src_info.YCount = MEMORY_COPY_SIZE_Y;
src_info.YModify = 1; // typically the same as element width
dst_info.StartAddress = &memory_buffer_destination[0][0];
dst_info.XCount = MEMORY_COPY_SIZE_X;
dst_info.XModify = 1; // typically the same as element width
dst_info.YCount = MEMORY_COPY_SIZE_Y;
dst_info.YModify = 1; // typically the same as element width
ezErrorCheck( adi_dma_MemoryCopy2D(Channel_Handle, &dst_info, &src_info, 1, NULL));
ezErrorCheck( CheckMemory() );
//
// Next, try it with 4-byte wide, simple 2-D array without using callbacks
//
SetupMemory();
// The Count variable specifies bytes, not elements! That's why it's the same as above.
src_info.StartAddress = &memory_buffer_source[0][0];
src_info.XCount = MEMORY_COPY_SIZE_X; // Notice that we still specify the same count
src_info.XModify = 4; // typically the same as element width
src_info.YCount = MEMORY_COPY_SIZE_Y; // Notice that we still specify the same count
src_info.YModify = 4; // typically the same as element width
dst_info.StartAddress = &memory_buffer_destination[0][0];
dst_info.XCount = MEMORY_COPY_SIZE_X; // Notice that we still specify the same count
dst_info.XModify = 4; // typically the same as element width
dst_info.YCount = MEMORY_COPY_SIZE_Y; // Notice that we still specify the same count
dst_info.YModify = 4; // typically the same as element width
// Make sure to use 4 bytes in the call below instead of 1 byte.
ezErrorCheck( adi_dma_MemoryCopy2D(Channel_Handle, &dst_info, &src_info, 4, NULL));
ezErrorCheck( CheckMemory() );
//
// Next, this is how to pull a column out of a 2-D matrix, without callbacks
//
SetupMemory();
// Get column 3 from the 2-D source array into a 1-D destination array.
src_info.StartAddress = &memory_buffer_source[0][3];
src_info.XCount = MEMORY_COPY_SIZE_X; // go through all rows of the 2-D source
src_info.XModify = MEMORY_COPY_SIZE_Y; // hop down to the next row after every fetch
src_info.YCount = 1; // since we just want 1 column, use 1
src_info.YModify = 1; // we just want 1 column
dst_info.StartAddress = &memory_buffer_column[0];
dst_info.XCount = MEMORY_COPY_SIZE_X; // for the destination, make it act like a 1-D copy
dst_info.XModify = 1; // for the destination, make it act like a 1-D copy
dst_info.YCount = 1; // for the destination, make it act like a 1-D copy
dst_info.YModify = 1; // for the destination, make it act like a 1-D copy
ezErrorCheck( adi_dma_MemoryCopy2D(Channel_Handle, &dst_info, &src_info, 1, NULL));
// Now verify the memory
for(i=0; i<MEMORY_COPY_SIZE_X; i++) {
if( memory_buffer_source[i][3] != memory_buffer_column[i] ) {
ezErrorCheck(1); // there was a mismatch, light all the LEDs
}
}
//
// From this point on, start using callbacks
//
// initialize callbacks
ezErrorCheck( adi_dcb_Init(Callback_Manager_Storage, sizeof(Callback_Manager_Storage), &Response_Count, NULL));
// open a callback queue
ezErrorCheck( adi_dcb_Open(ik_ivg14, Callback_Queue, sizeof(Callback_Queue), &Response_Count, &Callback_Handle));
//
// Next, show how to transpose a square 2-D matrix, with callbacks
//
SetupMemory();
// Assume a matrix with dimensions SQUARE_MATRIX_SIZE x SQUARE_MATRIX_SIZE
src_info.StartAddress = &memory_buffer_source[0][0];
src_info.XCount = SQUARE_MATRIX_SIZE;
src_info.XModify = SQUARE_MATRIX_SIZE; // hop down to the next row after every fetch
src_info.YCount = SQUARE_MATRIX_SIZE; // do all of the columns
//
// The next statement is the tricky part. After doing the Nth element of all rows, move to the next column
// by DECREMENTING by one less than the size of the matrix with one row missing.
//
// here's a 3x3 example:
//
// a b c
// d e f
// g h i
//
// a b c d e f g h i
// we want to do: a, d, g, b, e, h, c, f, i
// which means we move by: 3, 3,-5, 3, 3,-5, 3, 3
// note that -5 == -(( 3 * (3 - 1) ) - 1)
src_info.YModify = -((SQUARE_MATRIX_SIZE * (SQUARE_MATRIX_SIZE - 1) ) - 1); // note it's a negative modify value
// The destination just takes that stream of elements and constructs an ordinary matrix
dst_info.StartAddress = &memory_buffer_destination[0][0];
dst_info.XCount = SQUARE_MATRIX_SIZE; // just like the destination of a normal matrix copy
dst_info.XModify = 1; // just like the destination of a normal matrix copy
dst_info.YCount = SQUARE_MATRIX_SIZE; // just like the destination of a normal matrix copy
dst_info.YModify = 1; // just like the destination of a normal matrix copy
Callback_Flag = waiting_for_callback_to_happen;
ezErrorCheck( adi_dma_MemoryCopy2D(Channel_Handle, &dst_info, &src_info, 1, &Memory_Callback));
// Wait for the DMA to finish.
// If the program is stuck here, the callback never happened and the DMA did not work.
while(Callback_Flag != callback_happened);
// Now check if the result is transposed
for(x=0; x<SQUARE_MATRIX_SIZE; x++) {
for(y=0; y<SQUARE_MATRIX_SIZE; y++) {
if( memory_buffer_source[x][y] != memory_buffer_destination[y][x] ) {
ezErrorCheck(1); // The matrix was not transposed correctly
}
}
}
// All done, success
while(1) {
for(i=0; i<0x00FFFFFF; i++); // delay for a little while
ezCycleLEDs();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -