/* ---------------------------------------------------------------------------- | |
* SAM Software Package License | |
* ---------------------------------------------------------------------------- | |
* Copyright (c) 2013, 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. | |
* ---------------------------------------------------------------------------- | |
*/ | |
/** | |
* \addtogroup qspi_dma_module QSPI xDMA driver | |
* \ingroup peripherals_module | |
* | |
* | |
*/ | |
/** | |
* \file | |
* | |
* Implementation for the SPI Flash with xDMA driver. | |
* | |
*/ | |
/*---------------------------------------------------------------------------- | |
* Headers | |
*----------------------------------------------------------------------------*/ | |
#include "chip.h" | |
/*---------------------------------------------------------------------------- | |
* Definitions | |
*----------------------------------------------------------------------------*/ | |
/** xDMA support */ | |
/** xDMA Link List size for SPI transmission*/ | |
#define DMA_QSPI_LLI 2 | |
/*----------------------------------------------------------------------------- | |
* QSPI DMA Local functions | |
*----------------------------------------------------------------------------*/ | |
/** | |
* \brief SPI xDMA Rx callback | |
* Invoked on SPi DMA reception done. | |
* \param channel DMA channel. | |
* \param pArg Pointer to callback argument - Pointer to Spid instance. | |
*/ | |
static void QSPID_Spi_Cb(uint32_t channel, QspiDma_t* pArg) | |
{ | |
Qspi *pQspiHw = pArg->Qspid.pQspiHw; | |
if (channel != pArg->RxChNum) | |
return; | |
/* Release the semaphore */ | |
ReleaseMutex(pArg->progress); | |
QSPI_EndTransfer(pQspiHw); | |
memory_sync(); | |
} | |
/** | |
* \brief QSPI xDMA Tx callback | |
* Invoked on QSPi DMA Write done. | |
* \param channel DMA channel. | |
* \param pArg Pointer to callback argument - Pointer to Spid instance. | |
*/ | |
static void QSPID_qspiTx_Cb(uint32_t channel, QspiDma_t* pArg) | |
{ | |
Qspi *pQspiHw = pArg->Qspid.pQspiHw; | |
if (channel != pArg->TxChNum) | |
return; | |
/* Release the semaphore */ | |
ReleaseMutex(pArg->progress); | |
QSPI_EndTransfer(pQspiHw); | |
while(!QSPI_GetStatus(pArg->Qspid.pQspiHw, IsEofInst )); | |
memory_sync(); | |
} | |
/** | |
* \brief QSPI xDMA Rx callback | |
* Invoked on SPi DMA reception done. | |
* \param channel DMA channel. | |
* \param pArg Pointer to callback argument - Pointer to Spid instance. | |
*/ | |
static void QSPID_qspiRx_Cb(uint32_t channel, QspiDma_t* pArg) | |
{ | |
Qspi *pQspiHw = pArg->Qspid.pQspiHw; | |
if (channel != pArg->RxChNum) | |
return; | |
/* Release the semaphore */ | |
ReleaseMutex(pArg->progress); | |
QSPI_EndTransfer(pQspiHw); | |
while(!QSPI_GetStatus(pArg->Qspid.pQspiHw, IsEofInst )); | |
memory_sync(); | |
} | |
/** | |
* \brief Configures the DMA for QSPI | |
* | |
* \param pQspidma Pointer to QSPI DMA structure | |
* \param Addr Address to Read or write of QSPI flash memory | |
* \param pBuffer Pointer input/output buffer | |
* \param ReadWrite Read or write memory flag | |
* \returns 0 if the dma multibuffer configuration successfully; otherwise returns | |
* QSPID_ERROR_XXX. | |
*/ | |
static uint8_t QSPID_configureQpsiDma(QspiDma_t *pQspidma, uint32_t Addr, | |
QspiBuffer_t *pBuffer, Access_t const ReadWrite) | |
{ | |
sXdmadCfg xdmadCfg, xdmadRxCfg,xdmadTxCfg; | |
uint8_t chanNum; | |
uint8_t qspi_id = pQspidma->Qspid.qspiId; | |
Qspi *pQspiHw = pQspidma->Qspid.pQspiHw; | |
uint32_t xdmaCndc, xdmaInt, BurstSize, ChannelWidth; | |
/* Setup DMA for QSPI */ | |
if(pQspidma->Qspid.qspiMode == QSPI_MR_SMM_SPI) { | |
// SPI mode | |
/* SPI TX DMA config */ | |
xdmadTxCfg.mbr_sa = (uint32_t)pBuffer->pDataTx; | |
xdmadTxCfg.mbr_da = (uint32_t)&pQspiHw->QSPI_TDR; | |
xdmadTxCfg.mbr_ubc = (pBuffer->TxDataSize); | |
xdmadTxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN | | |
XDMAC_CC_MBSIZE_SINGLE | | |
XDMAC_CC_DSYNC_MEM2PER | | |
XDMAC_CC_CSIZE_CHK_1 | | |
XDMAC_CC_DWIDTH_BYTE| | |
XDMAC_CC_SIF_AHB_IF0 | | |
XDMAC_CC_DIF_AHB_IF1 | | |
XDMAC_CC_SAM_INCREMENTED_AM | | |
XDMAC_CC_DAM_FIXED_AM | | |
XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber | |
( qspi_id, XDMAD_TRANSFER_TX )); | |
xdmadTxCfg.mbr_bc = 0; | |
xdmadTxCfg.mbr_sus = 0; | |
xdmadTxCfg.mbr_dus =0; | |
/* SPI RX DMA config */ | |
xdmadRxCfg.mbr_da = (uint32_t)pBuffer->pDataRx; | |
xdmadRxCfg.mbr_sa = (uint32_t)&pQspiHw->QSPI_RDR; | |
xdmadRxCfg.mbr_ubc = (pBuffer->RxDataSize); | |
xdmadRxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN | | |
XDMAC_CC_MBSIZE_SINGLE | | |
XDMAC_CC_DSYNC_PER2MEM | | |
XDMAC_CC_CSIZE_CHK_1 | | |
XDMAC_CC_DWIDTH_BYTE| | |
XDMAC_CC_SIF_AHB_IF1 | | |
XDMAC_CC_DIF_AHB_IF0 | | |
XDMAC_CC_SAM_FIXED_AM | | |
XDMAC_CC_DAM_INCREMENTED_AM | | |
XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber | |
( qspi_id, XDMAD_TRANSFER_RX )); | |
xdmadRxCfg.mbr_bc = 0; | |
xdmadRxCfg.mbr_sus = 0; | |
xdmadRxCfg.mbr_dus =0; | |
xdmaCndc = 0; | |
/* Put all interrupts on for non LLI list setup of DMA */ | |
xdmaInt = (XDMAC_CIE_BIE | | |
XDMAC_CIE_RBIE | | |
XDMAC_CIE_WBIE | | |
XDMAC_CIE_ROIE); | |
memory_barrier(); | |
if (XDMAD_ConfigureTransfer | |
( pQspidma->pXdmad, pQspidma->RxChNum, &xdmadRxCfg, xdmaCndc, 0, xdmaInt)) | |
return QSPID_ERROR; | |
if (XDMAD_ConfigureTransfer | |
( pQspidma->pXdmad, pQspidma->TxChNum, &xdmadTxCfg, xdmaCndc, 0, xdmaInt)) | |
return QSPID_ERROR; | |
return 0; | |
} else { | |
if(ReadWrite == WriteAccess) { | |
xdmadCfg.mbr_sa = (uint32_t)pBuffer->pDataTx; | |
xdmadCfg.mbr_da = (uint32_t)( QSPIMEM_ADDR | Addr); | |
xdmadCfg.mbr_ubc = (pBuffer->TxDataSize); | |
chanNum = pQspidma->TxChNum; | |
ChannelWidth = XDMAC_CC_DWIDTH_BYTE; | |
BurstSize = XDMAC_CC_MBSIZE_SIXTEEN; | |
} else if(ReadWrite == ReadAccess) { | |
xdmadCfg.mbr_da = (uint32_t)pBuffer->pDataRx; | |
xdmadCfg.mbr_sa = (uint32_t)( QSPIMEM_ADDR | Addr); | |
xdmadCfg.mbr_ubc = ((pBuffer->RxDataSize>>2) + 1); | |
chanNum = pQspidma->RxChNum; | |
ChannelWidth = XDMAC_CC_DWIDTH_WORD; | |
BurstSize = XDMAC_CC_MBSIZE_SIXTEEN; | |
} else { | |
TRACE_ERROR(" QSPI error \n\r"); | |
return 1; | |
} | |
xdmadCfg.mbr_cfg = XDMAC_CC_TYPE_MEM_TRAN | | |
XDMAC_CC_MEMSET_NORMAL_MODE | | |
BurstSize | | |
ChannelWidth | | |
XDMAC_CC_SIF_AHB_IF1 | | |
XDMAC_CC_DIF_AHB_IF1 | | |
XDMAC_CC_SAM_INCREMENTED_AM | | |
XDMAC_CC_DAM_INCREMENTED_AM ; | |
xdmadCfg.mbr_bc = 0; | |
xdmadCfg.mbr_sus = 0; | |
xdmadCfg.mbr_dus =0; | |
xdmaCndc = 0; | |
/* Put all interrupts on for non LLI list setup of DMA */ | |
xdmaInt = (XDMAC_CIE_BIE | | |
XDMAC_CIE_RBIE | | |
XDMAC_CIE_WBIE | | |
XDMAC_CIE_ROIE); | |
memory_barrier(); | |
if (XDMAD_ConfigureTransfer( pQspidma->pXdmad, chanNum, &xdmadCfg, xdmaCndc, 0, xdmaInt)) | |
return QSPID_ERROR; | |
return 0; | |
} | |
} | |
/*---------------------------------------------------------------------------- | |
* Exported functions | |
*----------------------------------------------------------------------------*/ | |
/** | |
* \brief Initializes the pQspidma structure and the corresponding QSPI & DMA . | |
* hardware select value. | |
* | |
* \param pQspidma Pointer to a QspiDma_t instance. | |
* \param Mode Associated SPI peripheral. | |
* \param dwConf QSPI peripheral configuration. | |
* \param pXdmad Pointer to a Xdmad instance. | |
*/ | |
uint32_t QSPID_Configure( QspiDma_t *pQspidma, QspiMode_t Mode, | |
uint32_t dwConf, sXdmad* pXdmad) | |
{ | |
/* Initialize the QSPI structure */ | |
QSPI_ConfigureInterface(&pQspidma->Qspid, Mode, dwConf); | |
pQspidma->Qspid.qspiCommand.Instruction = 0; | |
pQspidma->Qspid.qspiCommand.Option = 0; | |
pQspidma->RxChNum = QSPID_CH_NOT_ENABLED; | |
pQspidma->TxChNum = QSPID_CH_NOT_ENABLED; | |
pQspidma->pXdmad = pXdmad; | |
/* XDMA Driver initialize */ | |
XDMAD_Initialize( pQspidma->pXdmad, 0 ); | |
/* Configure and enable interrupt */ | |
NVIC_ClearPendingIRQ(XDMAC_IRQn); | |
NVIC_SetPriority( XDMAC_IRQn ,1); | |
NVIC_EnableIRQ(XDMAC_IRQn); | |
return QSPI_SUCCESS; | |
} | |
/** | |
* \brief Enables a QSPI Rx channel. This function will allocate a dma Rx | |
* channel for QSPI | |
* | |
* \param pQspidma Pointer to a Spid instance. | |
* \returns 0 if the transfer has been started successfully; otherwise returns | |
* QSPID_ERROR_LOCK is the driver is in use, or QSPID_ERROR if the command is not | |
* valid. | |
*/ | |
uint32_t QSPID_EnableQspiRxChannel(QspiDma_t *pQspidma) | |
{ | |
static uint16_t DmaChannel; | |
/* Try to get the semaphore */ | |
if (pQspidma->RxChNum != QSPID_CH_NOT_ENABLED) { | |
return QSPID_ERROR_LOCK; | |
} | |
/* Allocate a DMA channel */ | |
DmaChannel = XDMAD_AllocateChannel( | |
pQspidma->pXdmad, XDMAD_TRANSFER_MEMORY, XDMAD_TRANSFER_MEMORY); | |
if ( DmaChannel == XDMAD_ALLOC_FAILED ){ | |
return QSPID_ERROR; | |
} | |
pQspidma->RxChNum = DmaChannel; | |
/* Setup callbacks*/ | |
XDMAD_SetCallback(pQspidma->pXdmad, pQspidma->RxChNum, | |
(XdmadTransferCallback)QSPID_qspiRx_Cb, pQspidma); | |
if (XDMAD_PrepareChannel( pQspidma->pXdmad, pQspidma->RxChNum )) | |
return QSPID_ERROR; | |
return 0; | |
} | |
/** | |
* \brief Enables a QSPI Tx channel. This function will allocate a dma Tx | |
* channel for QSPI | |
* | |
* \param pQspidma Pointer to a Spid instance. | |
* \returns 0 if the transfer has been started successfully; otherwise returns | |
* QSPID_ERROR_LOCK is the driver is in use, or QSPID_ERROR if the command is | |
* not valid. | |
*/ | |
uint32_t QSPID_EnableQspiTxChannel(QspiDma_t *pQspidma) | |
{ | |
static uint16_t DmaChannel; | |
/* Try to get the semaphore */ | |
if (pQspidma->TxChNum != QSPID_CH_NOT_ENABLED) { | |
return QSPID_ERROR_LOCK; | |
} | |
/* Allocate a DMA channel */ | |
DmaChannel = XDMAD_AllocateChannel( pQspidma->pXdmad, | |
XDMAD_TRANSFER_MEMORY, XDMAD_TRANSFER_MEMORY); | |
if ( DmaChannel == XDMAD_ALLOC_FAILED ) { | |
return QSPID_ERROR; | |
} | |
pQspidma->TxChNum = DmaChannel; | |
/* Setup callbacks */ | |
XDMAD_SetCallback(pQspidma->pXdmad, pQspidma->TxChNum, | |
(XdmadTransferCallback)QSPID_qspiTx_Cb, pQspidma); | |
if (XDMAD_PrepareChannel( pQspidma->pXdmad, pQspidma->TxChNum )) | |
return QSPID_ERROR; | |
return 0; | |
} | |
/** | |
* \brief Enables a QSPI SPI Rx channel. This function will allocate a dma | |
* Rx channel for QSPI SPI mode | |
* | |
* \param pQspidma Pointer to a Spid instance. | |
* \returns 0 if the transfer has been started successfully; otherwise returns | |
* QSPID_ERROR_LOCK is the driver is in use, or QSPID_ERROR if the command is | |
* not valid. | |
*/ | |
uint32_t QSPID_EnableSpiChannel(QspiDma_t *pQspidma) | |
{ | |
static uint16_t DmaChannel; | |
/* Try to get the semaphore */ | |
if (pQspidma->RxChNum != QSPID_CH_NOT_ENABLED) { | |
return QSPID_ERROR_LOCK; | |
} | |
/* Try to get the semaphore */ | |
if (pQspidma->TxChNum != QSPID_CH_NOT_ENABLED) { | |
return QSPID_ERROR_LOCK; | |
} | |
/* Allocate a DMA channel */ | |
DmaChannel = XDMAD_AllocateChannel | |
( pQspidma->pXdmad, pQspidma->Qspid.qspiId, XDMAD_TRANSFER_MEMORY); | |
if ( DmaChannel == XDMAD_ALLOC_FAILED ) { | |
return QSPID_ERROR; | |
} | |
pQspidma->RxChNum = DmaChannel; | |
/* Allocate a DMA channel */ | |
DmaChannel = XDMAD_AllocateChannel( pQspidma->pXdmad, | |
XDMAD_TRANSFER_MEMORY, pQspidma->Qspid.qspiId); | |
if ( DmaChannel == XDMAD_ALLOC_FAILED ) { | |
return QSPID_ERROR; | |
} | |
pQspidma->TxChNum = DmaChannel; | |
/* Setup callbacks*/ | |
XDMAD_SetCallback(pQspidma->pXdmad, pQspidma->RxChNum, | |
(XdmadTransferCallback)QSPID_Spi_Cb, pQspidma); | |
if (XDMAD_PrepareChannel( pQspidma->pXdmad, pQspidma->RxChNum )) | |
return QSPID_ERROR; | |
/* Setup callbacks for SPI0/1 TX (ignored) */ | |
XDMAD_SetCallback(pQspidma->pXdmad, pQspidma->TxChNum, NULL, NULL); | |
if ( XDMAD_PrepareChannel( pQspidma->pXdmad, pQspidma->TxChNum )) | |
return QSPID_ERROR; | |
return 0; | |
} | |
/** | |
* \brief Disables a QSPI Rx channel. This function will de-allocate previous | |
* allocated dma Rx channel for QSPI | |
* | |
* \param pQspidma Pointer to a Spid instance. | |
* \returns 0 if the transfer has been started successfully; otherwise returns | |
* QSPID_ERROR_LOCK is the driver is in use, or QSPID_ERROR if the command is | |
* not valid. | |
*/ | |
uint32_t QSPID_DisableQspiRxChannel(QspiDma_t *pQspidma) | |
{ | |
XDMAC_SoftwareFlushReq(pQspidma->pXdmad->pXdmacs, pQspidma->RxChNum); | |
XDMAD_StopTransfer(pQspidma->pXdmad, pQspidma->RxChNum); | |
XDMAD_SetCallback(pQspidma->pXdmad, pQspidma->RxChNum, NULL, NULL); | |
/* Free allocated DMA channel for QSPI RX. */ | |
XDMAD_FreeChannel( pQspidma->pXdmad, pQspidma->RxChNum); | |
pQspidma->RxChNum = QSPID_CH_NOT_ENABLED; | |
return 0; | |
} | |
/** | |
* \brief Disables a QSPI Tx channel. This function will de-allocate previous | |
* allocated dma Tx channel for QSPI | |
* | |
* \param pQspidma Pointer to a Spid instance. | |
* \returns 0 if the transfer has been started successfully; otherwise returns | |
* QSPID_ERROR_LOCK is the driver is in use, or QSPID_ERROR if the command is | |
* not valid. | |
*/ | |
uint32_t QSPID_DisableQspiTxChannel(QspiDma_t *pQspidma) | |
{ | |
XDMAC_SoftwareFlushReq(pQspidma->pXdmad->pXdmacs, pQspidma->TxChNum); | |
XDMAD_StopTransfer(pQspidma->pXdmad, pQspidma->TxChNum); | |
XDMAD_SetCallback(pQspidma->pXdmad, pQspidma->TxChNum, NULL, NULL); | |
/* Free allocated DMA channel for QSPI TX. */ | |
XDMAD_FreeChannel( pQspidma->pXdmad, pQspidma->TxChNum); | |
pQspidma->TxChNum = QSPID_CH_NOT_ENABLED; | |
return 0; | |
} | |
/** | |
* \brief Disables a QSPI SPI Rx and Tx channels. This function will | |
* de-allocate privious allocated dma Rx, Txchannel for QSPI in SPI mode | |
* | |
* \param pQspidma Pointer to a Spid instance. | |
* \returns 0 if the transfer has been started successfully; otherwise returns | |
* QSPID_ERROR_LOCK is the driver is in use, or QSPID_ERROR if the command is | |
* not valid. | |
*/ | |
uint32_t QSPID_DisableSpiChannel(QspiDma_t *pQspidma) | |
{ | |
XDMAC_SoftwareFlushReq(pQspidma->pXdmad->pXdmacs, pQspidma->RxChNum); | |
//XDMAC_SoftwareFlushReq(pQspidma->pXdmad->pXdmacs, pQspidma->TxChNum); | |
XDMAD_StopTransfer(pQspidma->pXdmad, pQspidma->RxChNum); | |
XDMAD_StopTransfer(pQspidma->pXdmad, pQspidma->TxChNum); | |
XDMAD_SetCallback(pQspidma->pXdmad, pQspidma->RxChNum, NULL, NULL); | |
/* Free allocated DMA channel for QSPI RX. */ | |
XDMAD_FreeChannel( pQspidma->pXdmad, pQspidma->RxChNum); | |
XDMAD_FreeChannel( pQspidma->pXdmad, pQspidma->TxChNum); | |
pQspidma->RxChNum = QSPID_CH_NOT_ENABLED; | |
pQspidma->TxChNum = QSPID_CH_NOT_ENABLED; | |
return 0; | |
} | |
/** | |
* \brief Starts a QSPI read or write operation. | |
* | |
* \param pQspidma Pointer to a Qspid instance. | |
* \param ReadWrite Defines the memory access type | |
* \returns 0 if the transfer has been started successfully; otherwise returns | |
* QSPID_ERROR_LOCK is the driver is in use, or QSPID_ERROR if the command is | |
* not valid. | |
*/ | |
uint32_t QSPID_ReadWriteQSPI(QspiDma_t *pQspidma, Access_t const ReadWrite) | |
{ | |
QspiBuffer_t *pBuffer = &pQspidma->Qspid.qspiBuffer; | |
uint8_t chanNum; | |
uint32_t semTimer = 0x7FF; | |
//assert(pBuffer->pDataTx); | |
if (pQspidma->progress) { | |
return QSPID_ERROR_LOCK; | |
} | |
LockMutex(pQspidma->progress, semTimer); | |
if(ReadWrite == WriteAccess) { | |
chanNum = pQspidma->TxChNum; | |
} else if(ReadWrite == ReadAccess) { | |
chanNum = pQspidma->RxChNum; | |
} else { | |
TRACE_ERROR("%s QSPI Access Error\n\r", __FUNCTION__); | |
} | |
if (QSPID_configureQpsiDma | |
( pQspidma, pQspidma->Qspid.pQspiFrame->Addr, pBuffer, ReadWrite) ) | |
return QSPID_ERROR_LOCK; | |
SCB_CleanInvalidateDCache(); | |
/* Start DMA 0(RX) && 1(TX) */ | |
if (XDMAD_StartTransfer( pQspidma->pXdmad,chanNum )) | |
return QSPID_ERROR_LOCK; | |
return 0; | |
} | |
/** | |
* \brief Starts a SPI master transfer. This is a non blocking function. It will | |
* return as soon as the transfer is started. | |
* | |
* \param pSpid Pointer to a Spid instance. | |
* \param pCommand Pointer to the SPI command to execute. | |
* \returns 0 if the transfer has been started successfully; otherwise returns | |
* SPID_ERROR_LOCK is the driver is in use, or SPID_ERROR if the command is not | |
* valid. | |
*/ | |
uint32_t QSPID_ReadWriteSPI(QspiDma_t *pQspidma, Access_t const ReadWrite) | |
{ | |
QspiBuffer_t *pBuffer = &pQspidma->Qspid.qspiBuffer; | |
uint32_t semTimer = 0x7FF; | |
assert(pBuffer->pDataRx); | |
assert(pBuffer->pDataTx); | |
/* Try to get the dataflash semaphore */ | |
if (pQspidma->progress) { | |
return QSPID_ERROR_LOCK; | |
} | |
LockMutex(pQspidma->progress, semTimer); | |
if (QSPID_configureQpsiDma | |
( pQspidma, pQspidma->Qspid.pQspiFrame->Addr, pBuffer, ReadWrite) ) | |
return QSPID_ERROR_LOCK; | |
SCB_CleanInvalidateDCache(); | |
/* Start DMA 0(RX) && 1(TX) */ | |
if (XDMAD_StartTransfer( pQspidma->pXdmad, pQspidma->RxChNum )) | |
return QSPID_ERROR_LOCK; | |
if (XDMAD_StartTransfer( pQspidma->pXdmad, pQspidma->TxChNum )) | |
return QSPID_ERROR_LOCK; | |
return 0; | |
} | |
/** | |
* \brief Check if the QSPI driver is busy. | |
* | |
* \param pSpid Pointer to a Spid instance. | |
* \returns 1 if the SPI driver is currently busy executing a command; otherwise | |
*/ | |
uint32_t QSPID_IsBusy(volatile uint8_t *QspiSemaphore) | |
{ | |
if( Is_LockFree(QspiSemaphore) ) { | |
return 1; | |
} else { | |
return 0; | |
} | |
} |