summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/arm/atsam/libraries/libchip/source/afe_dma.c
blob: b137d0194d8df49c0ab9e5c0844537be28f0e76c (plain) (tree)
































































































































































































































































                                                                                                             
/* ---------------------------------------------------------------------------- */
/*                  Atmel Microcontroller Software Support                      */
/*                       SAM Software Package License                           */
/* ---------------------------------------------------------------------------- */
/* Copyright (c) 2015, Atmel Corporation                                        */
/*                                                                              */
/* All rights reserved.                                                         */
/*                                                                              */
/* Redistribution and use in source and binary forms, with or without           */
/* modification, are permitted provided that the following condition is 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.                           */
/* ---------------------------------------------------------------------------- */

/** \addtogroup afe_dma_module Working with AFE (DMA support)
 *  \ingroup peripherals_module
 * The afec driver provides the interface to configure and use the afecC
 * peripheral with DMA support.\n
 *
 * For more accurate information, please look at the AFEC section of the
 * Datasheet.
 *
 * Related files :\n
 * \ref afe_dma.c\n
 * \ref afe_dma.h\n
 */
/*@{*/
/*@}*/
/**
 * \file
 *
 *
 */
/*----------------------------------------------------------------------------
 *        Headers
 *----------------------------------------------------------------------------*/

#include "chip.h"
#include "afe_dma.h"
#include "xdmad.h"

#include <stdint.h>
#include <assert.h>

/*  DMA driver instance */
static uint32_t afeDmaRxChannel;

/*----------------------------------------------------------------------------
 *        Local functions
 *----------------------------------------------------------------------------*/

/**
 * \brief AFE xDMA Rx callback
 * Invoked on AFE DMA reception done.
 * \param channel DMA channel.
 * \param pArg Pointer to callback argument - Pointer to AfeDma instance.
 */
static void Afe_Rx_Cb(uint32_t channel, AfeDma *pArg)
{
	AfeCmd *pAfedCmd = pArg->pCurrentCommand;

	if (channel != afeDmaRxChannel)
		return;

	/* Configure and enable interrupt on RC compare */
	NVIC_ClearPendingIRQ(XDMAC_IRQn);
	NVIC_DisableIRQ(XDMAC_IRQn);

	/* Release the DMA channels */
	XDMAD_FreeChannel(pArg->pXdmad, afeDmaRxChannel);
	SCB_InvalidateDCache_by_Addr(pAfedCmd->pRxBuff, pAfedCmd->RxSize);
	/* Release the dataflash semaphore */
	pArg->semaphore++;

	/* Invoke the callback associated with the current command */
	if (pAfedCmd && pAfedCmd->callback)
		pAfedCmd->callback(0, pAfedCmd->pArgument);
}

/**
 * \brief Configure the DMA Channels: 0 RX.
 * Channels are disabled after configure.
 * \param pXdmad Pointer to a AfeDma instance
 * \returns 0 if the dma channel configuration successfully; otherwise returns
 * AFE_ERROR_XXX.
 */
static uint8_t _AfeConfigureDmaChannels(AfeDma *pAfed)
{

	/* Driver initialize */
	XDMAD_Initialize(pAfed->pXdmad, 0);

	XDMAD_FreeChannel(pAfed->pXdmad, afeDmaRxChannel);

	/* Allocate a DMA channel for AFE0/1 RX. */
	afeDmaRxChannel =
		XDMAD_AllocateChannel(pAfed->pXdmad, pAfed->afeId, XDMAD_TRANSFER_MEMORY);

	if (afeDmaRxChannel == XDMAD_ALLOC_FAILED)
		return AFE_ERROR;

	/* Setup callbacks for AFE0/1 RX */
	XDMAD_SetCallback(pAfed->pXdmad, afeDmaRxChannel,
					  (XdmadTransferCallback)Afe_Rx_Cb, pAfed);

	if (XDMAD_PrepareChannel(pAfed->pXdmad, afeDmaRxChannel))
		return AFE_ERROR;

	return AFE_OK;
}

/**
 * \brief Configure the DMA source and destination with Linker List mode.
 * \param pXdmad Pointer to a AfeDma instance
 * \param pCommand Pointer to AfeCmd instance
 * \param AfeCmd Pointer to command
 */

static uint8_t _Afe_configureLinkList(Afec *pAfeHw, void *pXdmad,
									  AfeCmd *pCommand)
{
	uint32_t xdmaCndc, xdmaInt;
	sXdmadCfg xdmadRxCfg;
	uint32_t afeId;

	if ((unsigned int)pAfeHw == (unsigned int)AFEC0) afeId = ID_AFEC0;

	if ((unsigned int)pAfeHw == (unsigned int)AFEC1) afeId = ID_AFEC1;

	/* Setup RX Link List */
	xdmadRxCfg.mbr_ubc = XDMA_UBC_NVIEW_NDV0 |
						 XDMA_UBC_NDE_FETCH_DIS |
						 XDMA_UBC_NDEN_UPDATED |
						 pCommand->RxSize;

	xdmadRxCfg.mbr_da = (uint32_t)pCommand->pRxBuff;
	xdmadRxCfg.mbr_sa = (uint32_t) & (pAfeHw->AFEC_LCDR);
	xdmadRxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |
						 XDMAC_CC_MBSIZE_SINGLE |
						 XDMAC_CC_DSYNC_PER2MEM |
						 XDMAC_CC_CSIZE_CHK_1 |
						 XDMAC_CC_DWIDTH_WORD |
						 XDMAC_CC_SIF_AHB_IF1 |
						 XDMAC_CC_DIF_AHB_IF1 |
						 XDMAC_CC_SAM_FIXED_AM |
						 XDMAC_CC_DAM_INCREMENTED_AM |
						 XDMAC_CC_PERID(
							 XDMAIF_Get_ChannelNumber(afeId, XDMAD_TRANSFER_RX));

	xdmadRxCfg.mbr_bc = 0;
	xdmadRxCfg.mbr_sus = 0;
	xdmadRxCfg.mbr_dus = 0;

	xdmaInt =  (XDMAC_CIE_BIE   |
				XDMAC_CIE_DIE   |
				XDMAC_CIE_FIE   |
				XDMAC_CIE_RBIE  |
				XDMAC_CIE_WBIE  |
				XDMAC_CIE_ROIE);
	xdmaCndc = 0;

	if (XDMAD_ConfigureTransfer(pXdmad, afeDmaRxChannel,
								 &xdmadRxCfg, xdmaCndc, 0, xdmaInt))
		return AFE_ERROR;

	return AFE_OK;
}

/*----------------------------------------------------------------------------
 *        Exported functions
 *----------------------------------------------------------------------------*/


/**
 * \brief Initializes the AfeDma structure and the corresponding AFE & DMA .
 * hardware select value.
 * The driver will uses DMA channel 0 for RX .
 * The DMA channels are freed automatically when no DMA command processing.
 *
 * \param pAfed  Pointer to a AfeDma instance.
 * \param pAfeHw Associated Afe peripheral.
 * \param AfeId  Afe peripheral identifier.
 * \param pDmad  Pointer to a Dmad instance.
 */
uint32_t Afe_ConfigureDma(AfeDma *pAfed ,
						Afec *pAfeHw ,
						uint8_t AfeId,
						sXdmad *pXdmad)
{
	/* Initialize the Afe structure */
	pAfed->pAfeHw = pAfeHw;
	pAfed->afeId  = AfeId;
	pAfed->semaphore = 1;
	pAfed->pCurrentCommand = 0;
	pAfed->pXdmad = pXdmad;
	return 0;
}

/**
 * \brief Starts a AFE transfer. This is a non blocking function. It will
 *  return as soon as the transfer is started.
 *
 * \param pAfed  Pointer to a AfeDma instance.
 * \param pCommand Pointer to the Afe command to execute.
 * \returns 0 if the transfer has been started successfully; otherwise returns
 * AFE_ERROR_LOCK is the driver is in use, or AFE_ERROR if the command is not
 * valid.
 */
uint32_t Afe_SendData(AfeDma *pAfed, AfeCmd *pCommand)
{
	Afec *pAfeHw = pAfed->pAfeHw;

	/* Try to get the dataflash semaphore */
	if (pAfed->semaphore == 0)

		return AFE_ERROR_LOCK;

	pAfed->semaphore--;

	// Initialize the callback
	pAfed->pCurrentCommand = pCommand;

	/* Initialize DMA controller using channel 0 for RX. */
	if (_AfeConfigureDmaChannels(pAfed))
		return AFE_ERROR_LOCK;

	/* Configure and enable interrupt on RC compare */
	NVIC_ClearPendingIRQ(XDMAC_IRQn);
	NVIC_SetPriority(XDMAC_IRQn , 1);
	NVIC_EnableIRQ(XDMAC_IRQn);

	if (_Afe_configureLinkList(pAfeHw, pAfed->pXdmad, pCommand))
		return AFE_ERROR_LOCK;

	AFEC_StartConversion(pAfeHw);

	/* Start DMA 0(RX) */
	if (XDMAD_StartTransfer(pAfed->pXdmad, afeDmaRxChannel))
		return AFE_ERROR_LOCK;

	return AFE_OK;;
}