1 /* ----------------------------------------------------------------------------
\r
2 * ATMEL Microcontroller Software Support
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2010, Atmel Corporation
\r
6 * All rights reserved.
\r
8 * Redistribution and use in source and binary forms, with or without
\r
9 * modification, are permitted provided that the following conditions are met:
\r
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\r
14 * Atmel's name may not be used to endorse or promote products derived from
\r
15 * this software without specific prior written permission.
\r
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
\r
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
\r
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
\r
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
\r
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
27 * ----------------------------------------------------------------------------
\r
30 /** \addtogroup spi_module Working with QSPI
\r
31 * \ingroup peripherals_module
\r
32 * The QSPI driver provides the interface to configure and use the QSPI
\r
35 * The Serial Peripheral Interface (QSPI) circuit is a synchronous serial
\r
36 * data link that provides communication with external devices in Master
\r
39 * To use the QSPI, the user has to follow these few steps:
\r
40 * -# Enable the QSPI pins required by the application (see pio.h).
\r
41 * -# Configure the QSPI using the \ref QSPI_Configure(). This enables the
\r
42 * peripheral clock. The mode register is loaded with the given value.
\r
43 * -# Configure all the necessary chip selects with \ref QSPI_ConfigureNPCS().
\r
44 * -# Enable the QSPI by calling \ref QSPI_Enable().
\r
45 * -# Send/receive data using \ref QSPI_Write() and \ref QSPI_Read(). Note that \ref QSPI_Read()
\r
46 * must be called after \ref QSPI_Write() to retrieve the last value read.
\r
47 * -# Send/receive data using the PDC with the \ref QSPI_WriteBuffer() and
\r
48 * \ref QSPI_ReadBuffer() functions.
\r
49 * -# Disable the QSPI by calling \ref QSPI_Disable().
\r
51 * For more accurate information, please look at the QSPI section of the
\r
64 * Implementation of Serial Peripheral Interface (QSPI) controller.
\r
68 /*----------------------------------------------------------------------------
\r
70 *----------------------------------------------------------------------------*/
\r
74 #include "string.h"
\r
80 volatile uint8_t INSTRE_Flag =0;
\r
81 /*----------------------------------------------------------------------------
\r
82 * Exported functions
\r
83 *----------------------------------------------------------------------------*/
\r
86 * \brief Enables a QSPI peripheral.
\r
88 * \param qspi Pointer to an Qspi instance.
\r
90 extern void QSPI_Enable( Qspi* qspi )
\r
92 qspi->QSPI_CR = QSPI_CR_QSPIEN ;
\r
93 while(!(qspi->QSPI_SR & QSPI_SR_QSPIENS));
\r
97 * \brief Disables a SPI peripheral.
\r
99 * \param qspi Pointer to an Qspi instance.
\r
101 extern void QSPI_Disable( Qspi* qspi )
\r
103 qspi->QSPI_CR = QSPI_CR_QSPIDIS ;
\r
107 * \brief Reset a QSPI peripheral.
\r
109 * \param qspi Pointer to an Qspi instance.
\r
111 extern void QSPI_SwReset( Qspi* qspi )
\r
113 qspi->QSPI_CR = QSPI_CR_SWRST ;
\r
114 qspi->QSPI_CR = QSPI_CR_SWRST ;
\r
118 * \brief Enables one or more interrupt sources of a QSPI peripheral.
\r
120 * \param qspi Pointer to an Qspi instance.
\r
121 * \param sources Bitwise OR of selected interrupt sources.
\r
123 extern void QSPI_EnableIt( Qspi* qspi, uint32_t dwSources )
\r
125 qspi->QSPI_IER = dwSources ;
\r
129 * \brief Disables one or more interrupt sources of a QSPI peripheral.
\r
131 * \param qspi Pointer to an Qspi instance.
\r
132 * \param sources Bitwise OR of selected interrupt sources.
\r
134 extern void QSPI_DisableIt( Qspi* qspi, uint32_t dwSources )
\r
136 qspi->QSPI_IDR = dwSources ;
\r
140 * \brief Return the interrupt mask register.
\r
142 * \return Qspi interrupt mask register.
\r
144 extern uint32_t QSPI_GetItMask( Qspi* qspi )
\r
146 return (qspi->QSPI_IMR) ;
\r
150 * \brief Configures a QSPI peripheral as specified. The configuration can be computed
\r
151 * using several macros (see \ref spi_configuration_macros).
\r
153 * \param qspi Pointer to an Qspi instance.
\r
154 * \param id Peripheral ID of the QSPI.
\r
155 * \param configuration Value of the QSPI configuration register.
\r
157 extern void QSPI_Configure( Qspi* qspi, uint32_t dwConfiguration )
\r
159 qspi->QSPI_CR = QSPI_CR_QSPIDIS ;
\r
161 /* Execute a software reset of the QSPI twice */
\r
162 QSPI_SwReset(qspi);
\r
163 qspi->QSPI_MR = dwConfiguration ;
\r
168 * \brief Configures a chip select of a QSPI peripheral. The chip select configuration
\r
169 * is computed using several macros (see \ref spi_configuration_macros).
\r
171 * \param qspi Pointer to an Qspi instance.
\r
172 * \param npcs Chip select to configure (0, 1, 2 or 3).
\r
173 * \param configuration Desired chip select configuration.
\r
175 void QSPI_ConfigureClock( Qspi* qspi,uint32_t dwConfiguration )
\r
177 qspi->QSPI_SCR = dwConfiguration ;
\r
181 * \brief Get the current status register of the given QSPI peripheral.
\r
182 * \note This resets the internal value of the status register, so further
\r
183 * read may yield different values.
\r
184 * \param qspi Pointer to a Qspi instance.
\r
185 * \return QSPI status register.
\r
187 extern uint32_t QSPI_GetStatus( Qspi* qspi )
\r
189 return qspi->QSPI_SR ;
\r
193 * \brief Reads and returns the last word of data received by a SPI peripheral. This
\r
194 * method must be called after a successful SPI_Write call.
\r
196 * \param spi Pointer to an Spi instance.
\r
198 * \return readed data.
\r
200 extern uint32_t QSPI_Read( Qspi* qspi )
\r
202 while ( (qspi->QSPI_SR & SPI_SR_RDRF) == 0 ) ;
\r
204 return qspi->QSPI_RDR & 0xFFFF ;
\r
208 * \brief Sends data through a SPI peripheral. If the SPI is configured to use a fixed
\r
209 * peripheral select, the npcs value is meaningless. Otherwise, it identifies
\r
210 * the component which shall be addressed.
\r
212 * \param spi Pointer to an Spi instance.
\r
213 * \param npcs Chip select of the component to address (0, 1, 2 or 3).
\r
214 * \param data Word of data to send.
\r
216 extern void QSPI_Write( Qspi* qspi, uint16_t wData )
\r
219 while ( (qspi->QSPI_SR & QSPI_SR_TXEMPTY) == 0 ) ;
\r
220 qspi->QSPI_TDR = wData ;
\r
221 while ( (qspi->QSPI_SR & QSPI_SR_TDRE) == 0 ) ;
\r
225 * \brief Sends last data through a SPI peripheral.
\r
226 * If the SPI is configured to use a fixed peripheral select, the npcs value is
\r
227 * meaningless. Otherwise, it identifies the component which shall be addressed.
\r
229 * \param spi Pointer to an Spi instance.
\r
230 * \param npcs Chip select of the component to address (0, 1, 2 or 3).
\r
231 * \param data Word of data to send.
\r
233 extern void QSPI_WriteLast( Qspi* qspi, uint16_t wData )
\r
236 while ( (qspi->QSPI_SR & QSPI_SR_TXEMPTY) == 0 ) ;
\r
237 qspi->QSPI_TDR = wData ;
\r
238 qspi->QSPI_CR |= QSPI_CR_LASTXFER;
\r
239 while ( (qspi->QSPI_SR & QSPI_SR_TDRE) == 0 ) ;
\r
243 * \brief Enable QSPI Chip Select.
\r
244 * \param qspi Pointer to a Qspi instance.
\r
245 * \param cs QSPI chip select index.
\r
247 extern void QSPI_ConfigureCs( Qspi* qspi, uint8_t spiCs )
\r
251 /* Write to the MR register*/
\r
252 dwSpiMr = qspi->QSPI_MR ;
\r
253 dwSpiMr &= ~QSPI_MR_CSMODE_Msk ;
\r
255 qspi->QSPI_MR=dwSpiMr ;
\r
261 * \brief Returns if data has been received. This
\r
262 * method must be called after a successful QSPI_Write call.
\r
264 * \param qspi Pointer to an Qspi instance.
\r
266 * \return 1 if no data has been received else return return 0.
\r
268 extern int QSPI_RxEmpty(Qspi *qspi)
\r
270 return ((qspi->QSPI_SR & QSPI_SR_RDRF) == 0);
\r
274 * \brief Returns 1 if application can write data. This
\r
275 * method must be called before QSPI_Write call.
\r
277 * \param qspi Pointer to an Qspi instance.
\r
279 * \return 1 if application can write to the QSPI_TDR register else return return 0.
\r
281 extern int QSPI_TxRdy(Qspi *qspi)
\r
283 return ((qspi->QSPI_SR & QSPI_SR_TDRE) != 0);
\r
288 * \brief Check if QSPI transfer finish.
\r
290 * \param qspi Pointer to an Qspi instance.
\r
292 * \return Returns 1 if there is no pending write operation on the QSPI; otherwise
\r
295 extern uint32_t QSPI_IsFinished( Qspi* qspi )
\r
297 return ((qspi->QSPI_SR & QSPI_SR_TXEMPTY) != 0) ;
\r
301 * \brief Check if QSPI Cs is asserted.
\r
303 * \param qspi Pointer to an Qspi instance.
\r
305 * \return Returns 1 if tThe chip select is not asserted; otherwise
\r
308 extern uint32_t QSPI_IsCsAsserted( Qspi* qspi )
\r
310 return ((qspi->QSPI_SR & QSPI_SR_CSS) != 0) ;
\r
314 * \brief Check if QSPI Cs is asserted.
\r
316 * \param qspi Pointer to an Qspi instance.
\r
318 * \return Returns 1 if At least one chip select rise has been detected since the last read of QSPI_SR; otherwise
\r
321 extern uint32_t QSPI_IsCsRise( Qspi* qspi )
\r
323 return ((qspi->QSPI_SR & QSPI_SR_CSR) != 0) ;
\r
328 * \brief Check if QSPI Cs is asserted.
\r
330 * \param qspi Pointer to an Qspi instance.
\r
332 * \return Returns 1 if At least one instruction end has been detected since the last read of QSPI_SR.; otherwise
\r
335 extern uint32_t QSPI_IsEOFInst( Qspi* qspi )
\r
337 return ((qspi->QSPI_SR & QSPI_SR_INSTRE) != 0) ;
\r
341 * \brief Send instrucion over SPI or QSPI
\r
343 * \param qspi Pointer to an Qspi instance.
\r
345 * \return Returns 1 if At least one instruction end has been detected since the last read of QSPI_SR.; otherwise
\r
348 extern void QSPI_SendFrame( Qspi* qspi, qspiFrame *pFrame, AccesType ReadWrite)
\r
350 uint32_t regIFR, regICR, DummyRead;
\r
351 uint32_t *pQspiBuffer = (uint32_t *)QSPIMEM_ADDR;
\r
353 assert((qspi->QSPI_MR) & QSPI_MR_SMM);
\r
355 regIFR = (pFrame->spiMode | QSPI_IFR_INSTEN | (pFrame->OptionLen << QSPI_IFR_OPTL_Pos) | (pFrame->DummyCycles << QSPI_IFR_NBDUM_Pos) | (pFrame->ContinuousRead << 14)) ;
\r
356 // Write the instruction to reg
\r
357 regICR = ( QSPI_ICR_OPT(pFrame->Option) | QSPI_ICR_INST(pFrame->Instruction));
\r
359 if(pFrame->OptionEn)
\r
361 regIFR|=QSPI_IFR_OPTEN;
\r
364 /* Instruction frame without Data, only Instruction**/
\r
365 if(!(pFrame->DataSize))
\r
367 if(pFrame->InstAddrFlag) // If contain Address, put in IAr reg
\r
369 qspi->QSPI_IAR = pFrame->InstAddr;
\r
370 regIFR |= QSPI_IFR_ADDREN;
\r
372 qspi->QSPI_ICR = regICR; // update Instruction code reg
\r
373 qspi->QSPI_IFR = regIFR; // Instruction Frame reg
\r
375 else /* Instruction frame with Data and Instruction**/
\r
377 regIFR |= QSPI_IFR_DATAEN;
\r
380 regIFR |= QSPI_IFR_TFRTYP_TRSFR_WRITE;
\r
381 qspi->QSPI_ICR = regICR;
\r
382 qspi->QSPI_IFR = regIFR ;
\r
383 DummyRead = qspi->QSPI_IFR; // to synchronize system bus accesses
\r
384 if(pFrame->InstAddrFlag)
\r
386 pQspiBuffer += pFrame->InstAddr;
\r
388 memcpy(pQspiBuffer ,pFrame->pData, pFrame->DataSize);
\r
392 qspi->QSPI_ICR = regICR;
\r
393 qspi->QSPI_IFR = regIFR ;
\r
394 DummyRead = qspi->QSPI_IFR; // to synchronize system bus accesses
\r
395 memcpy(pFrame->pData, pQspiBuffer, pFrame->DataSize);
\r
400 qspi->QSPI_CR = QSPI_CR_LASTXFER; // End transmission after all data has been sent
\r
401 while(!(qspi->QSPI_SR & QSPI_SR_INSTRE)); // poll CR reg to know status if Intrustion has end
\r
409 * \brief Send instrucion over SPI or QSPI
\r
411 * \param qspi Pointer to an Qspi instance.
\r
413 * \return Returns 1 if At least one instruction end has been detected since the last read of QSPI_SR.; otherwise
\r
416 extern void QSPI_SendFrameToMem( Qspi* qspi, qspiFrame *pFrame, AccesType ReadWrite)
\r
418 uint32_t regIFR, regICR, DummyRead ;
\r
419 uint8_t *pQspiMem = (uint8_t *)QSPIMEM_ADDR;
\r
421 assert((qspi->QSPI_MR) & QSPI_MR_SMM);
\r
423 regIFR = (pFrame->spiMode | QSPI_IFR_INSTEN | QSPI_IFR_DATAEN | QSPI_IFR_ADDREN | (pFrame->OptionLen << QSPI_IFR_OPTL_Pos) | (pFrame->DummyCycles << QSPI_IFR_NBDUM_Pos) | (pFrame->ContinuousRead << 14)) ;
\r
424 // Write the instruction to reg
\r
425 regICR = ( QSPI_ICR_OPT(pFrame->Option) | QSPI_ICR_INST(pFrame->Instruction));
\r
426 if(pFrame->OptionEn)
\r
428 regIFR|=QSPI_IFR_OPTEN;
\r
430 pQspiMem += pFrame->InstAddr;
\r
433 regIFR |= QSPI_IFR_TFRTYP_TRSFR_WRITE_MEMORY;
\r
435 qspi->QSPI_ICR = regICR;
\r
436 qspi->QSPI_IFR = regIFR ;
\r
437 DummyRead = qspi->QSPI_IFR; // to synchronize system bus accesses
\r
439 memcpy(pQspiMem ,pFrame->pData, pFrame->DataSize);
\r
444 regIFR |= QSPI_IFR_TFRTYP_TRSFR_READ_MEMORY;
\r
446 qspi->QSPI_ICR = regICR;
\r
447 qspi->QSPI_IFR = regIFR ;
\r
448 DummyRead = qspi->QSPI_IFR; // to synchronize system bus accesses
\r
449 memcpy(pFrame->pData, pQspiMem , pFrame->DataSize); // Read QSPI AHB memory space
\r
453 qspi->QSPI_CR = QSPI_CR_LASTXFER; // End transmission after all data has been sent
\r
454 while(!(qspi->QSPI_SR & QSPI_SR_INSTRE)); // poll CR reg to know status if Intrustion has end
\r