/* ---------------------------------------------------------------------------- | |
* SAM Software Package License | |
* ---------------------------------------------------------------------------- | |
* Copyright (c) 2014, 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_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)); | |
} | |
/*---------------------------------------------------------------------------- | |
* 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, 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; NumOfBytesWrite++) { | |
if( QSPI_GetStatus(pQspi, IsTxEmpty)) { | |
QSPI_WriteSPI(pQspi, (uint16_t )*pwData); | |
pwData += Addr_Inc; | |
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; | |
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(); | |
while(!(pQspid->pQspiHw->QSPI_SR & QSPI_SR_INSTRE)); | |
// 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; | |
uint32_t *pQspiMem = (uint32_t *)( QSPIMEM_ADDR | pFrame->Addr); | |
QspiBuffer_t pBuffer = pQspid->qspiBuffer; | |
assert( ( (ReadWrite > CmdAccess) && (ReadWrite <= WriteAccess) ) ? true: false ); | |
if (ReadWrite == WriteAccess) { | |
memcpy(pQspiMem, pBuffer.pDataTx , pBuffer.TxDataSize ); | |
} else { | |
memcpy(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; | |
} |