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

📄 dma.cpp

📁 ARM9基于WINDOWSCE的BSP源代码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
	        // Calculate the number of pages in the buffer(s)
	        dwPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(NULL, BYTE_OFFSET( pdwSourceBuffer[0] ) + 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 - (DWORD)BYTE_OFFSET(pdwSourceBuffer[0]);	//!!!
	        // 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)dwTransferSize;    // !!! 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
			DEBUGMSG(1, (TEXT("DMA %d set to intr on the last entry\r\n"), ucDMAChannel));
	    } //	if(dwTotalSize > (DWORD)MAX_DMA_TRANSFER_SIZE)
		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_D:
		////////////////////////
		DEBUGMSG(1, (TEXT("DMA %d - BYTE_OFFSET( pdwDestBuffer[0] ) = 0x%x\r\n"), ucDMAChannel, BYTE_OFFSET( pdwDestBuffer[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( pdwDestBuffer[0] ) + dwTotalSize > (DWORD)MAX_DMA_TRANSFER_SIZE) //!!!
		{
	        // Calculate the number of pages in the buffer(s)
	        dwPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(NULL, BYTE_OFFSET( pdwDestBuffer[0] ) + 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 - (DWORD)BYTE_OFFSET(pdwDestBuffer[0]);	//!!!
	        // 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)dwTransferSize;    // !!!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
	   		DEBUGMSG(1, (TEXT("DMA %d set to intr on the last entry\r\n"), ucDMAChannel));
	    } //    if(dwTotalSize > (DWORD)MAX_DMA_TRANSFER_SIZE)
		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;
	default: ;    
    }

    // Flush the data cache as the DMA controller needs the LLI information in
    // DMA accessible memory
    OEMCacheRangeFlush(NULL, 0, CACHE_SYNC_DISCARD);

    DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: Source = 0x%X\r\n"), pDMACChannelRegs->DMACCxSrcAddr));
    DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: Dest = 0x%X\r\n"), pDMACChannelRegs->DMACCxDestAddr));
    DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: LLI = 0x%X\r\n"), pDMACChannelRegs->DMACCxLLI));
    DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: Control = 0x%X\r\n"), pDMACChannelRegs->DMACCxControl));
    DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: Config = 0x%X\r\n"), pDMACChannelRegs->DMACCxConfiguration));

    // Enable the channel, this should start the transfer or allow a peripheral to do so

    pDMACChannelRegs->DMACCxConfiguration |= DMAC_CHCONFIG_E;

    DEBUGMSG(1, (TEXT("-StartDMATransfer\r\n")));


    return TRUE;
}

//
// HaltDMATransfer - Halts a DMA channel
//
// Note: Care should be taken over the state of the Cache at this point
// It is up to the user to make sure the correct data will be accessed
//
extern "C" BOOL HaltDMATransfer(PHALT_DMA_PARAMS pParams, PHALT_DMA_RESULT pResults)
{
    UCHAR   ucDMAChannel;
    volatile PDMAC_CHANNEL_REGS pDMACChannelRegs;

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

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

    // Halt any transfer (don't disable the channel as this will lose data!)
    pDMACChannelRegs->DMACCxConfiguration |= (DWORD)DMAC_CHCONFIG_H;

    // Wait for channel to become inactive
    while(pDMACChannelRegs->DMACCxConfiguration&(DWORD)DMAC_CHCONFIG_A);

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

    return TRUE;
}

//
// RestartDMATransfer - Restarts a halted DMA channel
//
// Note: Care should be taken over the state of the Cache at this point.
// It is up to the user to make sure the correct data will be accessed.
//
extern "C" BOOL RestartDMATransfer(PRESTART_DMA_PARAMS pParams, PRESTART_DMA_RESULT pResults)
{
    UCHAR   ucDMAChannel;
    volatile PDMAC_CHANNEL_REGS pDMACChannelRegs;

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

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

⌨️ 快捷键说明

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