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

📄 mcbsp_ad535.c

📁 Using DSP/BIOS I/O in Multichannel Systems
💻 C
字号:
/* ***********************************************************
* THIS PROGRAM IS PROVIDED "AS IS". TI MAKES NO WARRANTIES OR
* REPRESENTATIONS, EITHER EXPRESS, IMPLIED OR STATUTORY, 
* INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 
* FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR 
* COMPLETENESS OF RESPONSES, RESULTS AND LACK OF NEGLIGENCE. 
* TI DISCLAIMS ANY WARRANTY OF TITLE, QUIET ENJOYMENT, QUIET 
* POSSESSION, AND NON-INFRINGEMENT OF ANY THIRD PARTY 
* INTELLECTUAL PROPERTY RIGHTS WITH REGARD TO THE PROGRAM OR 
* YOUR USE OF THE PROGRAM.
*
* IN NO EVENT SHALL TI BE LIABLE FOR ANY SPECIAL, INCIDENTAL, 
* CONSEQUENTIAL OR INDIRECT DAMAGES, HOWEVER CAUSED, ON ANY 
* THEORY OF LIABILITY AND WHETHER OR NOT TI HAS BEEN ADVISED 
* OF THE POSSIBILITY OF SUCH DAMAGES, ARISING IN ANY WAY OUT 
* OF THIS AGREEMENT, THE PROGRAM, OR YOUR USE OF THE PROGRAM. 
* EXCLUDED DAMAGES INCLUDE, BUT ARE NOT LIMITED TO, COST OF 
* REMOVAL OR REINSTALLATION, COMPUTER TIME, LABOR COSTS, LOSS 
* OF GOODWILL, LOSS OF PROFITS, LOSS OF SAVINGS, OR LOSS OF 
* USE OR INTERRUPTION OF BUSINESS. IN NO EVENT WILL TI'S 
* AGGREGATE LIABILITY UNDER THIS AGREEMENT OR ARISING OUT OF 
* YOUR USE OF THE PROGRAM EXCEED FIVE HUNDRED DOLLARS 
* (U.S.$500).
*
* Unless otherwise stated, the Program written and copyrighted 
* by Texas Instruments is distributed as "freeware".  You may, 
* only under TI's copyright in the Program, use and modify the 
* Program without any charge or restriction.  You may 
* distribute to third parties, provided that you transfer a 
* copy of this license to the third party and the third party 
* agrees to these terms by its first use of the Program. You 
* must reproduce the copyright notice and any other legend of 
* ownership on each copy or partial copy, of the Program.
*
* You acknowledge and agree that the Program contains 
* copyrighted material, trade secrets and other TI proprietary 
* information and is protected by copyright laws, 
* international copyright treaties, and trade secret laws, as 
* well as other intellectual property laws.  To protect TI's 
* rights in the Program, you agree not to decompile, reverse 
* engineer, disassemble or otherwise translate any object code 
* versions of the Program to a human-readable form.  You agree 
* that in no event will you alter, remove or destroy any 
* copyright notice included in the Program.  TI reserves all 
* rights not specifically granted under this license. Except 
* as specifically provided herein, nothing in this agreement 
* shall be construed as conferring by implication, estoppel, 
* or otherwise, upon you, any license or other right under any 
* TI patents, copyrights or trade secrets.
*
* You may not use the Program in non-TI devices.
* ********************************************************* */
/*
 * MCBSP interrupt low-level streaming device driver for TI 6211/6711 DSK.
 *
 * DSP/BIOS configuration:
 *     McBSP0 (McBSP1 on 6211 rev 1.x silicon) RX ISR plugged to rcvIsr
 *     McBSP1 (McBSP1 on 6211 rev 1.x silicon) TX ISR plugged to xmtIsr
 *
 */
#include <std.h>

#include <csl.h>
#include <mcbsp.h>
#include <irq.h>
#include <log.h>

#include <lio.h> /* lio interface definition */
#include <dsk6211_mcbsp_ad535.h>

extern far LOG_Obj trace;

/* Private Driver state variables */
typedef struct drv_state {
	Bool running;      /* Should interrupts be enabled? */
	Ptr currentBuffer; /* Saved pointer to buffer being filled or drained */
	Uns currentSize;   /* Size in MAUs of that buffer. */
	Uns currentPtr;    /* Pointer to next insertion point, used by
                          ISR. NULL if no buffer is currently being
                          transfered. */
	Uns currentCount;  /* Count of elems in currentPtr(NOT MAUs),
						  used by ISR */
	Ptr fullBuffer;    /* Previously filled or drained buffer, to be
						  returned by getBuf */
	Uns fullSize;      /* Size of fullBuffer */
	Ptr nextBuffer;    /* Next buffer to fill or drain after currentBuffer */
	Uns nextSize;      /* Size of nextBuffer */
	LIO_TcallBack callback; /* Callback to notify of new full buffer */
	Arg callbackArg;
} LIO_Obj;

/* chan0 & 2 are rcv, chan1 & 3 are xmt */
#define NUM_CHANS 4

static LIO_Obj chans[4] = {
	{ NULL, 0, NULL, 0, NULL, 0, NULL, 0},
	{ NULL, 0, NULL, 0, NULL, 0, NULL, 0},
	{ NULL, 0, NULL, 0, NULL, 0, NULL, 0},
	{ NULL, 0, NULL, 0, NULL, 0, NULL, 0}
};

/* CSL handle to the McBSP. The McBSP is shared between the two channels */
static MCBSP_HANDLE hMcbsp;

/* Has the codec been inited yet? */
static int codecInited = 0;

/* Private functions */

/* Inialize a Drv_Obj with safe defaults */
static LIO_Obj *initDrvObj(LIO_Obj *obj)
{
	obj->running = FALSE;
	obj->currentBuffer = 0x0;
	obj->fullBuffer = 0x0;
	obj->nextBuffer = 0x0;
	obj->callback = NULL;    
	
	return obj;
}
     
/* Convenience function for dispatching to chanIsr. Easily called from
   asm code. */
void xmtIsr()
{
	chanIsr(XMT_CHAN0);
}

/* Convenience function for dispatching to chanIsr. Easily called from
   asm code. */
void rcvIsr()
{
	chanIsr(RCV_CHAN0);
}

/*
 * Handle sample interrupt. Can be called by DSP/BIOS dispatcher with
 * appropriate channel arg.
 *
 * Copy from McBSP to buffer or the other way around. If buffer is
 * full/empty then move chans[chan].currentBuffer to
 * chans[chan].fullBuffer. If nextBuffer != NULL then move it to
 * currentBuffer.  */
Void chanIsr(Uns chan)
{ 
	/* Do the transfer */
	if (chans[chan].currentPtr == NULL) {
		/* spurious interrupt */
		return;
	} else {
		switch (chan) {
		   case RCV_CHAN0:
			   *(unsigned short *)chans[chan].currentPtr
				   = (unsigned short)MCBSP_Read(hMcbsp);
			   break;
		   case XMT_CHAN0:
			   MCBSP_Write(hMcbsp,
						   *(unsigned short *)chans[chan].currentPtr
						   & 0xfffe);
			   break;
		   default:
			   SYS_abort("mcbsp_code: bad channel number");
		}
		/* explicit address arith for clarity */
		chans[chan].currentPtr = chans[chan].currentPtr + sizeof(short);
		chans[chan].currentCount--;
		/* fake the second channel */
		chans[chan+2].currentPtr = chans[chan+2].currentPtr + sizeof(short);
		chans[chan+2].currentCount--;
		/* Is this buffer finished? */
		if (chans[chan].currentCount == 0) {
			/* Yes. So swap. */
				
			if (chans[chan].fullBuffer != 0x0) {
				LOG_message("HELP!!! Dropped buffer!!", NULL);
			}

			/* move buffer pointer from current to full */
			chans[chan].fullBuffer = chans[chan].currentBuffer;
			/* only full frames are transfered */
			chans[chan].fullSize = chans[chan].currentSize;
			/* fake the second channel */ 
			/* move buffer pointer from current to full */
			chans[chan+2].fullBuffer = chans[chan+2].currentBuffer;
			/* only full frames are transfered */
			chans[chan+2].fullSize = chans[chan+2].currentSize; 
			/* Is there a next buffer? */
			if (chans[chan].nextBuffer == 0x0) {
				/* no next buffer */
				chans[chan].currentBuffer = 0x0;
				/* Shut down further transfers on this channel */
				chans[chan].currentPtr = NULL;
			} else {
				chans[chan].currentBuffer = chans[chan].nextBuffer;
				chans[chan].currentPtr = (Uns)chans[chan].nextBuffer;
				chans[chan].currentSize = chans[chan].nextSize;  
				chans[chan].currentCount
					= chans[chan].nextSize / sizeof(short);
				chans[chan].nextBuffer = NULL;
			}
			/* Is there a next buffer? */
			/* fake the second channel */
			if (chans[chan+2].nextBuffer == 0x0) {
				/* no next buffer */
				chans[chan+2].currentBuffer = 0x0;
				/* Shut down further transfers on this channel */
				chans[chan+2].currentPtr = NULL;
			} else {
				chans[chan+2].currentBuffer = chans[chan+2].nextBuffer;
				chans[chan+2].currentPtr = (Uns)chans[chan+2].nextBuffer;
				chans[chan+2].currentSize = chans[chan+2].nextSize;  
				chans[chan+2].currentCount
					= chans[chan+2].nextSize / sizeof(short);
				chans[chan+2].nextBuffer = NULL;
			}
			/* Call the callback before exiting. */
			if (chans[chan].callback != NULL) {
				(*chans[chan].callback)(chan, chans[chan].callbackArg);
			}
			/* fake the second channel */
			/* Call the callback before exiting. */
			if (chans[chan+2].callback != NULL) {
				(*chans[chan+2].callback)(chan+2, chans[chan+2].callbackArg);
			}
		}
	}
}

/* Only called within the driver to disable the device interrupt for
 * mutual exclusion. enableIntr is called to reenable.
 * */
static Void disableIntr(Uns chan)
{
	if (chans[chan].running) { /* redundant, if we're not running then
                                  intr's aren't enabled. Here for
                                  completeness. */
		if (chan == RCV_CHAN0) {
			IRQ_Disable(IRQ_EVT_RINT1);
		} 
		else {
			if (chan == XMT_CHAN0) {
				IRQ_Disable(IRQ_EVT_XINT1);
			}
		}
	}
}

/* After McBSP is configured, program the off-chip AD535. Called by init(). */
static Void enableCodec(Void)
{
    hMcbsp = MCBSP_Open(MCBSP_DEV0, MCBSP_OPEN_RESET);

	ad535_init(hMcbsp);
}

/*
 * Only called within the driver to reenable interrupts after a call to
 * disableIntr. Interrupts are reenabled only if the device state is
 * running and there is a transfer occurring.
 * */
static Void enableIntr(Uns chan)
{
	if (chans[chan].running && chans[chan].currentPtr != 0x0) {
		/* PENDING: Are the IRQ_Set's required here? */
		if (chan == RCV_CHAN0) {
			IRQ_Enable(IRQ_EVT_RINT1);
			if (MCBSP_Rrdy(hMcbsp)) {
				IRQ_Set(IRQ_EVT_RINT1);
			}
		} 
		else {
			if (chan == XMT_CHAN0) {
				IRQ_Enable(IRQ_EVT_XINT1);
				if (MCBSP_Xrdy(hMcbsp)) {
					IRQ_Set(IRQ_EVT_XINT1);
				} 
			}
		}
	}
}

/***********************/
/* Begining of public interface functions. */						

/* PENDING: Close does not free McBSP */
static Void close(Uns chan)
{
	initDrvObj(&chans[chan]);
	/* fake second channel */
	initDrvObj(&chans[chan+2]);
}

/* IOCTL for anything else */
static Int ctrl(Uns chan, Uns flag)
{
	/* 
	 * Potential things here include 
	 * - Sample rate and format
	 * - pre-allocating link entries
	 * - setting max links per channel
	 */    
	 
	 return 0;
}

/* Return the next complete buffer, or NULL */
static Ptr getBuf(Uns chan, Int *size, Int *dataSize)
{
	Ptr retVal;
	
	if ((chan == RCV_CHAN0) || (chan == XMT_CHAN0)) {
		disableIntr(chan);
	}
	
	retVal = chans[chan].fullBuffer;
	
	if (chans[chan].fullBuffer != NULL) {
		*size = *dataSize = chans[chan].fullSize;
	}
	
	chans[chan].fullBuffer = NULL;

	if ((chan == RCV_CHAN0) || (chan == XMT_CHAN0)) {
		enableIntr(chan);        
    }
        
	return retVal;
}

/* Allocate resources for a channel */
static Int init(Uns chan, Ptr args)
{
	if (!codecInited) {
		enableCodec(); /* Allocate and configure Codec */
		codecInited = 1;
		/*
		 * Set up IRQ map.
		 * PENDING: CSL doesn't do this for ints above 8 for
		 * 6211. Future versions of the CSL and
		 * DSP/BIOS II will do this automatically.
		 * */
		IRQ_Map(IRQ_EVT_RINT1, 6);
		IRQ_Map(IRQ_EVT_XINT1, 7);
	
	}

	if (chan < NUM_CHANS) { 
	  /* initialize channel data structure */
	  /* PENDING: return an error if channel isn't in closed state */
	  initDrvObj(&chans[chan]);

	  return 1;
	} 

	/* fail safe fall through */
	return 0;
}

/* return true if we are idle */
static Int isEmpty(Uns chan)
{
	return chans[chan].currentBuffer == NULL;
}

/* return true if setBuf will succeed */
static Int isFull(Uns chan)
{
	return chans[chan].nextBuffer != NULL;
}

/* Set new buffer. Returns 1 if room available in hardware queue, 0 if
   no room in hardware queue. */
static Int setBuf(Uns chan, Ptr buf, Uns size)
{
	Int retVal = 0;

	/* Make sure nothing changes while we're changing state. Note that
       this assumes that only an ISR and one user thread are acessing
       this channel. If more than one user thread needs to access the
       channel then a semaphore will be needed. */
	if ((chan == RCV_CHAN0) || (chan == XMT_CHAN0)) {
		disableIntr(chan);
	}

	/* Are we filling a buffer already? */
	if (chans[chan].currentBuffer != 0x0) {
		/* yes we are. Do we have room for a nextbuffer? */
		if (chans[chan].nextBuffer == NULL) {
			/* yes */
			chans[chan].nextBuffer = buf;
			chans[chan].nextSize = size/sizeof(short);
			retVal = 1;
		} else {
			/* no room, return failure */
			retVal = 0;
		}
	} else {
		/* No current buffer, set it up and go! */
		retVal = 1;
		chans[chan].currentBuffer = buf;
		chans[chan].currentSize = size;
		chans[chan].currentPtr = (Uns)buf;
		/* Units of count is elements, not MAUs */
		chans[chan].currentCount = size / sizeof(short); 
		/* If receiving, clear old data from MCBSP if present */
		if (chan == RCV_CHAN0 && MCBSP_Rrdy(hMcbsp)) {
			MCBSP_Read(hMcbsp);
		}
	}

	/* Kick it off again */
	if ((chan == RCV_CHAN0) || (chan == XMT_CHAN0)) {
		enableIntr(chan);
	}
	
	return retVal;
}

static Void setCallback(Uns chan, LIO_TcallBack cb, Arg arg)
{
	chans[chan].callback = cb;
	chans[chan].callbackArg = arg;
}

/* Enable McBSP interrupts. */
static Void start(Uns chan)
{
	chans[chan].running = TRUE;
	if ((chan == RCV_CHAN0) || (chan == XMT_CHAN0)) {
		enableIntr(chan);
	}
}

/* Disable McBSP rcv events on rcv DMA channel. */
static Void stop(Uns chan)
{
	if ((chan == RCV_CHAN0) || (chan == XMT_CHAN0)) {
		disableIntr(chan);
	}
	chans[chan].running = FALSE;
}

/* eXpress DSP Algorithm Standard naming convention used for driver table */
LIO_Fxns DSK6211MCBSPAD535_TI_iLio = {
	&close,
	&ctrl,
	&getBuf,
	&init,
	&isEmpty,
	&isFull,
	&setBuf,
	&setCallback,
	&start,
	&stop
};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -