diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-01-12 15:34:31 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-01-19 08:36:20 +0100 |
commit | e1eeb883d82ce218c2a9c754795cb3c86ac0f36d (patch) | |
tree | 646a7c22772297094bb77303953eda0e71679dd9 /c/src/lib/libbsp/arm/atsam/libraries/libchip/source/qspi_dma.c | |
parent | bsps/arm: Copy vector table only if necessary (diff) | |
download | rtems-e1eeb883d82ce218c2a9c754795cb3c86ac0f36d.tar.bz2 |
bsp/atsam: Import SAM Software Package
Import selected files of the "SAM V71 / V70 / E70 / S70 Software
Package" obtained from the "SAMV71-XULT GNU Software Package 1.5".
Converted files via dos2unix before import.
Update #2529.
Diffstat (limited to 'c/src/lib/libbsp/arm/atsam/libraries/libchip/source/qspi_dma.c')
-rw-r--r-- | c/src/lib/libbsp/arm/atsam/libraries/libchip/source/qspi_dma.c | 623 |
1 files changed, 623 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/arm/atsam/libraries/libchip/source/qspi_dma.c b/c/src/lib/libbsp/arm/atsam/libraries/libchip/source/qspi_dma.c new file mode 100644 index 0000000000..b465ac8bd2 --- /dev/null +++ b/c/src/lib/libbsp/arm/atsam/libraries/libchip/source/qspi_dma.c @@ -0,0 +1,623 @@ +/* ---------------------------------------------------------------------------- */ +/* 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 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); + SCB_InvalidateDCache_by_Addr((uint32_t *)pArg->Qspid.qspiBuffer.pDataRx, + pArg->Qspid.qspiBuffer.RxDataSize); + 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)); + + SCB_InvalidateDCache_by_Addr((uint32_t *)pArg->Qspid.qspiBuffer.pDataRx, + pArg->Qspid.qspiBuffer.RxDataSize); + 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)); + 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 (QSPID_configureQpsiDma + (pQspidma, pQspidma->Qspid.pQspiFrame->Addr, pBuffer, ReadWrite)) + return QSPID_ERROR_LOCK; + + if (ReadWrite == WriteAccess) { + chanNum = pQspidma->TxChNum; + SCB_CleanDCache_by_Addr((uint32_t *)pBuffer->pDataTx, pBuffer->TxDataSize); + } else if (ReadWrite == ReadAccess) + chanNum = pQspidma->RxChNum; + else + TRACE_ERROR("%s QSPI Access Error\n\r", __FUNCTION__); + + /* 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_CleanDCache_by_Addr((uint32_t *)pBuffer->pDataTx, pBuffer->TxDataSize); + + /* 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; +} |