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

📄 dma.cpp

📁 ARM9基于WINDOWSCE的BSP源代码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
    // Setup the source width
    pDMACChannelRegs->DMACCxControl &= ~(DWORD)DMAC_SWIDTH;
    pDMACChannelRegs->DMACCxControl |=
        ((DWORD)DMAInfo.DMAChannels[ucDMAChannel].ucSourceWidth << DMAC_SWIDTH_SHIFT);
    // Setup the destination burst size
    pDMACChannelRegs->DMACCxControl &= ~(DWORD)DMAC_DBSIZE;
    pDMACChannelRegs->DMACCxControl |=
        ((DWORD)DMAInfo.DMAChannels[ucDMAChannel].ucDestBurstSize << DMAC_DBSIZE_SHIFT);
    // Setup the source burst size
    pDMACChannelRegs->DMACCxControl &= ~(DWORD)DMAC_SBSIZE;
    pDMACChannelRegs->DMACCxControl |=
        ((DWORD)DMAInfo.DMAChannels[ucDMAChannel].ucSourceBurstSize << DMAC_SBSIZE_SHIFT);
    // Determine whether to increment the source and destination
    if(DMAInfo.DMAChannels[ucDMAChannel].fIncrementSource)
        pDMACChannelRegs->DMACCxControl |= DMAC_CTRL_SI;    // Increment the source
    if(DMAInfo.DMAChannels[ucDMAChannel].fIncrementDest)
        pDMACChannelRegs->DMACCxControl |= DMAC_CTRL_DI;    // Increment the destination

    // Setup the dest device
    pDMACChannelRegs->DMACCxConfiguration &= ~(DWORD)DMAC_CHCONFIG_DPER;
    pDMACChannelRegs->DMACCxConfiguration |= 
        ((DWORD)DMAInfo.DMAChannels[ucDMAChannel].ucDestDevice << DMAC_DPER_SHIFT);
    // Setup the source device
    pDMACChannelRegs->DMACCxConfiguration &= ~(DWORD)DMAC_CHCONFIG_SPER;
    pDMACChannelRegs->DMACCxConfiguration |= 
        ((DWORD)DMAInfo.DMAChannels[ucDMAChannel].ucSourceDevice << DMAC_SPER_SHIFT);
    // Setup the flow control
    pDMACChannelRegs->DMACCxConfiguration &= ~(DWORD)DMAC_CHCONFIG_FLOW;
    pDMACChannelRegs->DMACCxConfiguration |= 
        ((DWORD)DMAInfo.DMAChannels[ucDMAChannel].ucFlowControl << DMAC_FLOW_SHIFT);

    DEBUGMSG(DMA_ZONE_OPT, (TEXT("-InitializeDMAChannel\r\n")));

    return TRUE;
}

//
// FreeDMAChannel - Frees the specified DMA channel
//
extern "C" BOOL FreeDMAChannel(PFREE_DMA_PARAMS pParams, PFREE_DMA_RESULT pResults)
{
    UCHAR   ucDMAChannel;
    volatile PDMAC_CHANNEL_REGS pDMACChannelRegs;
    pvstSP810Regs pstSP810 = (pvstSP810Regs)(VA_SC_BASE);

    DEBUGMSG(1, (TEXT("+FreeDMAChannel(channel %d)\r\n"), pParams->ucChannelNumber));

    ucDMAChannel = pParams->ucChannelNumber;
    pDMACChannelRegs = DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs;

    // Disable the DMA channel to ensure no more transfers can occur on it
    pDMACChannelRegs->DMACCxConfiguration &= ~(DWORD)DMAC_CHCONFIG_E;

    DMAInfo.DMAChannels[ucDMAChannel].fInUse = FALSE;   // Set this channel to 'free'
   
    DEBUGMSG(1, (TEXT("-FreeDMAChannel\r\n")));

    // Disable the DMA's peripheral clock if there are no more channels allocated
    for(ucDMAChannel=0; ucDMAChannel<MAX_DMA_CHANNELS; ucDMAChannel++)
    {
        if(DMAInfo.DMAChannels[ucDMAChannel].fInUse) break;
    }
    DEBUGMSG(1, (TEXT("Freed a channel, no of channels = %d\r\n"),(DWORD)ucDMAChannel));
        
    if(MAX_DMA_CHANNELS == ucDMAChannel)
    {
        DEBUGMSG(1, (TEXT("Switching DMA clock off.\r\n")));
        pstSP810->SCPERDIS = HCLKDMA;

    }


    return TRUE;
}

//
// FreeDmaSysIntr - Removes the SYSINTR mapping from the chosen channel
//
extern "C" BOOL FreeDmaSysIntr(PFREE_DMA_SYSINTR_PARAMS pParams, PFREE_DMA_SYSINTR_RESULT pResults )
{
    DEBUGMSG(1, (TEXT("+FreeDmaSysIntr(Freeing Channel: %d)\r\n"), pParams->ucChannelNumber));

    /* Channel number out of range */
    if(pParams->ucChannelNumber >= MAX_DMA_CHANNELS)
        return FALSE; 

    /* Attempting to remove an unmapped SYSINTR */
    if(SYSINTR_UNDEFINED == DMAInfo.DMAChannels[pParams->ucChannelNumber].dwDMASysIntr) {
        DEBUGMSG(1, (TEXT("[ERR]FreeDmaSysIntr(Chennel not mapped)\r\n")));
        return FALSE;
    }
    
    /* Remove from OAL mapping */
    if(ERROR_SUCCESS == OEMReleaseSysIntr(DMAInfo.DMAChannels[pParams->ucChannelNumber].dwDMASysIntr))
    {
        DEBUGMSG(1, (TEXT("FreeDmaSysIntr(SYSINTR: %d now free)\r\n"), 
            DMAInfo.DMAChannels[pParams->ucChannelNumber].dwDMASysIntr));
        
        /* Clear in DMAInfo structure */
        DMAInfo.DMAChannels[pParams->ucChannelNumber].dwDMASysIntr=SYSINTR_UNDEFINED;
        return TRUE;
    } else {
        DEBUGMSG(1, (TEXT("[ERR]FreeDmaSysIntr(SYSINTR: %d unable to free)\r\n"), 
            DMAInfo.DMAChannels[pParams->ucChannelNumber].dwDMASysIntr));
    }

    /* Failed to remove mapping */
    return FALSE;
}

//
// StartDMATransfer - Starts a DMA transfer between two devices
//
extern "C" BOOL StartDMATransfer(PSTART_DMA_PARAMS pParams, PSTART_DMA_RESULT pResults)
{
    UCHAR   ucDMAChannel;
    volatile PDMAC_CHANNEL_REGS pDMACChannelRegs;
    DWORD   dwPages, dwPage;
    PDWORD  pdwSourceBuffer;
    PDWORD  pdwDestBuffer;
    DWORD   dwTotalSize, dwTransferSize, dwTransfers, dwListOffset;

    if (!fDMAInitialised) { /* not present */
        DEBUGMSG(1, (TEXT("NO DMA blocking StartDMATransfer(channel %d)\r\n"), pParams->ucChannelNumber));
        return FALSE;
        }

    ucDMAChannel = pParams->ucChannelNumber;

    if (ucDMAChannel >= MAX_DMA_CHANNELS) { /* Illegal */
        DEBUGMSG(1, (TEXT("ERROR : DMA blocked: Illegal channel %d\r\n"), pParams->ucChannelNumber));
        return FALSE;
        }

    DEBUGMSG(1, (TEXT("+StartDMATransfer(channel %d)\r\n"), pParams->ucChannelNumber));

    // Save the parameters in case we need to restart the transfer
    dwTotalSize = pParams->dwTransferSize;
    DMAInfo.DMAChannels[ucDMAChannel].dwTransferSize = pParams->dwTransferSize;
    DMAInfo.DMAChannels[ucDMAChannel].pdwSourceBuffer = pParams->pdwSourceBuffer;
    DMAInfo.DMAChannels[ucDMAChannel].pdwDestBuffer = pParams->pdwDestBuffer;

    DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: source buffer = 0x%X\r\n"), pParams->pdwSourceBuffer));
    DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: dest buffer = 0x%X\r\n"), pParams->pdwDestBuffer));
    DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: total size = 0x%X\r\n"), dwTotalSize));

    pDMACChannelRegs = DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs;

    // Store the buffer locations
    pdwSourceBuffer = pParams->pdwSourceBuffer;
    pdwDestBuffer = pParams->pdwDestBuffer;

    // Setup the DMA control register
    pDMACChannelRegs->DMACCxControl &= ~(DWORD)DMAC_TRANSFER_SIZE;  // Clear the size
    pDMACChannelRegs->DMACCxControl |= DMAC_CTRL_PRIV;  // We are always in privileged mode

    // Setup the address registers to the first physical address
    pDMACChannelRegs->DMACCxSrcAddr = pdwSourceBuffer[0];
    pDMACChannelRegs->DMACCxDestAddr = pdwDestBuffer[0];

    switch (pDMACChannelRegs->DMACCxControl & (((DWORD)DMAC_CTRL_S) | ((DWORD)DMAC_CTRL_D)))
    {
    	case 0:
    	case ((DWORD)DMAC_CTRL_S) | ((DWORD)DMAC_CTRL_D):	// in this case, these two memory spaces' offset should be zero
	    // Clip the transfer size to one DMA block and create a linked list for the rest
	    if(dwTotalSize > (DWORD)MAX_DMA_TRANSFER_SIZE) {
	        // Calculate the number of pages in the buffer(s)
	        dwPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(NULL, dwTotalSize);
	
	        DEBUGMSG(1, (TEXT("DMA %d - Number of virtual pages required = %d\r\n"), ucDMAChannel, dwPages));
	
	        // Check if the transfer is too big for our list buffer
	        if(dwPages > (DWORD)MAX_DMA_LIST_ENTRIES) {
	            DEBUGMSG(1, (TEXT("Error - the DMA %d transfer is too large for the list buffer\r\n"), ucDMAChannel));
	            return FALSE;
	        }
	
	        // Setup the list entry pointer to the start of the list for this channel
	        dwListOffset = ucDMAChannel * sizeof(LLI_ENTRY) * MAX_DMA_LIST_ENTRIES;
	        DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntry = (PLLI_ENTRY)(DMA_LIST_BUFFER_VIRT + dwListOffset);
	         // Keep a physical copy
	        DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntryPhys = (PLLI_ENTRY)(DMA_LIST_BUFFER_PHYS + dwListOffset);
	
	        dwTransferSize = (DWORD)PAGE_SIZE;
	        // Adjust the size to the number of transfers required
	        switch(DMAInfo.DMAChannels[ucDMAChannel].ucSourceWidth) {
	        case TRANSFER_WIDTH_BYTE:
	            dwTransfers = dwTransferSize - 1;
	            // Add a 1 byte list entry to make up 1 virtual page
	            // This is due to the maximum transfer size of the DMAC (4095 bytes)
	            dwPage = 0;
	            AddLLIEntry(ucDMAChannel, dwPage, pdwSourceBuffer, pdwDestBuffer, (DWORD)-1);
	            break;
	        case TRANSFER_WIDTH_WORD:
	            dwTransfers = dwTransferSize/sizeof(WORD);
	            break;
	        case TRANSFER_WIDTH_DWORD:
	            dwTransfers = dwTransferSize/sizeof(DWORD);
	            break;
	
	        } /* switch(DMAInfo.DMAChannels[] */
	
	        pDMACChannelRegs->DMACCxControl |= dwTransfers; // Set the number of transfers
	        dwTotalSize -= (DWORD)PAGE_SIZE;    // The first block has been taken care of
	
	        // Point the DMA controller at the start of the list buffer
	        // We OR in AHB2 as the master select for loading LLIs (Versatile)
	        pDMACChannelRegs->DMACCxLLI = (DWORD)((DMA_LIST_BUFFER_PHYS + dwListOffset) | DMAC_LLI_LM);
	
	        // Create the linked list
	        for(dwPage=1;dwPage<dwPages;dwPage++) {
	            DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA %d list entry - virtual list entry pointer = 0x%X\r\n"), 
	                            ucDMAChannel, DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntry));
	            DEBUGMSG(1, (TEXT("DMA %d list entry - physical list entry pointer = 0x%X\r\n"), 
	                            ucDMAChannel, DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntryPhys));
	
	            // Calculate the size of the transfer
	            dwTransferSize = MIN(dwTotalSize, (DWORD)PAGE_SIZE);
	
	            DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA %d list entry - transfer size = 0x%X\r\n"), ucDMAChannel, dwTransferSize));
	
	            AddLLIEntry(ucDMAChannel, dwPage, pdwSourceBuffer, pdwDestBuffer, dwTransferSize);
	
	            // If we are transfering a page size of bytes we need an extra 1 byte transfer
	            if(DMAInfo.DMAChannels[ucDMAChannel].ucSourceWidth == TRANSFER_WIDTH_BYTE && 
	                dwTransferSize == (DWORD)PAGE_SIZE) {
	                // Add a 1 byte list entry to make up 1 virtual page
	                // Again due to the maximum transfer size of the DMAC (4095 bytes)
	                AddLLIEntry(ucDMAChannel, dwPage, pdwSourceBuffer, pdwDestBuffer, (DWORD)-1);
	            }
	
	            dwTotalSize -= dwTransferSize;  // Reduce the overall transfer size accordingly
	
	            DEBUGMSG(1, (TEXT("DMA %d list entry - bytes left = 0x%X\r\n"), ucDMAChannel, dwTotalSize));
	        }
	        DMAInfo.DMAChannels[ucDMAChannel].pPrevLLIEntry->pNextEntry = 0;  // This is the end of the list
	        DMAInfo.DMAChannels[ucDMAChannel].pPrevLLIEntry->dwControl |= DMAC_CTRL_I;    // Set to interrupt on this last entry
	    
	    } else {
	        // Adjust the size to the number of transfers required
	        switch(DMAInfo.DMAChannels[ucDMAChannel].ucSourceWidth) {
	        case TRANSFER_WIDTH_BYTE:
	            dwTransfers = dwTotalSize;
	            break;
	            case TRANSFER_WIDTH_WORD:
	                dwTransfers = dwTotalSize/sizeof(WORD);
	            break;
	            case TRANSFER_WIDTH_DWORD:
	                dwTransfers = dwTotalSize/sizeof(DWORD);
	            break;
	        }
	
	        DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfers = 0x%X\r\n"), dwTransfers));
	
	        pDMACChannelRegs->DMACCxLLI = 0;    // There is no linked list for small transfers
	        pDMACChannelRegs->DMACCxControl |= DMAC_CTRL_I; // Interrupt at the end of the transfer
	        pDMACChannelRegs->DMACCxControl |= dwTransfers; // Set the number of transfers
	 
	    } //    if(dwTotalSize > (DWORD)MAX_DMA_TRANSFER_SIZE)
	    break;

	case (DWORD)DMAC_CTRL_S:
		////////////////////////////
		DEBUGMSG(1, (TEXT("DMA %d - BYTE_OFFSET( pdwSourceBuffer[0] ) = 0x%x\r\n"), ucDMAChannel, BYTE_OFFSET( pdwSourceBuffer[0] )));
		DEBUGMSG(1, (TEXT("DMA %d - dwTotalSize = 0x%x\r\n"), ucDMAChannel, dwTotalSize));
		////////////////////////////
		// Clip the transfer size to one DMA block and create a linked list for the rest
	    if(BYTE_OFFSET( pdwSourceBuffer[0] ) + dwTotalSize > (DWORD)MAX_DMA_TRANSFER_SIZE) //!!!
		{

⌨️ 快捷键说明

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