blob: e78a7c5cdb61709e9592b5fca2fb543f6de9998d [file] [log] [blame]
/* ----------------------------------------------------------------------------
* 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 <utility/assert.h>
#include <utility/trace.h>
//------------------------------------------------------------------------------
// 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 = ~(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;
}
//------------------------------------------------------------------------------
/// 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;
}
//------------------------------------------------------------------------------
/// 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, "this channel does not exist");
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;
value &= ~ (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;
}
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 &= ~ (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 << 24;
break;
case DMA_TRANSFER_LLI:
value |= addressingType << 24;
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;
value &= ~ (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;
}
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;
}
//------------------------------------------------------------------------------
/// 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 &= ~ (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;
}
//------------------------------------------------------------------------------
/// 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 &= ~ (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;
}