/* ---------------------------------------------------------------------------- * ATMEL Microcontroller Software Support * ---------------------------------------------------------------------------- * Copyright (c) 2008, Atmel Corporation * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * * Atmel's name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ---------------------------------------------------------------------------- */ //------------------------------------------------------------------------------ // Headers //------------------------------------------------------------------------------ #include "dma.h" #include #include //------------------------------------------------------------------------------ // Global functions //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ /// Configure a DMAC peripheral //------------------------------------------------------------------------------ void DMA_Config(unsigned int flag) { AT91C_BASE_HDMA->HDMA_GCFG = flag; } //------------------------------------------------------------------------------ /// Enables a DMAC peripheral //------------------------------------------------------------------------------ void DMA_Enable(void) { AT91C_BASE_HDMA->HDMA_EN = AT91C_HDMA_ENABLE; } //------------------------------------------------------------------------------ /// Disables DMAC peripheral //------------------------------------------------------------------------------ void DMA_Disable(void) { AT91C_BASE_HDMA->HDMA_EN = ~(unsigned int)AT91C_HDMA_ENABLE; } //----------------------------------------------------------------------------- /// Enable DMA interrupt /// \param flag IT to be enabled //----------------------------------------------------------------------------- void DMA_EnableIt (unsigned int flag) { AT91C_BASE_HDMA->HDMA_EBCIER = flag; } //----------------------------------------------------------------------------- /// Disable DMA interrupt /// \param flag IT to be enabled //----------------------------------------------------------------------------- void DMA_DisableIt (unsigned int flag) { AT91C_BASE_HDMA->HDMA_EBCIDR = flag; } //----------------------------------------------------------------------------- /// Return DMA Interrupt Status //----------------------------------------------------------------------------- unsigned int DMA_GetStatus(void) { return (AT91C_BASE_HDMA->HDMA_EBCISR); } //----------------------------------------------------------------------------- /// Return DMA Interrupt Mask Status //----------------------------------------------------------------------------- unsigned int DMA_GetInterruptMask(void) { return (AT91C_BASE_HDMA->HDMA_EBCIMR); } //----------------------------------------------------------------------------- /// Returns the current status register of the given DMA peripheral, but /// masking interrupt sources which are not currently enabled. //----------------------------------------------------------------------------- unsigned int DMA_GetMaskedStatus(void) { unsigned int status; status = AT91C_BASE_HDMA->HDMA_EBCISR; status &= AT91C_BASE_HDMA->HDMA_EBCIMR; return status; } //------------------------------------------------------------------------------ /// Enables DMAC channel /// \param channel Particular channel number. //------------------------------------------------------------------------------ void DMA_EnableChannel(unsigned int channel) { ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist"); AT91C_BASE_HDMA->HDMA_CHER |= DMA_ENA << channel; } void DMA_EnableChannels(unsigned int bmChannels) { AT91C_BASE_HDMA->HDMA_CHER = bmChannels; } //------------------------------------------------------------------------------ /// Disables a DMAC channel /// \param channel Particular channel number. //------------------------------------------------------------------------------ void DMA_DisableChannel(unsigned int channel) { ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist"); AT91C_BASE_HDMA->HDMA_CHDR |= DMA_DIS << channel; } void DMA_DisableChannels(unsigned int bmChannels) { AT91C_BASE_HDMA->HDMA_CHDR = bmChannels; } //------------------------------------------------------------------------------ /// Resume DMAC channel from an stall state. /// \param channel Particular channel number. //------------------------------------------------------------------------------ void DMA_KeeponChannel(unsigned int channel) { ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist"); AT91C_BASE_HDMA->HDMA_CHER |= DMA_KEEPON << channel; } //------------------------------------------------------------------------------ /// Clear automatic mode for multi-buffer transfer. /// \param channel Particular channel number. //------------------------------------------------------------------------------ void DMA_ClearAutoMode(unsigned int channel) { ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist"); AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB &= 0x7FFFFFFF; } //------------------------------------------------------------------------------ /// Return DMAC channel status //------------------------------------------------------------------------------ unsigned int DMA_GetChannelStatus(void) { return( AT91C_BASE_HDMA->HDMA_CHSR); } //----------------------------------------------------------------------------- /// Set DMA source address used by a HDMA channel. /// \param channel Particular channel number. /// \param sources sources address. //----------------------------------------------------------------------------- void DMA_SetSourceAddr(unsigned char channel, unsigned int address) { ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist"); AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_SADDR = address; } //----------------------------------------------------------------------------- /// Set DMA destination address used by a HDMA channel. /// \param channel Particular channel number. /// \param sources destination address. //----------------------------------------------------------------------------- void DMA_SetDestinationAddr(unsigned char channel, unsigned int address) { ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist"); AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_DADDR = address; } //----------------------------------------------------------------------------- /// Set DMA descriptor address used by a HDMA channel. /// \param channel Particular channel number. /// \param sources destination address. //----------------------------------------------------------------------------- void DMA_SetDescriptorAddr(unsigned char channel, unsigned int address) { ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist"); AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_DSCR = address ; } //----------------------------------------------------------------------------- /// Set DMA control A register used by a HDMA channel. /// \param channel Particular channel number. /// \param size Dma transfer size in byte. /// \param sourceWidth Single transfer width for source. /// \param destWidth Single transfer width for destination. /// \param done Transfer done field. //----------------------------------------------------------------------------- void DMA_SetSourceBufferSize(unsigned char channel, unsigned int size, unsigned char sourceWidth, unsigned char destWidth, unsigned char done) { ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist"); ASSERT(sourceWidth < 4, "width does not support"); ASSERT(destWidth < 4, "width does not support"); AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLA = (size | sourceWidth << 24 | destWidth << 28 | done << 31); } //----------------------------------------------------------------------------- /// Set DMA transfer mode for source used by a HDMA channel. /// \param channel Particular channel number. /// \param transferMode Transfer buffer mode (single, LLI, reload or contiguous) /// \param addressingType Type of addrassing mode /// 0 : incrementing, 1: decrementing, 2: fixed. //----------------------------------------------------------------------------- void DMA_SetSourceBufferMode(unsigned char channel, unsigned char transferMode, unsigned char addressingType) { unsigned int value; ASSERT(channel < DMA_CHANNEL_NUM, "channel %d does not exist", channel); value = AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB; value &= ~ (AT91C_SRC_DSCR | AT91C_SRC_INCR | 1<<31); switch(transferMode){ case DMA_TRANSFER_SINGLE: value |= AT91C_SRC_DSCR | addressingType << 24; break; case DMA_TRANSFER_LLI: value |= addressingType << 24; break; case DMA_TRANSFER_RELOAD: case DMA_TRANSFER_CONTIGUOUS: value |= AT91C_SRC_DSCR | addressingType << 24 | 1<<31; break; } AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB = value; if(transferMode == DMA_TRANSFER_RELOAD || transferMode == DMA_TRANSFER_CONTIGUOUS){ value = AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CFG; #if defined(AT91C_SRC_REP) value &= ~(unsigned int)AT91C_SRC_REP; // When automatic mode is activated, the source address and the control register are reloaded from previous transfer. if(transferMode == DMA_TRANSFER_RELOAD) { value |= AT91C_SRC_REP; } #endif AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CFG = value; } else { AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CFG = 0; } } //----------------------------------------------------------------------------- /// Set DMA transfer mode for destination used by a HDMA channel. /// \param channel Particular channel number. /// \param transferMode Transfer buffer mode (single, LLI, reload or contiguous) /// \param addressingType Type of addrassing mode /// 0 : incrementing, 1: decrementing, 2: fixed. //----------------------------------------------------------------------------- void DMA_SetDestBufferMode(unsigned char channel, unsigned char transferMode, unsigned char addressingType) { unsigned int value; ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist"); value = AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB; value &= ~(unsigned int)(AT91C_DST_DSCR | AT91C_DST_INCR); switch(transferMode){ case DMA_TRANSFER_SINGLE: case DMA_TRANSFER_RELOAD: case DMA_TRANSFER_CONTIGUOUS: value |= AT91C_DST_DSCR | addressingType << 28; break; case DMA_TRANSFER_LLI: value |= addressingType << 28; break; } AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB = value; if(transferMode == DMA_TRANSFER_RELOAD || transferMode == DMA_TRANSFER_CONTIGUOUS){ value = AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CFG; #if defined(AT91C_DST_REP) value &= ~(unsigned int)AT91C_DST_REP; // When automatic mode is activated, the source address and the control register are reloaded from previous transfer. if(transferMode == DMA_TRANSFER_RELOAD) { value |= AT91C_DST_REP; } #endif AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CFG = value; } else { AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CFG = 0; } } //------------------------------------------------------------------------------ /// Set DMA configuration registe used by a HDMA channel. /// \param channel Particular channel number. /// \param value configuration value. //------------------------------------------------------------------------------ void DMA_SetConfiguration(unsigned char channel, unsigned int value) { ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist"); AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CFG = value; } #if defined(AT91C_SRC_PIP) //------------------------------------------------------------------------------ /// Set DMA source PIP configuration used by a HDMA channel. /// \param channel Particular channel number. /// \param pipHole stop on done mode. /// \param pipBoundary lock mode. //------------------------------------------------------------------------------ void DMA_SPIPconfiguration(unsigned char channel, unsigned int pipHole, unsigned int pipBoundary) { unsigned int value; ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist"); value = AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB; value &= ~(unsigned int)AT91C_SRC_PIP; value |= AT91C_SRC_PIP; AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB = value; AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_SPIP = (pipHole + 1) | pipBoundary <<16; } #endif #if defined(AT91C_DST_PIP) //------------------------------------------------------------------------------ /// Set DMA destination PIP configuration used by a HDMA channel. /// \param channel Particular channel number. /// \param pipHole stop on done mode. /// \param pipBoundary lock mode. //------------------------------------------------------------------------------ void DMA_DPIPconfiguration(unsigned char channel, unsigned int pipHole, unsigned int pipBoundary) { unsigned int value; ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist"); value = AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB; value &= ~(unsigned int)AT91C_DST_PIP; value |= AT91C_DST_PIP; AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB = value; AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_DPIP = (pipHole + 1) | pipBoundary <<16; } #endif //----------------------------------------------------------------------------- /// Set DMA control B register Flow control bit field. /// \param channel Particular channel number. /// \param size Dma transfer size in byte. /// \param sourceWidth Single transfer width for source. /// \param destWidth Single transfer width for destination. /// \param done Transfer done field. //----------------------------------------------------------------------------- void DMA_SetFlowControl(unsigned char channel, unsigned int flow) { unsigned int value; ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist"); ASSERT(flow < 4, "flow control does not support"); value = AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB; value &= ~(unsigned int)AT91C_FC; value |= flow << 21; AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB = value; }