/* ---------------------------------------------------------------------------- */
/* 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_module Working with QSPI
* \ingroup peripherals_module
* The QSPI driver provides the interface to configure and use the QSPI
* peripheral.
*
* The Serial Peripheral Interface (QSPI) circuit is a synchronous serial
* data link that provides communication with external devices in Master
* or Slave Mode.
*
* To use the QSPI, the user has to follow these few steps:
* -# Enable the QSPI pins required by the application (see pio.h).
* -# Configure the QSPI using the \ref QSPI_Configure(). This enables the
* peripheral clock. The mode register is loaded with the given value.
* -# Configure all the necessary chip selects with \ref QSPI_ConfigureNPCS().
* -# Enable the QSPI by calling \ref QSPI_Enable().
* -# Send/receive data using \ref QSPI_Write() and \ref QSPI_Read(). Note that
* \ref QSPI_Read()
* must be called after \ref QSPI_Write() to retrieve the last value read.
* -# Send/receive data using the PDC with the \ref QSPI_WriteBuffer() and
* \ref QSPI_ReadBuffer() functions.
* -# Disable the QSPI by calling \ref QSPI_Disable().
*
* For more accurate information, please look at the QSPI section of the
* Datasheet.
*
* Related files :\n
* \ref qspi.c\n
* \ref qspi.h.\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of Serial Peripheral Interface (QSPI) controller.
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "stdlib.h"
#include "string.h"
#include <stdint.h>
#define SCRAMBLE_KEY 0x0BADDEAD
/*----------------------------------------------------------------------------
* Internal functions
*----------------------------------------------------------------------------*/
/**
* \brief Configure QSPI/SPI mode
*
* \param pQspi Pointer to a Qspi instance.
*/
__STATIC_INLINE void QSPI_ConfigureMode(Qspi *pQspi, uint8_t dMode)
{
assert(pQspi);
pQspi->QSPI_MR = dMode;
}
/**
* \brief Configure mode register of QSPI
*
* \param pQspi Pointer to a Qspi instance.
*/
__STATIC_INLINE void QSPI_Configure(Qspi *pQspi, uint32_t dwConfiguration)
{
assert(pQspi);
pQspi->QSPI_MR |= dwConfiguration;
}
/**
* \brief Configures a instruction address for QSPI in QSPI mode
*
* \param pQspi Pointer to a Qspi instance.
* \param dwAddr Instruction Address
*/
__STATIC_INLINE void QSPI_SetInstAddr(Qspi *pQspi, uint32_t dwAddr)
{
assert(pQspi);
pQspi->QSPI_IAR = dwAddr;
}
/**
* \brief Configures instruction register with a given command for QSPI
*
* \param pQspi Pointer to a Qspi instance.
* \param dwInst Instruction Code
* \param dwOpt Instruction Code option
*/
__STATIC_INLINE void QSPI_SetInst(Qspi *pQspi, uint8_t dwInst, uint8_t dwOpt)
{
assert(pQspi);
pQspi->QSPI_ICR = (dwInst | QSPI_ICR_OPT(dwOpt));
}
/**
* \brief Configures instruction frame register of QSPI
*
* \param pQspi Pointer to a Qspi instance.
* \param pInstFrame Instruction Frame configuration
*/
__STATIC_INLINE void QSPI_SetInstFrame(Qspi *pQspi,
QspiInstFrame_t *pInstFrame)
{
assert(pQspi);
pQspi->QSPI_IFR = pInstFrame->InstFrame.val;
}
/**
* \brief Reads the Instruction frame of QSPI
*
* \param pQspi Pointer to an Qspi instance.
*/
__STATIC_INLINE uint32_t QSPI_GetInstFrame(Qspi *pQspi)
{
assert(pQspi);
return pQspi->QSPI_IFR;
}
/**
* \brief Read QSPI RDR register for SPI mode
*
* \param pQspi Pointer to an Qspi instance.
*/
__STATIC_INLINE uint16_t QSPI_ReadSPI(Qspi *pQspi)
{
assert(pQspi);
while (!QSPI_GetStatus(pQspi, IsReceived));
return pQspi->QSPI_RDR;
}
/**
* \brief Write to QSPI Tx register in SPI mode
*
* \param pQspi Pointer to an Qspi instance.
* \param wData Data to transmit
*/
__STATIC_INLINE void QSPI_WriteSPI(Qspi *pQspi, uint16_t wData)
{
assert(pQspi);
/* Send data */
while (!QSPI_GetStatus(pQspi, IsTxEmpty));
pQspi->QSPI_TDR = wData;
while (!QSPI_GetStatus(pQspi, IsTxSent));
}
/**
* \brief Configures QSPI scrambling with a given Key
*
* \param pQspi Pointer to an Qspi instance.
* \param wKey Key for scramble/unscramble
* \param EnableFlag Enable/disable scramble
* \param Random Add random value with given key
*/
__STATIC_INLINE void QSPI_ScrambleData(Qspi *pQspi, uint32_t wKey,
uint8_t EnableFlag, uint8_t Random)
{
assert(pQspi);
assert(EnableFlag < 2);
assert(Random < 2);
if (EnableFlag)
pQspi->QSPI_SKR = wKey;
pQspi->QSPI_SMR = (EnableFlag | (Random << 1));
}
static void do_copy(uint8_t *dst, const uint8_t *src, size_t n, bool aligned)
{
if (aligned) {
while (n > 3) {
*(uint32_t *)dst = *(uint32_t *)src;
dst += 4;
src += 4;
n -= 4;
}
}
while (n > 0) {
*dst = *src;
++dst;
++src;
--n;
}
}
static void copy_to_io(void *dst, const void *src, size_t n)
{
do_copy(dst, src, n, ((uintptr_t)dst) % 4 == 0);
}
static void copy_from_io(void *dst, const void *src, size_t n)
{
do_copy(dst, src, n, ((uintptr_t)src) % 4 == 0);
}
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Enables a QSPI peripheral.
*
* \param pQspi Pointer to a Qspi instance.
*/
void QSPI_Enable(Qspi *pQspi)
{
assert(pQspi);
pQspi->QSPI_CR = QSPI_CR_QSPIEN;
while (!(pQspi->QSPI_SR & QSPI_SR_QSPIENS));
}
/**
* \brief Disables a QSPI peripheral.
*
* \param pQspi Pointer to a Qspi instance.
*/
void QSPI_Disable(Qspi *pQspi)
{
assert(pQspi);
pQspi->QSPI_CR = QSPI_CR_QSPIDIS;
while (pQspi->QSPI_SR & QSPI_SR_QSPIENS);
}
/**
* \brief Resets a QSPI peripheral.
*
* \param pQspi Pointer to a Qspi instance.
*/
void QSPI_SwReset(Qspi *pQspi)
{
assert(pQspi);
pQspi->QSPI_CR = QSPI_CR_SWRST;
}
/**
* \brief Enables one or more interrupt sources of a QSPI peripheral.
*
* \param pQspi Pointer to a Qspi instance.
* \param sources Bitwise OR of selected interrupt sources.
*/
QspidStatus_t QSPI_EnableIt(Qspi *pQspi, uint32_t dwSources)
{
assert(pQspi);
pQspi->QSPI_IER = dwSources;
return QSPI_SUCCESS;
}
/**
* \brief Disables one or more interrupt sources of a QSPI peripheral.
*
* \param pQspi Pointer to a Qspi instance.
* \param sources Bitwise OR of selected interrupt sources.
*/
QspidStatus_t QSPI_DisableIt(Qspi *pQspi, uint32_t dwSources)
{
assert(pQspi);
pQspi->QSPI_IDR = dwSources;
return QSPI_SUCCESS;
}
/**
* \brief Return the interrupt mask register.
*
* \return Qspi interrupt mask register.
*/
uint32_t QSPI_GetItMask(Qspi *pQspi)
{
assert(pQspi);
return (pQspi->QSPI_IMR);
}
/**
* \brief Returns enabled interrupt status
*
* \return Qspi interrupt mask register.
*/
uint32_t QSPI_GetEnabledItStatus(Qspi *pQspi)
{
assert(pQspi);
return (pQspi->QSPI_IMR & QSPI_GetStatus(pQspi, (QspiStatus_t)0xFFFFFFFF));
}
/**
* \brief Get the current status register of the given QSPI peripheral.
* \note This resets the internal value of the status register, so further
* read may yield different values.
* \param pQspi Pointer to a Qspi instance.
* \param rStatus Compare status with given status bit
* \return QSPI status register.
*/
uint32_t QSPI_GetStatus(Qspi *pQspi, const QspiStatus_t rStatus)
{
assert(pQspi);
return (pQspi->QSPI_SR & rStatus);
}
/**
* \brief Configures peripheral clock of a QSPI/SPI peripheral.
*
* \param pQspi Pointer to an Qspi instance.
* \param dwConfiguration Desired clock configuration.
*/
void QSPI_ConfigureClock(Qspi *pQspi, QspiClockMode_t ClockMode,
uint32_t dwClockCfg)
{
assert(pQspi);
pQspi->QSPI_SCR = ClockMode;
pQspi->QSPI_SCR |= dwClockCfg;
}
/**
* \brief Configures QSPI/SPI
*
* \param pQspi Pointer to an Qspi instance.
* \param Mode Mode for QSPI or SPI
* \param dwConfiguration Config of SPI or QSPI mode
*/
QspidStatus_t QSPI_ConfigureInterface(Qspid_t *pQspid, QspiMode_t Mode,
uint32_t dwConfiguration)
{
pQspid->pQspiHw = QSPI;
pQspid->qspiId = ID_QSPI;
QSPI_Disable(pQspid->pQspiHw);
QSPI_SwReset(pQspid->pQspiHw);
QSPI_ConfigureMode(pQspid->pQspiHw, Mode);
QSPI_Configure(pQspid->pQspiHw, dwConfiguration);
return QSPI_SUCCESS;
}
/**
* \brief Ends ongoing transfer by releasing CS of QSPI peripheral.
*
* \param pQspi Pointer to an Qspi instance.
*/
QspidStatus_t QSPI_EndTransfer(Qspi *pQspi)
{
assert(pQspi);
while (!QSPI_GetStatus(pQspi, IsTxEmpty));
pQspi->QSPI_CR = QSPI_CR_LASTXFER;
return QSPI_SUCCESS;
}
/*----------------------------------------------------------------------------
* SPI functions
*----------------------------------------------------------------------------*/
/**
* \brief Reads the data received by a SPI peripheral. This
* method must be called after a successful SPI_Write call.
*
* \param pQspid Pointer to a Qspi instance.
* \param pData Buffer to put read value
* \return Qspi status
*/
QspidStatus_t QSPI_SingleReadSPI(Qspid_t *pQspid, uint16_t *const pData)
{
QspidStatus_t Status = QSPI_UNKNOWN_ERROR;
Qspi *pQspi = pQspid->pQspiHw;
uint32_t NumOfAttempt = 0;
uint16_t Dummy = 0xFF;
for (;;) {
if (QSPI_GetStatus(pQspi, IsReceived)) {
*pData = QSPI_ReadSPI(pQspi);
QSPI_WriteSPI(pQspi, Dummy);
*pData = QSPI_ReadSPI(pQspi);
NumOfAttempt = 0;
Status = QSPI_SUCCESS;
} else {
if (NumOfAttempt > 0xFFFF) {
Status = QSPI_READ_ERROR;
TRACE_ERROR(" SPI Read Error \n\r");
break;
} else {
Status = QSPI_READ_ERROR;
NumOfAttempt++;
}
}
}
return Status;
}
/**
* \brief Reads multiple data received by a SPI peripheral. This
* method must be called after a successful SPI_Write call.
*
* \param pQspid Pointer to a Qspi instance.
* \param pData Pointer to read buffer
* \param NumOfBytes Num of bytes to read
*
* \return Qspi status
*/
QspidStatus_t QSPI_MultiReadSPI(Qspid_t *pQspid, uint16_t *const pData,
uint32_t NumOfBytes)
{
QspidStatus_t Status = QSPI_UNKNOWN_ERROR;
Qspi *pQspi = pQspid->pQspiHw;
uint32_t NumOfBytesRead = 0;
uint32_t NumOfAttempt = 0;
uint8_t *pwData = (uint8_t *)pData;
uint16_t Dummy = 0xFF;
/* Dummy read and write to discard first bytes recvd and start
receiving new data*/
Dummy = QSPI_ReadSPI(pQspi);
QSPI_WriteSPI(pQspi, Dummy);
for (; NumOfBytesRead < NumOfBytes;) {
if (QSPI_GetStatus(pQspi, IsTxSent)) {
*pwData = QSPI_ReadSPI(pQspi);
if (pQspi->QSPI_MR & QSPI_MR_NBBITS_Msk)
pwData += sizeof(uint16_t);
else
pwData += sizeof(uint8_t);
NumOfBytesRead++;
NumOfAttempt = 0;
Status = QSPI_SUCCESS;
QSPI_WriteSPI(pQspi, Dummy);
} else {
if (NumOfAttempt > 0xFFFF) {
Status = QSPI_READ_ERROR;
TRACE_ERROR(" SPI MultiRead Error \n\r");
break;
} else {
Status = QSPI_READ_ERROR;
NumOfAttempt++;
}
}
}
return Status;
}
/**
* \brief Sends a single data through a SPI peripheral.
*
* \param pQspid Pointer to a Qspi instance.
* \param pData Pointer to Tx data
*
* \return Qspi status
*/
QspidStatus_t QSPI_SingleWriteSPI(Qspid_t *pQspid, uint16_t const *pData)
{
QspidStatus_t Status = QSPI_UNKNOWN_ERROR;
Qspi *pQspi = pQspid->pQspiHw;
uint32_t NumOfAttempt = 0;
for (;;) {
if (QSPI_GetStatus(pQspi, IsTxSent)) {
QSPI_WriteSPI(pQspi, *pData);
NumOfAttempt = 0;
Status = QSPI_SUCCESS;
break;
} else {
Status = QSPI_BUSY_SENDING;
NumOfAttempt++;
if (NumOfAttempt > 0xFFFF) {
Status = QSPI_WRITE_ERROR;
TRACE_ERROR(" SPI Write Error \n\r");
break;
}
}
}
return Status;
}
/**
* \brief Sends multiple data through a SPI peripheral.
*
* \param pQspid Pointer to a Qspi instance.
* \param pData Pointer to a Tx buffer
* \param NumOfBytes Num of data to send.
*/
QspidStatus_t QSPI_MultiWriteSPI(Qspid_t *pQspid, uint16_t const *pData,
uint32_t NumOfBytes)
{
QspidStatus_t Status = QSPI_UNKNOWN_ERROR;
Qspi *pQspi = pQspid->pQspiHw;
uint32_t NumOfBytesWrite = 0;
uint32_t NumOfAttempt = 0;
uint8_t *pwData = (uint8_t *)pData;
uint8_t Addr_Inc = 0;
if (pQspi->QSPI_MR & QSPI_MR_NBBITS_Msk)
Addr_Inc = sizeof(uint16_t);
else
Addr_Inc = sizeof(uint8_t);
for (; NumOfBytesWrite < NumOfBytes;) {
if (QSPI_GetStatus(pQspi, IsTxEmpty)) {
QSPI_WriteSPI(pQspi, (uint16_t)*pwData);
pwData += Addr_Inc;
NumOfBytesWrite++;
NumOfAttempt = 0;
Status = QSPI_SUCCESS;
} else {
Status = QSPI_BUSY_SENDING;
NumOfAttempt++;
if (NumOfAttempt > 0xFFFF) {
Status = QSPI_WRITE_ERROR;
TRACE_ERROR(" SPI Multi Write Error \n\r");
break;
}
}
}
return Status;
}
/*----------------------------------------------------------------------------
* QSPI functions
*----------------------------------------------------------------------------*/
/**
* \brief Send an instruction over QSPI (oly a flash command no data)
*
* \param pQspi Pointer to an Qspi instance.
* \param KeepCfg To keep Instruction fram value or restes to zero
*
* \return Returns 1 if At least one instruction end has been detected since
* the last read of QSPI_SR.; otherwise
* returns 0.
*/
QspidStatus_t QSPI_SendCommand(Qspid_t *pQspid, uint8_t const KeepCfg)
{
QspiInstFrame_t *const pFrame = pQspid->pQspiFrame;
QspiMemCmd_t pCommand = pQspid->qspiCommand;
QspidStatus_t Status = QSPI_UNKNOWN_ERROR;
uint32_t timeout = 15000;
if (pFrame->InstFrame.bm.bAddrEn)
QSPI_SetInstAddr(pQspid->pQspiHw, pFrame->Addr);
QSPI_SetInst(pQspid->pQspiHw, (pCommand.Instruction & 0xFF),
((pCommand.Option >> QSPI_ICR_OPT_Pos) & 0xFF));
QSPI_SetInstFrame(pQspid->pQspiHw, pFrame);
memory_sync();
/*
* FIXME: Timeout has been introduced due to a problem that was detected
* when QSPI_SR_INSTRE was not detected and the function is stuck in an
* endless loop. This is still an open issue.
* peripheral clock: 50Mhz -> 20 ns period time.
* timeout: set to 15000 loop cycles => 300000 ns.
* with loop instructions, the delay increases to 1ms altogether.
*/
while (!(pQspid->pQspiHw->QSPI_SR & QSPI_SR_INSTRE) && timeout > 0) {
--timeout;
}
if (timeout == 0) {
Status = QSPI_WRITE_ERROR;
}
// poll CR reg to know status if instruction has end
if (!KeepCfg)
pFrame->InstFrame.val = 0;
return Status;
}
/**
* \brief Send instruction over QSPI with data
*
* \param pQspi Pointer to an Qspi instance.
* \param KeepCfg To keep Instruction fram value or restes to zero
*
* \return Returns 1 if At least one instruction end has been detected
* since the last read of QSPI_SR.; otherwise returns 0.
*/
QspidStatus_t QSPI_SendCommandWithData(Qspid_t *pQspid, uint8_t const KeepCfg)
{
QspiInstFrame_t *const pFrame = pQspid->pQspiFrame;
QspiMemCmd_t pCommand = pQspid->qspiCommand;
QspiBuffer_t pBuffer = pQspid->qspiBuffer;
uint32_t *pQspiBuffer = (uint32_t *)QSPIMEM_ADDR;
QspidStatus_t Status = QSPI_UNKNOWN_ERROR;
//assert(pBuffer.pDataRx);
assert(pBuffer.pDataTx);
QSPI_SetInst(pQspid->pQspiHw, (pCommand.Instruction & 0xFF),
(pCommand.Option & 0xFF));
QSPI_SetInstFrame(pQspid->pQspiHw, pFrame);
QSPI_GetInstFrame(pQspid->pQspiHw);
// to synchronize system bus accesses
if (!KeepCfg)
pFrame->InstFrame.val = 0;
memcpy(pQspiBuffer , pBuffer.pDataTx , pBuffer.TxDataSize);
memory_sync();
QSPI_EndTransfer(pQspid->pQspiHw);
// End transmission after all data has been sent
while (!(pQspid->pQspiHw->QSPI_SR & QSPI_SR_INSTRE));
// poll CR reg to know status if instruction has end
return Status;
}
/**
* \brief Send instruction over QSPI to read data
*
* \param pQspi Pointer to an Qspi instance.
* \param KeepCfg To keep Instruction from value or resets to zero
*
* \return Returns 1 if At least one instruction end has been detected
* since the last read of QSPI_SR.; otherwise returns 0.
*/
QspidStatus_t QSPI_ReadCommand(Qspid_t *pQspid, uint8_t const KeepCfg)
{
QspiInstFrame_t *const pFrame = pQspid->pQspiFrame;
QspiMemCmd_t pCommand = pQspid->qspiCommand;
QspiBuffer_t pBuffer = pQspid->qspiBuffer;
uint32_t *pQspiBuffer = (uint32_t *)QSPIMEM_ADDR;
QspidStatus_t Status = QSPI_UNKNOWN_ERROR;
assert(pBuffer.pDataRx);
QSPI_SetInst(pQspid->pQspiHw, (pCommand.Instruction & 0xFF),
(pCommand.Option & 0xFF));
QSPI_SetInstFrame(pQspid->pQspiHw, pFrame);
QSPI_GetInstFrame(pQspid->pQspiHw);
// to synchronize system bus accesses
if (!KeepCfg)
pFrame->InstFrame.val = 0;
memcpy(pBuffer.pDataRx , pQspiBuffer, pBuffer.RxDataSize);
memory_sync();
QSPI_EndTransfer(pQspid->pQspiHw);
// End transmission after all data has been sent
while (!(pQspid->pQspiHw->QSPI_SR & QSPI_SR_INSTRE));
// poll CR reg to know status if instruction has end
return Status;
}
/**
* \brief Sends an instruction over QSPI and configures other related address
* like Addr , Frame and synchronise bus access before data read or write
*
* \param pQspi Pointer to an Qspi instance.
* \param KeepCfg To keep Instruction from value or resets to zero
* \param ScrambleFlag Enable or disable scramble on QSPI
*
* \return Returns 1 if At least one instruction end has been detected since
* the last read of QSPI_SR.; otherwise returns 0.
*/
QspidStatus_t QSPI_EnableMemAccess(Qspid_t *pQspid, uint8_t const KeepCfg,
uint8_t ScrambleFlag)
{
QspiInstFrame_t *const pFrame = pQspid->pQspiFrame;
QspiMemCmd_t pCommand = pQspid->qspiCommand;
QspidStatus_t Status = QSPI_UNKNOWN_ERROR;
QSPI_SetInst(pQspid->pQspiHw, (pCommand.Instruction & 0xFF),
(pCommand.Option & 0xFF));
if (ScrambleFlag)
QSPI_ScrambleData(pQspid->pQspiHw, SCRAMBLE_KEY, ScrambleFlag, 1);
QSPI_SetInstFrame(pQspid->pQspiHw, pFrame);
QSPI_GetInstFrame(pQspid->pQspiHw);
// to synchronize system bus accesses
if (!KeepCfg)
pFrame->InstFrame.val = 0;
Status = QSPI_SUCCESS;
return Status;
}
/**
* \brief Writes or reads the QSPI memory (0x80000000) to transmit or
* receive data from Flash memory
* \param pQspi Pointer to an Qspi instance.
* \param ReadWrite Flag to indicate read/write QSPI memory access
*
* \return Returns 1 if At least one instruction end has been detected since
* the last read of QSPI_SR.; otherwise returns 0.
*/
QspidStatus_t QSPI_ReadWriteMem(Qspid_t *pQspid, Access_t const ReadWrite)
{
QspidStatus_t Status = QSPI_UNKNOWN_ERROR;
QspiInstFrame_t *const pFrame = pQspid->pQspiFrame;
void *pQspiMem = (void *)(QSPIMEM_ADDR | pFrame->Addr);
QspiBuffer_t pBuffer = pQspid->qspiBuffer;
assert(((ReadWrite > CmdAccess)
&& (ReadWrite <= WriteAccess)) ? true : false);
if (ReadWrite == WriteAccess) {
copy_to_io(pQspiMem, pBuffer.pDataTx , pBuffer.TxDataSize);
} else {
copy_from_io(pBuffer.pDataRx, pQspiMem, pBuffer.RxDataSize);
}
memory_sync();
QSPI_EndTransfer(pQspid->pQspiHw);
// End transmission after all data has been sent
while (!(pQspid->pQspiHw->QSPI_SR & QSPI_SR_INSTRE));
// poll CR reg to know status if instruction has end
Status = QSPI_SUCCESS;
return Status;
}