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

📄 dmadrv.c

📁 NXP LPC3000系列 wince BSP包
💻 C
📖 第 1 页 / 共 2 页
字号:
// dmaGetRegPtr
//
// Returns address to DMA registers
//
DMAC_REGS_T *dmaGetRegPtr(DWORD dmaData)
{
	DMADRVDATA_T *pDrvData = (DMADRVDATA_T *) dmaData;

	return pDrvData->pDMARegs;
}

//-----------------------------------------------------------------------------
//
// dmaTranEntry
//
// Starts a DMA transfer with the passed attributes (not LLI)
//
DWORD dmaTranEntry(DWORD dmaData,
				   DWORD src,      // Physical address
				   DWORD dst,      // Physical address
				   DWORD bytes)    // Number of bytes to transfer
{
	DWORD ctrl;
	DMADRVDATA_T *pDrvData = (DMADRVDATA_T *) dmaData;
	DWORD trans;

	trans = bytes / pDrvData->xferSize;
	if (trans >= 4096)
	{
		return 0;
	}

	if (dmaIsOn(dmaData) != 0)
	{
		// Channel is currently on
		return 0;
	}

	// Update config word
	pDrvData->pDMAChan->config_ch = pDrvData->savedConfig;

	// Setup control word
	ctrl = (pDrvData->savedControl | DMAC_CHAN_TRANSFER_SIZE(trans) |
		DMAC_CHAN_INT_TC_EN);

	// Start transfer
	dmaStartDMA((DMADRVDATA_T *) dmaData, src, dst, 0, ctrl);

	return bytes;
}

//-----------------------------------------------------------------------------
//
// dmaListReset
//
// Disable and reset the current DMA list
//
void dmaListReset(DWORD dmaData)
{
	DMADRVDATA_T *pDrvData = (DMADRVDATA_T *) dmaData;

	dmaDisable(dmaData);
	pDrvData->GetListIdx = 0;
	pDrvData->PutListIdx = 0;
	pDrvData->ListEntries = 0;
	pDrvData->pDMAChan->lli = 0;
}

//-----------------------------------------------------------------------------
//
// dmaChanConfig
//
// Change the current channel's attributes, adjusts channel configuation
// without creating new buffers
//
DWORD dmaChanConfig(DWORD dmaData,
					DMASETUP_T *pDmaSetup)
{
	UINT32 tmp;
	DMADRVDATA_T *pDrvData = (DMADRVDATA_T *) dmaData;

	// Setup control word for the channel
	// Source on AHB0, destination on AHB1
	tmp = (DMAC_CHAN_SRC_AHB1 | pDmaSetup->SrcWidth | pDmaSetup->DestWidth |
//		DMAC_CHAN_DEST_AHB1 | // TBD
//	tmp = (0 | pDmaSetup->SrcWidth | pDmaSetup->DestWidth |
//		DMAC_CHAN_DEST_AHB1 | // TBD
		pDmaSetup->SrcBurstSize | pDmaSetup->DestBurstSize);
	if (pDmaSetup->DestInc != 0)
	{
		tmp |= DMAC_CHAN_DEST_AUTOINC;
	}
	if (pDmaSetup->SrcInc != 0)
	{
		tmp |= DMAC_CHAN_SRC_AUTOINC;
	}
	pDrvData->savedControl = tmp;
	pDrvData->pDMAChan->control = 0;

	// Compute transfer size
	if (pDmaSetup->SrcWidth == DMAC_CHAN_SRC_WIDTH_8)
	{
		pDrvData->xferSize = 1;
	}
	else if (pDmaSetup->SrcWidth == DMAC_CHAN_SRC_WIDTH_16)
	{
		pDrvData->xferSize = 2;
	}
	else
	{
		pDrvData->xferSize = 4;
	}

	// Setup channel configuration word for the channel
	// DMA requests enabled, channel not enabled
	tmp = (pDmaSetup->perFlowSource | pDmaSetup->destPeripheral |
		pDmaSetup->srcPeripheral | DMAC_CHAN_ITC);
	pDrvData->savedConfig = tmp;
	pDrvData->pDMAChan->config_ch = tmp;

	return 1;
}

//-----------------------------------------------------------------------------
//
// dmaDumpRegs
//
// Dumps current DMA registers
//
void dmaDumpRegs(DWORD dmaData)
{
	int idx;
	UINT32 *pReg;
	DMADRVDATA_T *pDrvData = (DMADRVDATA_T *) dmaData;

	RETAILMSG(1,
	    (TEXT("dmaDumpRegs: Dumping DMA common registers\r\n")));

	idx = 0;
	pReg = (UINT32 *) pDrvData->pDMARegs;
	for (idx = 0; idx < 14; idx++)
	{
		RETAILMSG(1,
		    (TEXT("dmaDumpRegs: Reg 0x%x = 0x%x\r\n"), pReg, *pReg));
		pReg++;
	}

	RETAILMSG(1,
	    (TEXT("dmaDumpRegs: Dumping DMA channel(%d) registers\r\n"), pDrvData->dmaInfo.dmaCh));
	idx = 0;
	pReg = (UINT32 *) pDrvData->pDMAChan;
	for (idx = 0; idx < 5; idx++)
	{
		RETAILMSG(1,
		    (TEXT("dmaDumpRegs: Reg 0x%x = 0x%x\r\n"), pReg, *pReg));
		pReg++;
	}
}

//-----------------------------------------------------------------------------
//
// dmaCleanUp
//
// Pops a single list entry and returns the number of bytes sent in
// that list
//
DWORD dmaCleanUp(DWORD dmaData)
{
	int toproc;
	DWORD trans = 0;
	DMADRVDATA_T *pDrvData = (DMADRVDATA_T *) dmaData;
	DMAC_LL_T *PCurHWList, *pExpListVirt;

	// Only process if entries need processing
	if (pDrvData->ListEntries > 0)
	{
		// Current DMA list entry to check before resubmitting to pool
		pExpListVirt = pDrvData->pDMAListVirt + pDrvData->GetListIdx;

		// Current HW pointer and convert to virtual address
		PCurHWList = (DMAC_LL_T *) (pDrvData->pDMAChan->lli &
			~DMAC_CHAN_LLI_SEL_AHB1);
		PCurHWList = dmaToVirt(pDrvData, PCurHWList);

		// If DMA is stopped, then always pop the list
		if (dmaIsOn(dmaData) == 0)
		{
			// Get size of the completed transfer
			trans = pExpListVirt->next_ctrl;
			trans = trans & DMAC_CHAN_TRANSFER_SIZE(0xFFF);

			// One entry cleaned, can be used by dmaListEntry()
			pDrvData->ListEntries--;
		}
		else if (PCurHWList != NULL)
		{
			// DMA is not idle and there is 2 or more entries on the
			// list. Determine if an entry needs to be popped.

			// Determine the number of entries the DMA has to process
			if (PCurHWList > pExpListVirt)
			{
				toproc = (DWORD) PCurHWList - (DWORD) pExpListVirt;
			}
			else
			{
				toproc = (DWORD) pExpListVirt - (DWORD) PCurHWList;
			}
			toproc = toproc / sizeof (DMAC_LL_T);

			// If there are less entries for DMA processing than what
			// was submitted, then an entry can be popped off the list
			if (toproc != pDrvData->ListEntries)
			{
				// Get size of the completed transfer
				trans = pExpListVirt->next_ctrl;
				trans = trans & DMAC_CHAN_TRANSFER_SIZE(0xFFF);

				// One entry cleaned, can be used by dmaListEntry()
				pDrvData->ListEntries--;
			}
		}
		else
		{
			// Current HW list is NULL
			if (pDrvData->ListEntries > 1)
			{
				// Get size of the completed transfer
				trans = pExpListVirt->next_ctrl;
				trans = trans & DMAC_CHAN_TRANSFER_SIZE(0xFFF);

				// One entry cleaned, can be used by dmaListEntry()
				pDrvData->ListEntries--;
			}
		}
	}

	// Switch to next check entry
	if (trans > 0)
	{
		pDrvData->GetListIdx++;
		if (pDrvData->GetListIdx >= DMALISTENTRIES)
		{
			pDrvData->GetListIdx = 0;
		}

		// Readjust for bytes
		trans = trans * pDrvData->xferSize;
	}

	return trans;
}

//-----------------------------------------------------------------------------
//
// dmaListEntry
//
// Adds a new entry to the DMA linked list and starts DMA
//
DWORD dmaListEntry(DWORD dmaData,
				   DWORD src,      // Physical address
				   DWORD dst,      // Physical address
				   DWORD bytes)    // Number of bytes to transfer
{
	int prevIdx;
	DWORD trans, added = 0;
	DMADRVDATA_T *pDrvData = (DMADRVDATA_T *) dmaData;
	DMAC_LL_T *pPrevListV, *pCurListV, *pCurListP, *PCurHWList;

	trans = bytes / pDrvData->xferSize;
	if ((trans == 0) || (trans >= 4096))
	{
		return 0;
	}

	// Only process if there is enough space
	if (pDrvData->ListEntries < DMALISTENTRIES)
	{
		// Get pointer to next DMA list entry to put
		pCurListV = pDrvData->pDMAListVirt + pDrvData->PutListIdx;

		// Get pointer to previous DMA list entry
		prevIdx = pDrvData->PutListIdx - 1;
		if (prevIdx < 0)
		{
			prevIdx = DMALISTENTRIES - 1;
		}
		pPrevListV = pDrvData->pDMAListVirt + prevIdx;

		// Get physical address for list entry to put
		pCurListP = dmaToPhy(pDrvData, pCurListV);

		// Increment buffer and put counts
		pDrvData->ListEntries++;
		pDrvData->PutListIdx++;
		if (pDrvData->PutListIdx >= DMALISTENTRIES)
		{
			pDrvData->PutListIdx = 0;
		}

		// Add to next entry in the list
		pCurListV->dma_src = src;
		pCurListV->dma_dest = dst;
		pCurListV->next_lli = 0;
		trans = bytes / pDrvData->xferSize;
		pCurListV->next_ctrl = (pDrvData->savedControl |
			DMAC_CHAN_TRANSFER_SIZE(trans) | DMAC_CHAN_INT_TC_EN);

		// Update previous link pointer to point to current link
		pPrevListV->next_lli = ((UNS_32) pCurListP |
			DMAC_CHAN_LLI_SEL_AHB1);

		// If next link is NULL, then update the current DMA HW link to
		// the next link
		PCurHWList = (DMAC_LL_T *) pDrvData->pDMAChan->lli;
		if (PCurHWList == 0)
		{
			pDrvData->pDMAChan->lli = ((UNS_32) pCurListP |
				DMAC_CHAN_LLI_SEL_AHB1);
		}

		// If DMA is idle, then the DMA list was empty and the previous
		// link update occured after DMA was disabled, so restart or
		// start DMA
		if (dmaIsOn(dmaData) == 0)
		{
			// Start transfer
			dmaStartDMA(pDrvData, pCurListV->dma_src, pCurListV->dma_dest,
				0, pCurListV->next_ctrl);
		}

		added = 1;
	}

	return added;
}

⌨️ 快捷键说明

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