SAMV71 Xplained Ultra Software Package 1.3

spid.c

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 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines