00001 /* ---------------------------------------------------------------------------- */ 00002 /* Atmel Microcontroller Software Support */ 00003 /* SAM Software Package License */ 00004 /* ---------------------------------------------------------------------------- */ 00005 /* Copyright (c) 2015, Atmel Corporation */ 00006 /* */ 00007 /* All rights reserved. */ 00008 /* */ 00009 /* Redistribution and use in source and binary forms, with or without */ 00010 /* modification, are permitted provided that the following condition is met: */ 00011 /* */ 00012 /* - Redistributions of source code must retain the above copyright notice, */ 00013 /* this list of conditions and the disclaimer below. */ 00014 /* */ 00015 /* Atmel's name may not be used to endorse or promote products derived from */ 00016 /* this software without specific prior written permission. */ 00017 /* */ 00018 /* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR */ 00019 /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ 00020 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE */ 00021 /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, */ 00022 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ 00023 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */ 00024 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */ 00025 /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */ 00026 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */ 00027 /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 00028 /* ---------------------------------------------------------------------------- */ 00029 00030 //------------------------------------------------------------------------------ 00031 // Headers 00032 //------------------------------------------------------------------------------ 00033 00034 #include "spid.h" 00035 #include "board.h" 00036 00037 //------------------------------------------------------------------------------ 00038 // Macros 00039 //------------------------------------------------------------------------------ 00040 00041 /// Write PMC register 00042 #define WRITE_PMC(pPmc, regName, value) pPmc->regName = (value) 00043 00044 /// Write SPI register 00045 #define WRITE_SPI(pSpi, regName, value) pSpi->regName = (value) 00046 00047 /// Read SPI registers 00048 #define READ_SPI(pSpi, regName) (pSpi->regName) 00049 00050 //------------------------------------------------------------------------------ 00051 // Exported functions 00052 //------------------------------------------------------------------------------ 00053 00054 //------------------------------------------------------------------------------ 00055 /// Initializes the Spid structure and the corresponding SPI hardware. 00056 /// Always returns 0. 00057 /// \param pSpid Pointer to a Spid instance. 00058 /// \param pSpiHw Associated SPI peripheral. 00059 /// \param spiId SPI peripheral identifier. 00060 //------------------------------------------------------------------------------ 00061 unsigned char SPID_Configure(Spid *pSpid, AT91S_SPI *pSpiHw, 00062 unsigned char spiId) 00063 { 00064 // Initialize the SPI structure 00065 pSpid->pSpiHw = pSpiHw; 00066 pSpid->spiId = spiId; 00067 pSpid->semaphore = 1; 00068 pSpid->pCurrentCommand = 0; 00069 00070 // Enable the SPI clock 00071 WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << pSpid->spiId)); 00072 00073 // Execute a software reset of the SPI twice 00074 WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST); 00075 WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST); 00076 00077 // Configure SPI in Master Mode with No CS selected !!! 00078 WRITE_SPI(pSpiHw, SPI_MR, AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS); 00079 00080 // Disable the PDC transfer 00081 WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS); 00082 00083 // Enable the SPI 00084 WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIEN); 00085 00086 // Enable the SPI clock 00087 WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pSpid->spiId)); 00088 00089 return 0; 00090 } 00091 00092 //------------------------------------------------------------------------------ 00093 /// Configures the parameters for the device corresponding to the cs. 00094 /// \param pSpid Pointer to a Spid instance. 00095 /// \param cs number corresponding to the SPI chip select. 00096 /// \param csr SPI_CSR value to setup. 00097 //------------------------------------------------------------------------------ 00098 void SPID_ConfigureCS(Spid *pSpid, unsigned char cs, unsigned int csr) 00099 { 00100 AT91S_SPI *pSpiHw = pSpid->pSpiHw; 00101 WRITE_SPI(pSpiHw, SPI_CSR[cs], csr); 00102 } 00103 00104 //------------------------------------------------------------------------------ 00105 /// Starts a SPI master transfer. This is a non blocking function. It will 00106 /// return as soon as the transfer is started. 00107 /// Returns 0 if the transfer has been started successfully; otherwise returns 00108 /// SPID_ERROR_LOCK is the driver is in use, or SPID_ERROR if the command is not 00109 /// valid. 00110 /// \param pSpid Pointer to a Spid instance. 00111 /// \param pCommand Pointer to the SPI command to execute. 00112 //------------------------------------------------------------------------------ 00113 unsigned char SPID_SendCommand(Spid *pSpid, SpidCmd *pCommand) 00114 { 00115 AT91S_SPI *pSpiHw = pSpid->pSpiHw; 00116 unsigned int spiMr; 00117 00118 // Try to get the dataflash semaphore 00119 if (pSpid->semaphore == 0) 00120 00121 return SPID_ERROR_LOCK; 00122 00123 pSpid->semaphore--; 00124 00125 // Enable the SPI clock 00126 WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << pSpid->spiId)); 00127 00128 // Disable transmitter and receiver 00129 WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS); 00130 00131 // Write to the MR register 00132 spiMr = READ_SPI(pSpiHw, SPI_MR); 00133 spiMr |= AT91C_SPI_PCS; 00134 spiMr &= ~((1 << pCommand->spiCs) << 16); 00135 WRITE_SPI(pSpiHw, SPI_MR, spiMr); 00136 00137 // Initialize the two SPI PDC buffer 00138 WRITE_SPI(pSpiHw, SPI_RPR, (int) pCommand->pCmd); 00139 WRITE_SPI(pSpiHw, SPI_RCR, pCommand->cmdSize); 00140 WRITE_SPI(pSpiHw, SPI_TPR, (int) pCommand->pCmd); 00141 WRITE_SPI(pSpiHw, SPI_TCR, pCommand->cmdSize); 00142 00143 WRITE_SPI(pSpiHw, SPI_RNPR, (int) pCommand->pData); 00144 WRITE_SPI(pSpiHw, SPI_RNCR, pCommand->dataSize); 00145 WRITE_SPI(pSpiHw, SPI_TNPR, (int) pCommand->pData); 00146 WRITE_SPI(pSpiHw, SPI_TNCR, pCommand->dataSize); 00147 00148 // Initialize the callback 00149 pSpid->pCurrentCommand = pCommand; 00150 00151 // Enable transmitter and receiver 00152 WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTEN | AT91C_PDC_TXTEN); 00153 00154 // Enable buffer complete interrupt 00155 WRITE_SPI(pSpiHw, SPI_IER, AT91C_SPI_RXBUFF); 00156 00157 return 0; 00158 } 00159 00160 //------------------------------------------------------------------------------ 00161 /// The SPI_Handler must be called by the SPI Interrupt Service Routine with the 00162 /// corresponding Spi instance. 00163 /// The SPI_Handler will unlock the Spi semaphore and invoke the upper application 00164 /// callback. 00165 /// \param pSpid Pointer to a Spid instance. 00166 //------------------------------------------------------------------------------ 00167 void SPID_Handler(Spid *pSpid) 00168 { 00169 SpidCmd *pSpidCmd = pSpid->pCurrentCommand; 00170 AT91S_SPI *pSpiHw = pSpid->pSpiHw; 00171 volatile unsigned int spiSr; 00172 00173 // Read the status register 00174 spiSr = READ_SPI(pSpiHw, SPI_SR); 00175 00176 if (spiSr & AT91C_SPI_RXBUFF) { 00177 // Disable transmitter and receiver 00178 WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS); 00179 00180 // Disable the SPI clock 00181 WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pSpid->spiId)); 00182 00183 // Disable buffer complete interrupt 00184 WRITE_SPI(pSpiHw, SPI_IDR, AT91C_SPI_RXBUFF); 00185 00186 // Release the dataflash semaphore 00187 pSpid->semaphore++; 00188 00189 // Invoke the callback associated with the current command 00190 if (pSpidCmd && pSpidCmd->callback) 00191 00192 pSpidCmd->callback(0, pSpidCmd->pArgument); 00193 00194 // Nothing must be done after. A new DF operation may have been started 00195 // in the callback function. 00196 } 00197 } 00198 00199 //------------------------------------------------------------------------------ 00200 /// Returns 1 if the SPI driver is currently busy executing a command; otherwise 00201 /// returns 0. 00202 /// \param pSpid Pointer to a SPI driver instance. 00203 //------------------------------------------------------------------------------ 00204 unsigned char SPID_IsBusy(const Spid *pSpid) 00205 { 00206 if (pSpid->semaphore == 0) 00207 return 1; 00208 else 00209 return 0; 00210 } 00211