//------------------------------------------------------------------------------ /// Configure the DMA transfer buffer by giving transfer mode, it could be single /// buffer or multi-buffer(LLI/auto-reload/contiguous buffers) with or without /// Picture-In-Picture mode. /// \param dwChannel Particular dwChannel number. /// \param sourceTransferMode Source buffer transfer mode. /// \param destTransferMode Destination buffer transfer mode. /// \param lli Pointer to a DmaLinkList structure instance. /// \param pip Pointer to a PictureInPicture structure. //------------------------------------------------------------------------------ extern uint32_t DMAD_Configure_Buffer( uint32_t dwChannel, uint32_t sourceTransferMode, uint32_t destTransferMode, DmaLinkList *lli ) { DmaTransfer *pTransfer = &(dmad.transfers[dwChannel]) ; // Check that no transfer is pending on the dwChannel if ( pTransfer-> transferSize > 0 ) { TRACE_ERROR("DAM transfer is already pending\n\r"); return DMAD_ERROR_BUSY ; } // Configure source transfer mode. DMA_SetSourceBufferMode( DMAC, dwChannel, sourceTransferMode, 0 ) ; // Configure destination transfer mode. DMA_SetDestBufferMode( DMAC, dwChannel, destTransferMode, 0 ) ; if ( lli ) { DMA_SetDescriptorAddr( DMAC, dwChannel, (uint32_t)(&lli[0]) ) ; } else { DMA_SetDescriptorAddr( DMAC, dwChannel, 0 ) ; } return 0 ; }
//------------------------------------------------------------------------------ /// Configure the DMA transfer buffer by giving transfer mode, it could be single /// buffer or multi-buffer(LLI/auto-reload/contiguous buffers) with or without /// Picture-In-Picture mode. /// \param channel Particular channel number. /// \param sourceTransferMode Source buffer transfer mode. /// \param destTransferMode Destination buffer transfer mode. /// \param lli Pointer to a DmaLinkList structure instance. /// \param pip Pointer to a PictureInPicture structure. //------------------------------------------------------------------------------ U8 DMAD_Configure_Buffer(U8 channel, U8 sourceTransferMode, U8 destTransferMode, DmaLinkList *lli, PictureInPicture *pip) { DmaTransfer *pTransfer = &(dmad.transfers[channel]); if(pTransfer-> transferSize > 0) // Check that no transfer is pending on the channel { DEBUG_MSG("DAM transfer is already pending"); return DMAD_ERROR_BUSY; } DMA_SetSourceBufferMode(channel, sourceTransferMode, 0); // Configure source transfer mode. DMA_SetDestBufferMode(channel, destTransferMode, 0); // Configure destination transfer mode. if(lli) { DMA_SetDescriptorAddr(channel, (U32)(&lli[0])); } else { DMA_SetDescriptorAddr(channel, 0); } if(pip) { if(pip->pipSourceBoundarySize)// If source picture-in-picture mode is enabled, program the DMAC_SPIP. { DMA_SPIPconfig(channel, pip->pipSourceHoleSize, pip->pipSourceBoundarySize); // If destination picture-in-picture mode is enabled, program the DMAC_DPIP. } if(pip->pipDestBoundarySize) { DMA_DPIPconfig(channel, pip->pipDestHoleSize, pip->pipDestBoundarySize); } } return 0; }
//------------------------------------------------------------------------------ /// Configure the DMA transfer buffer by giving transfer mode, it could be single /// buffer or multi-buffer(LLI/auto-reload/contiguous buffers) with or without /// Picture-In-Picture mode. /// \param channel Particular channel number. /// \param sourceTransferMode Source buffer transfer mode. /// \param destTransferMode Destination buffer transfer mode. /// \param lli Pointer to a DmaLinkList structure instance. /// \param pip Pointer to a PictureInPicture structure. //------------------------------------------------------------------------------ unsigned char DMAD_Configure_Buffer(unsigned char channel, unsigned char sourceTransferMode, unsigned char destTransferMode, DmaLinkList *lli, PictureInPicture *pip) { DmaTransfer *pTransfer = &(dmad.transfers[channel]); // Check that no transfer is pending on the channel if (pTransfer-> transferSize > 0 ) { TRACE_ERROR("DAM transfer is already pending\n\r"); return DMAD_ERROR_BUSY; } // Configure source transfer mode. DMA_SetSourceBufferMode(channel, sourceTransferMode, 0); // Configure destination transfer mode. DMA_SetDestBufferMode(channel, destTransferMode, 0); if(lli){ DMA_SetDescriptorAddr(channel, (unsigned int)(&lli[0])); } else { DMA_SetDescriptorAddr(channel, 0); } if(pip){ #if defined(AT91C_SRC_PIP) // If source picture-in-picture mode is enabled, program the DMAC_SPIP. if(pip->pipSourceBoundarySize){ // If destination picture-in-picture mode is enabled, program the DMAC_DPIP. DMA_SPIPconfiguration(channel, pip->pipSourceHoleSize, pip->pipSourceBoundarySize); } #endif #if defined(AT91C_DST_PIP) if(pip->pipDestBoundarySize){ DMA_DPIPconfiguration(channel, pip->pipDestHoleSize, pip->pipDestBoundarySize); } #endif } return 0; }
//------------------------------------------------------------------------------ //./ Configure the DMA source and destination with Linker List mode. //./ \param pCommand Pointer to command //------------------------------------------------------------------------------ static void configureLinkList(AT91S_SPI *pSpiHw, SpiDCmd *pCommand) { // Setup RX Link List dmaRxLinkList[0].sourceAddress = (unsigned int)&pSpiHw->SPI_RDR; dmaRxLinkList[0].destAddress = (unsigned int)pCommand->pCmd; dmaRxLinkList[0].controlA = pCommand->cmdSize | AT91C_HDMA_SRC_WIDTH_BYTE | AT91C_HDMA_DST_WIDTH_BYTE ; dmaRxLinkList[0].controlB = 0 //| AT91C_HDMA_SIF_0 //| AT91C_HDMA_DIF_0 | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM | AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM | AT91C_HDMA_FC_PER2MEM | AT91C_HDMA_SRC_ADDRESS_MODE_FIXED | AT91C_HDMA_DST_ADDRESS_MODE_INCR ; dmaTxLinkList[0].sourceAddress = (unsigned int)pCommand->pCmd; dmaTxLinkList[0].destAddress = (unsigned int)&pSpiHw->SPI_TDR; dmaTxLinkList[0].controlA = pCommand->cmdSize | AT91C_HDMA_SRC_WIDTH_BYTE | AT91C_HDMA_DST_WIDTH_BYTE ; dmaTxLinkList[0].controlB = 0 //| AT91C_HDMA_SIF_0 //| AT91C_HDMA_DIF_0 | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM | AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM | AT91C_HDMA_FC_MEM2PER | AT91C_HDMA_SRC_ADDRESS_MODE_INCR | AT91C_HDMA_DST_ADDRESS_MODE_FIXED ; // Only command if (pCommand->pData == 0) { dmaRxLinkList[0].descriptor = 0; dmaTxLinkList[0].descriptor = 0; } // Command & Data else { dmaRxLinkList[0].descriptor = (unsigned int)&dmaRxLinkList[1]; dmaRxLinkList[1].sourceAddress = (unsigned int)&pSpiHw->SPI_RDR; dmaRxLinkList[1].destAddress = (unsigned int)pCommand->pData; dmaRxLinkList[1].controlA = pCommand->dataSize | AT91C_HDMA_SRC_WIDTH_BYTE | AT91C_HDMA_DST_WIDTH_BYTE ; dmaRxLinkList[1].controlB = 0 //| AT91C_HDMA_SIF_0 //| AT91C_HDMA_DIF_0 | AT91C_HDMA_SRC_DSCR_FETCH_DISABLE | AT91C_HDMA_DST_DSCR_FETCH_DISABLE | AT91C_HDMA_FC_PER2MEM | AT91C_HDMA_SRC_ADDRESS_MODE_FIXED | AT91C_HDMA_DST_ADDRESS_MODE_INCR ; dmaRxLinkList[1].descriptor = 0; dmaTxLinkList[0].descriptor = (unsigned int)&dmaTxLinkList[1]; dmaTxLinkList[1].sourceAddress = (unsigned int)pCommand->pData; dmaTxLinkList[1].destAddress = (unsigned int)&pSpiHw->SPI_TDR; dmaTxLinkList[1].controlA = pCommand->dataSize | AT91C_HDMA_SRC_WIDTH_BYTE | AT91C_HDMA_DST_WIDTH_BYTE ; dmaTxLinkList[1].controlB = 0 //| AT91C_HDMA_SIF_0 //| AT91C_HDMA_DIF_0 | AT91C_HDMA_SRC_DSCR_FETCH_DISABLE | AT91C_HDMA_DST_DSCR_FETCH_DISABLE | AT91C_HDMA_FC_MEM2PER | AT91C_HDMA_SRC_ADDRESS_MODE_INCR | AT91C_HDMA_DST_ADDRESS_MODE_FIXED ; dmaTxLinkList[1].descriptor = 0; } // Setup registers DMA_SetDescriptorAddr(DMA_CHANNEL_0, (unsigned int)&dmaRxLinkList[0]); DMA_SetDescriptorAddr(DMA_CHANNEL_1, (unsigned int)&dmaTxLinkList[0]); AT91C_BASE_HDMA->HDMA_CH[DMA_CHANNEL_0].HDMA_CTRLB = 0 | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM | AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM ; AT91C_BASE_HDMA->HDMA_CH[DMA_CHANNEL_1].HDMA_CTRLB = 0 | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM | AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM ; }
//------------------------------------------------------------------------------ /// Sends the contents of a data buffer a SSC peripheral, using the PDC. Returns /// true if the buffer has been queued for transmission; otherwise returns /// false. /// \param ssc Pointer to an AT91S_SSC instance. /// \param buffer Data buffer to send. /// \param length Size of the data buffer. //------------------------------------------------------------------------------ unsigned char SSC_WriteBuffer(AT91S_SSC *ssc, void *buffer, unsigned int length) { #if !defined(CHIP_SSC_DMA) // Check if first bank is free if (ssc->SSC_TCR == 0) { ssc->SSC_TPR = (unsigned int) buffer; ssc->SSC_TCR = length; ssc->SSC_PTCR = AT91C_PDC_TXTEN; return 1; } // Check if second bank is free else if (ssc->SSC_TNCR == 0) { ssc->SSC_TNPR = (unsigned int) buffer; ssc->SSC_TNCR = length; return 1; } #else unsigned short* startSourceAddr; unsigned short* startDestAddr; unsigned int srcAddress; unsigned int destAddress; unsigned int buffSize; unsigned int LLI_rownumber = 0; startSourceAddr = (unsigned short*)(buffer); startDestAddr = (unsigned short*)(&ssc->SSC_THR); srcAddress = (unsigned int)startSourceAddr; // Set the data start address destAddress = (unsigned int)startDestAddr; buffSize = length; if(buffSize > 0x8000){ TRACE_WARNING("SSC DMA, size too big %d\n\r", buffSize); buffSize = 0x8000; } // Set DMA channel DSCR DMA_SetDescriptorAddr(BOARD_SSC_DMA_CHANNEL, (unsigned int)&LLI_CH[0]); // Clear any pending interrupts DMA_GetStatus(); //Set DMA channel control B DMA_SetSourceBufferMode(BOARD_SSC_DMA_CHANNEL, DMA_TRANSFER_LLI, (AT91C_HDMA_SRC_ADDRESS_MODE_INCR >> 24)); DMA_SetDestBufferMode(BOARD_SSC_DMA_CHANNEL, DMA_TRANSFER_LLI, (AT91C_HDMA_DST_ADDRESS_MODE_FIXED >> 28)); DMA_SetFlowControl(BOARD_SSC_DMA_CHANNEL, AT91C_HDMA_FC_MEM2PER >> 21); // Set DMA channel config DMA_SetConfiguration(BOARD_SSC_DMA_CHANNEL, BOARD_SSC_DMA_HW_SRC_REQ_ID \ | BOARD_SSC_DMA_HW_DEST_REQ_ID \ | AT91C_HDMA_SRC_H2SEL_SW \ | AT91C_HDMA_DST_H2SEL_HW \ | AT91C_HDMA_SOD_DISABLE \ | AT91C_HDMA_FIFOCFG_LARGESTBURST); // Set link list while(srcAddress < ((unsigned int)(startSourceAddr + buffSize))) { if(((unsigned int)(startSourceAddr + buffSize)) - srcAddress <= (BOARD_SSC_DMA_FIFO_SIZE) ) { AT91F_Prepare_Multiple_Transfer(BOARD_SSC_DMA_CHANNEL, LLI_rownumber, LAST_ROW, srcAddress, destAddress, (((((unsigned int)(startSourceAddr + buffSize)) - srcAddress)/2) | AT91C_HDMA_SRC_WIDTH_HALFWORD | AT91C_HDMA_DST_WIDTH_HALFWORD | AT91C_HDMA_SCSIZE_1 | AT91C_HDMA_DCSIZE_1 ), ( //| AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM AT91C_HDMA_DST_DSCR_FETCH_DISABLE | AT91C_HDMA_DST_ADDRESS_MODE_FIXED | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM //| AT91C_HDMA_SRC_DSCR_FETCH_DISABLE | AT91C_HDMA_SRC_ADDRESS_MODE_INCR | AT91C_HDMA_FC_MEM2PER)); } else { AT91F_Prepare_Multiple_Transfer(BOARD_SSC_DMA_CHANNEL, LLI_rownumber, 0, srcAddress, destAddress, ((BOARD_SSC_DMA_FIFO_SIZE)/2 | AT91C_HDMA_SRC_WIDTH_HALFWORD | AT91C_HDMA_DST_WIDTH_HALFWORD | AT91C_HDMA_SCSIZE_1 | AT91C_HDMA_DCSIZE_1 ), ( //| AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM AT91C_HDMA_DST_DSCR_FETCH_DISABLE | AT91C_HDMA_DST_ADDRESS_MODE_FIXED | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM //| AT91C_HDMA_SRC_DSCR_FETCH_DISABLE | AT91C_HDMA_SRC_ADDRESS_MODE_INCR | AT91C_HDMA_FC_MEM2PER)); } srcAddress += BOARD_SSC_DMA_FIFO_SIZE; LLI_rownumber++; } #endif // No free banks return 0; }