ATxmega128A1のDMA驱动程序

来源:互联网 发布:js confirm 套for循环 编辑:程序博客网 时间:2024/06/15 22:02
//----------------dma_driver.h----------------
/* This file has been prepared for Doxygen automatic documentation generation.*/
/*! \file *********************************************************************
 *
 * \brief  XMEGA DMA Controller driver header file.
 *
 *      This file contains the function prototypes and enumerator definitions
 *      for various configuration parameters for the XMEGA DMA driver.
 *
 *      The driver is not intended for size and/or speed critical code, since
 *      most functions are just a few lines of code, and the function call
 *      overhead would decrease code performance. The driver is intended for
 *      rapid prototyping and documentation purposes for getting started with
 *      the XMEGA DMA module.
 *
 *      For size and/or speed critical code, it is recommended to copy the
 *      function contents directly into your application instead of making
 *      a function call.
 *
 * \par Application note:
 *      AVR1304: Using the XMEGA DMA Controller
 *
 * \par Documentation
 *      For comprehensive code documentation, supported compilers, compiler
 *      settings and supported devices see readme.html
 *
 * \author
 *      Atmel Corporation: http://www.atmel.com \n
 *      Support email: avr@atmel.com
 *
 * $Revision: 1653 $
 * $Date: 2008-05-21 10:26:08 +0200 (on, 21 mai 2008) $  \n
 *
 * 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:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. The name of ATMEL may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
 * SPECIFICALLY 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.
 *****************************************************************************/
#ifndef DMA_DRIVER_H
#define DMA_DRIVER_H

#include "avr_compiler.h"


/*! \brief This function enable the DMA module.
 *
 *  \note Each individual DMA channel must be enabled separately
 *        using the DMA_EnableChannel() function.
 */
#define DMA_Enable()    ( DMA.CTRL |= DMA_ENABLE_bm )

/*! \brief This function disables the DMA module.
 *
 *  \note On-going transfers will be aborted.
 */
#define DMA_Disable()   ( DMA.CTRL &= ~DMA_ENABLE_bm )

/*! \brief This function forces a software reset of the DMA module.
 *
 *  All registers will be set to their default values. If the DMA
 *  module is enabled, it must and will be disabled before being reset.
 *  It will not be enabled afterwards.
 */
#define DMA_Reset()                 \
{                            \
DMA.CTRL &= ~DMA_ENABLE_bm; \
DMA.CTRL |= DMA_RESET_bm;   \
DMA.CTRL &= ~DMA_RESET_bm   \
}

/*! Prototyping of functions. */

void DMA_ConfigDoubleBuffering( DMA_DBUFMODE_t dbufMode );
void DMA_SetPriority( DMA_PRIMODE_t priMode );
uint8_t DMA_CH_IsOngoing( volatile DMA_CH_t * channel );
uint8_t DMA_IsOngoing( void );
uint8_t DMA_CH_IsPending( volatile DMA_CH_t * channel );
uint8_t DMA_IsPending( void );
uint8_t DMA_ReturnStatus_non_blocking( volatile DMA_CH_t * channel );
uint8_t DMA_ReturnStatus_blocking( volatile DMA_CH_t * channel );
void DMA_EnableChannel( volatile DMA_CH_t * channel );
void DMA_DisableChannel( volatile DMA_CH_t * channel );
void DMA_ResetChannel( volatile DMA_CH_t * channel );
void DMA_SetIntLevel( volatile DMA_CH_t * channel,
                      DMA_CH_TRNINTLVL_t transferInt,
                      DMA_CH_ERRINTLVL_t errorInt );
void DMA_SetupBlock( volatile DMA_CH_t * channel,
                     const void * srcAddr,
                     DMA_CH_SRCRELOAD_t srcReload,
                     DMA_CH_SRCDIR_t srcDirection,
                     void * destAddr,
                     DMA_CH_DESTRELOAD_t destReload,
                     DMA_CH_DESTDIR_t destDirection,
                     uint16_t blockSize,
                     DMA_CH_BURSTLEN_t burstMode,
                     uint8_t repeatCount,
                     bool useRepeat );
void DMA_EnableSingleShot( volatile DMA_CH_t * channel );
void DMA_DisableSingleShot( volatile DMA_CH_t * channel );
void DMA_SetTriggerSource( volatile DMA_CH_t * channel, uint8_t trigger );
void DMA_StartTransfer( volatile DMA_CH_t * channel );

#endif

//-----------------------dma_driver.c-----------------------
/* This file has been prepared for Doxygen automatic documentation generation.*/
/*! \file *********************************************************************
 *
 * \brief  XMEGA DMA Controller driver source file.
 *
 *      This file contains the function implementations for the XMEGA DMA driver.
 *
 *      The driver is not intended for size and/or speed critical code, since
 *      most functions are just a few lines of code, and the function call
 *      overhead would decrease code performance. The driver is intended for
 *      rapid prototyping and documentation purposes for getting started with
 *      the XMEGA DMA module.
 *
 *      For size and/or speed critical code, it is recommended to copy the
 *      function contents directly into your application instead of making
 *      a function call.
 *
 * \par Application note:
 *      AVR1304: Using the XMEGA DMA Controller
 *
 * \par Documentation
 *      For comprehensive code documentation, supported compilers, compiler
 *      settings and supported devices see readme.html
 *
 * \author
 *      Atmel Corporation: http://www.atmel.com \n
 *      Support email: avr@atmel.com
 *
 * $Revision: 1569 $
 * $Date: 2008-04-22 13:03:43 +0200 (ti, 22 apr 2008) $  \n
 *
 * 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:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. The name of ATMEL may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
 * SPECIFICALLY 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.
 *****************************************************************************/

#include "dma_driver.h"


/*! \brief This function configures the double buffering feature of the DMA.
 *
 *  Channel pair 0/1 and/or channel pair 2/3 can
 *  be configured to operation in a chained mode. This means that
 *  once the first channel has completed its transfer, the second
 *  channel takes over automatically. It is important to setup the
 *  channel pair with equal block sizes, repeat modes etc.
 *
 *  Do not change these settings after a transfer has started.
 *
 *  \param  dbufMode  Double buffering mode.
 */
void DMA_ConfigDoubleBuffering( DMA_DBUFMODE_t dbufMode )
{
DMA.CTRL = ( DMA.CTRL & ~DMA_DBUFMODE_gm ) | dbufMode;//Double buffer enabled on channel0/1 and channel2/3
}


/*! \brief This function selects what priority scheme to use for the DMA channels.
 *
 *  It decides what channels to schedule in a round-robin
 *  manner, which means that they take turns in acquiring the data bus
 *  for individual data transfers. Channels not included in the round-robin
 *  scheme will have fixed priorities, with channel 0 having highest priority.
 *
 *  \note  Do not change these settings after a transfer has started.
 *
 *  \param  priMode  An enum selection the priority scheme to use.
 */
void DMA_SetPriority( DMA_PRIMODE_t priMode )
{
DMA.CTRL = ( DMA.CTRL & ~DMA_PRIMODE_gm ) | priMode;
}


/*! \brief This function checks if the channel has on-going transfers not
 *         finished yet.
 *
 *  \param  channel Channel to check.
 *
 *  \return  Non-zero if the selected channel have on-going transfers,
 *           zero otherwise.
 */
uint8_t DMA_CH_IsOngoing( volatile DMA_CH_t * channel )
{
uint8_t flagMask;
flagMask = channel->CTRLB & DMA_CH_CHBUSY_bm;
return flagMask;
}

/*! \brief This function checks if any channel have on-going transfers are not
 *         finished yet.
 *
 *  \return  Non-zero if any channel have on-going transfers, zero otherwise.
 */
uint8_t DMA_IsOngoing( void )
{
uint8_t flagMask;
flagMask = DMA.STATUS & 0xF0;
return flagMask;
}

/*! \brief This function check if the channel has transfers pending.
 *
 *  This function checks if the channel selected have transfers that are
 *  pending, which means that a transfer has been requested by a trigger source
 *  or by a manual request, but the channel haven't yet started its transfer.
 *
 *  \param  channel Channel to check.
 *
 *  \return  Non-zero if the selected channel have pending transfers,
 *           zero otherwise.
 */
uint8_t DMA_CH_IsPending( volatile DMA_CH_t * channel )
{
uint8_t flagMask;
flagMask = channel->CTRLB & DMA_CH_CHPEND_bm;
return flagMask;
}


/*! \brief This function check if there are any transfers pending.
 *
 *  This function checks if any channel have transfers that are pending,
 *  which means that a transfer has been requested by a trigger source
 *  or by a manual request, but the channels haven't yet started its transfer.
 *
 *  \return  Non-zero if the selected channel have pending transfers,
 *           zero otherwise.
 */
uint8_t DMA_IsPending( void )
{
uint8_t flagMask;
flagMask = DMA.STATUS & 0x0F;
return flagMask;
}

/*! \brief This function return the interrupt flag status of a channel.
 *
 *  This function return the status the channels selected finishes an on-going
 *  transfer or encounters an error and aborts the transfer.
 *
 *  \note  Flags covered by the channel will NOT be cleared when this
 *         function exits.
 *
 *  \param  channel  The channel to check.
 *
 *  \return  Relevant interrupt flags.
 */
uint8_t DMA_ReturnStatus_non_blocking( volatile DMA_CH_t * channel )
{
uint8_t relevantFlags;
relevantFlags = channel->CTRLB & (DMA_CH_ERRIF_bm | DMA_CH_TRNIF_bm);
return relevantFlags;
}


/*! \brief This function return the interrupt flag status of a channel.
 *
 *  This function return the status of the channel selected either finishes
 *  an on-going transfer or encounters an error and aborts the transfer.
 *
 *  \note  Flags covered by the channel will be cleared when this
 *         function exits. However, it will return the flag status. This
 *         is a BLOCKING function, and will go into a dead-lock if the flags
 *         never get set.
 *
 *  \param  channel  The channel to check.
 *
 *  \return  Relevant interrupt flags.
 */
uint8_t DMA_ReturnStatus_blocking( volatile DMA_CH_t * channel )
{
uint8_t flagMask;
uint8_t relevantFlags;

flagMask = DMA_CH_ERRIF_bm | DMA_CH_TRNIF_bm;

do {
relevantFlags = channel->CTRLB & flagMask;
} while (relevantFlags == 0x00);

channel->CTRLB = flagMask;
return relevantFlags;
}

/*! \brief This function enables one DMA channel sub module.
 *
 *  \note A DMA channel will be automatically disabled
 *        when a transfer is finished.
 *
 *  \param  channel  The channel to enable.
 */
void DMA_EnableChannel( volatile DMA_CH_t * channel )
{
channel->CTRLA |= DMA_CH_ENABLE_bm;
}


/*! \brief This function disables one DMA channel sub module.
 *
 *  \note On-going transfers will be aborted and the error flag be set if a
 *        channel is disabled in the middle of a transfer.
 *
 *  \param  channel  The channel to disable.
 */
void DMA_DisableChannel( volatile DMA_CH_t * channel )
{
channel->CTRLA &= ~DMA_CH_ENABLE_bm;
}


/*! \brief This function forces a software reset of the DMA channel sub module.
 *
 *  All registers will be set to their default values. If the channel
 *  is enabled, it must and will be disabled before being reset.
 *  It will not be enabled afterwards.
 *
 *  \param  channel  The channel to reset.
 */
void DMA_ResetChannel( volatile DMA_CH_t * channel )
{
channel->CTRLA &= ~DMA_CH_ENABLE_bm;
channel->CTRLA |= DMA_CH_RESET_bm;
channel->CTRLA &= ~DMA_CH_RESET_bm;
}


/*! \brief This function configures the interrupt levels for one DMA channel.
 *
 *  \note  The interrupt level parameter use the data type for channel 0,
 *         regardless of which channel is used. This is because we use the
 *         same function for all channel. This method relies upon channel
 *         bit fields to be located this way: CH3:CH2:CH1:CH0.
 *
 *  \param  channel      The channel to configure.
 *  \param  transferInt  Transfer Complete Interrupt Level.
 *  \param  errorInt     Transfer Error Interrupt Level.
 */
void DMA_SetIntLevel( volatile DMA_CH_t * channel,
                      DMA_CH_TRNINTLVL_t transferInt,
                      DMA_CH_ERRINTLVL_t errorInt )
{
channel->CTRLB = (channel->CTRLB & ~(DMA_CH_ERRINTLVL_gm | DMA_CH_TRNINTLVL_gm)) |
 transferInt | errorInt;
}


/*! \brief This function configures the necessary registers for a block transfer.
 *
 *  \note The transfer must be manually triggered or a trigger source
 *        selected before the transfer starts. It is possible to reload the
 *        source and/or destination address after each data transfer, block
 *        transfer or only when the entire transfer is complete.
 *        Do not change these settings after a transfer has started.
 *
 *  \param  channel        The channel to configure.
 *  \param  srcAddr        Source memory address.
 *  \param  srcReload      Source address reload mode.
 *  \param  srcDirection   Source address direction (fixed, increment, or decrement).
 *  \param  destAddr       Destination memory address.
 *  \param  destReload     Destination address reload mode.
 *  \param  destDirection  Destination address direction (fixed, increment, or decrement).
 *  \param  blockSize      Block size in number of bytes (0 = 64k).
 *  \param  burstMode      Number of bytes per data transfer (1, 2, 4, or 8 bytes).
 *  \param  repeatCount    Number of blocks, 0x00 if you want to repeat at infinitum.
 *  \param  useRepeat      True if reapeat should be used, false if not.
 */
void DMA_SetupBlock( volatile DMA_CH_t * channel,
                     const void * srcAddr,
                     DMA_CH_SRCRELOAD_t srcReload,
                     DMA_CH_SRCDIR_t srcDirection,
                     void * destAddr,
                     DMA_CH_DESTRELOAD_t destReload,
                     DMA_CH_DESTDIR_t destDirection,
                     uint16_t blockSize,
                     DMA_CH_BURSTLEN_t burstMode,
                     uint8_t repeatCount,
                     bool useRepeat )
{
channel->SRCADDR0 = (( (uint16_t) srcAddr) >> 0*8 ) & 0xFF;
channel->SRCADDR1 = (( (uint16_t) srcAddr) >> 1*8 ) & 0xFF;
channel->SRCADDR2 = 0;

channel->DESTADDR0 = (( (uint16_t) destAddr) >> 0*8 ) & 0xFF;
channel->DESTADDR1 = (( (uint16_t) destAddr) >> 1*8 ) & 0xFF;
channel->DESTADDR2 = 0;

channel->ADDRCTRL = (uint8_t) srcReload | srcDirection |
                              destReload | destDirection;
channel->TRFCNT = blockSize;
channel->CTRLA = ( channel->CTRLA & ~( DMA_CH_BURSTLEN_gm | DMA_CH_REPEAT_bm ) ) |
                  burstMode | ( useRepeat ? DMA_CH_REPEAT_bm : 0);

if ( useRepeat ) {
channel->REPCNT = repeatCount;
}
}


/*! \brief This function enables single-shot transfer mode for a channel.
 *
 *  In single-shot mode, one transfer trigger (manual or from a trigger source)
 *  only causes one single data transfer (1, 2, 4, or 8 byte). When not
 *  in single-shot mode, one transfer trigger causes one entire block transfer.
 *  Do not change this setting after a transfer has started.
 *
 *  \param  channel  The channel to configure.
 */
void DMA_EnableSingleShot( volatile DMA_CH_t * channel )
{
channel->CTRLA |= DMA_CH_SINGLE_bm;
}


/*! \brief This function disables single-shot transfer mode for a channel.
 *
 *  In single-shot mode, one transfer trigger (manual or from a trigger source)
 *  only causes one single data transfer (1, 2, 4, or 8 byte). When not
 *  in single-shot mode, one transfer trigger causes one entire block transfer.
 *
 *  Do not change this setting after a transfer has started.
 *
 *  \param  channel  The channel to configure.
 */
void DMA_DisableSingleShot( volatile DMA_CH_t * channel )
{
channel->CTRLA &= ~DMA_CH_SINGLE_bm;
}


/*! \brief This function sets the transfer trigger source for a channel.
 *
 *  \note A manual transfer requests can be used even after setting a trigger
 *        source. Do not change this setting after a transfer has started.
 *
 *  \param  channel  The channel to configure.
 *  \param  trigger  The trigger source ID.
 */
void DMA_SetTriggerSource( volatile DMA_CH_t * channel, uint8_t trigger )
{
channel->TRIGSRC = trigger;
}


/*! \brief This function sends a manual transfer request to the channel.
 *
 *  The bit will automatically clear when transfer starts.
 *
 *  \param  channel  The channel to request a transfer for.
 */
void DMA_StartTransfer( volatile DMA_CH_t * channel )
{
channel->CTRLA |= DMA_CH_TRFREQ_bm;
}