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