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 /** \addtogroup spi_module Working with SPI 00031 * The SPI driver provides the interface to configure and use the SPI 00032 * peripheral. 00033 * 00034 * The Serial Peripheral Interface (SPI) circuit is a synchronous serial 00035 * data link that provides communication with external devices in Master 00036 * or Slave Mode. 00037 * 00038 * To use the SPI, the user has to follow these few steps: 00039 * -# Enable the SPI pins required by the application (see pio.h). 00040 * -# Configure the SPI using the \ref SPI_Configure(). This enables the 00041 * peripheral clock. The mode register is loaded with the given value. 00042 * -# Configure all the necessary chip selects with \ref SPI_ConfigureNPCS(). 00043 * -# Enable the SPI by calling \ref SPI_Enable(). 00044 * -# Send/receive data using \ref SPI_Write() and \ref SPI_Read(). Note that 00045 * \ref SPI_Read() 00046 * must be called after \ref SPI_Write() to retrieve the last value read. 00047 * -# Disable the SPI by calling \ref SPI_Disable(). 00048 * 00049 * For more accurate information, please look at the SPI section of the 00050 * Datasheet. 00051 * 00052 * Related files :\n 00053 * \ref spi.c\n 00054 * \ref spi.h.\n 00055 */ 00056 /*@{*/ 00057 /*@}*/ 00058 00059 /** 00060 * \file 00061 * 00062 * Implementation of Serial Peripheral Interface (SPI) controller. 00063 * 00064 */ 00065 00066 /*---------------------------------------------------------------------------- 00067 * Headers 00068 *----------------------------------------------------------------------------*/ 00069 00070 #include "chip.h" 00071 00072 #include <stdint.h> 00073 00074 /*---------------------------------------------------------------------------- 00075 * Exported functions 00076 *----------------------------------------------------------------------------*/ 00077 00078 /** 00079 * \brief Enables a SPI peripheral. 00080 * 00081 * \param spi Pointer to an SPI instance. 00082 */ 00083 extern void SPI_Enable(Spi *spi) 00084 { 00085 spi->SPI_CR = SPI_CR_SPIEN; 00086 } 00087 00088 /** 00089 * \brief Disables a SPI peripheral. 00090 * 00091 * \param spi Pointer to an SPI instance. 00092 */ 00093 extern void SPI_Disable(Spi *spi) 00094 { 00095 spi->SPI_CR = SPI_CR_SPIDIS; 00096 } 00097 00098 /** 00099 * \brief Enables one or more interrupt sources of a SPI peripheral. 00100 * 00101 * \param spi Pointer to an SPI instance. 00102 * \param sources Bitwise OR of selected interrupt sources. 00103 */ 00104 extern void SPI_EnableIt(Spi *spi, uint32_t dwSources) 00105 { 00106 spi->SPI_IER = dwSources; 00107 } 00108 00109 /** 00110 * \brief Disables one or more interrupt sources of a SPI peripheral. 00111 * 00112 * \param spi Pointer to an SPI instance. 00113 * \param sources Bitwise OR of selected interrupt sources. 00114 */ 00115 extern void SPI_DisableIt(Spi *spi, uint32_t dwSources) 00116 { 00117 spi->SPI_IDR = dwSources; 00118 } 00119 00120 /** 00121 * \brief Configures a SPI peripheral as specified. The configuration can be 00122 * computed using several macros (see \ref spi_configuration_macros). 00123 * 00124 * \param spi Pointer to an SPI instance. 00125 * \param id Peripheral ID of the SPI. 00126 * \param configuration Value of the SPI configuration register. 00127 */ 00128 extern void SPI_Configure(Spi *spi, uint32_t dwId, uint32_t dwConfiguration) 00129 { 00130 PMC_EnablePeripheral(dwId); 00131 00132 spi->SPI_CR = SPI_CR_SPIDIS; 00133 00134 /* Execute a software reset of the SPI twice */ 00135 spi->SPI_CR = SPI_CR_SWRST; 00136 spi->SPI_CR = SPI_CR_SWRST; 00137 spi->SPI_MR = dwConfiguration; 00138 } 00139 00140 /** 00141 * \brief Configures SPI chip select. 00142 * 00143 * \param spi Pointer to an SPI instance. 00144 * \param cS Chip select of NPSCx. 00145 */ 00146 extern void SPI_ChipSelect(Spi *spi, uint8_t cS) 00147 { 00148 spi->SPI_MR |= SPI_MR_PCS_Msk; 00149 spi->SPI_MR &= ~(SPI_MR_PCS (cS)); 00150 } 00151 00152 /** 00153 * \brief Configures SPI Mode Register. 00154 * 00155 * \param spi Pointer to an SPI instance. 00156 * \param configuration Value of the SPI mode register. 00157 */ 00158 extern void SPI_SetMode(Spi *spi, 00159 uint32_t dwConfiguration) 00160 { 00161 spi->SPI_MR = dwConfiguration; 00162 } 00163 00164 /** 00165 * \brief Configures SPI to release last used CS line. 00166 * 00167 * \param spi Pointer to an SPI instance. 00168 */ 00169 extern void SPI_ReleaseCS(Spi *spi) 00170 { 00171 spi->SPI_CR = SPI_CR_LASTXFER; 00172 } 00173 00174 00175 /** 00176 * \brief Configures a chip select of a SPI peripheral. The chip select 00177 * configuration is computed using several macros 00178 * (see \ref spi_configuration_macros). 00179 * 00180 * \param spi Pointer to an SPI instance. 00181 * \param npcs Chip select to configure (0, 1, 2 or 3). 00182 * \param configuration Desired chip select configuration. 00183 */ 00184 void SPI_ConfigureNPCS(Spi *spi, uint32_t dwNpcs, uint32_t dwConfiguration) 00185 { 00186 spi->SPI_CSR[dwNpcs] = dwConfiguration; 00187 } 00188 00189 /** 00190 * \brief Configures a chip select active mode of a SPI peripheral. 00191 * 00192 * \param spi Pointer to an SPI instance. 00193 * \param dwNpcs Chip select to configure (0, 1, 2 or 3). 00194 * \param bReleaseOnLast CS controlled by last transfer. 00195 * SPI_ReleaseCS() is used to release CS. 00196 */ 00197 void SPI_ConfigureCSMode(Spi *spi, uint32_t dwNpcs, uint32_t bReleaseOnLast) 00198 { 00199 if (bReleaseOnLast) 00200 spi->SPI_CSR[dwNpcs] |= SPI_CSR_CSAAT; 00201 else 00202 spi->SPI_CSR[dwNpcs] &= ~SPI_CSR_CSAAT; 00203 } 00204 00205 /** 00206 * \brief Get the current status register of the given SPI peripheral. 00207 * \note This resets the internal value of the status register, so further 00208 * read may yield different values. 00209 * \param spi Pointer to a Spi instance. 00210 * \return SPI status register. 00211 */ 00212 extern uint32_t SPI_GetStatus(Spi *spi) 00213 { 00214 return spi->SPI_SR; 00215 } 00216 00217 /** 00218 * \brief Reads and returns the last word of data received by a SPI peripheral. 00219 * This method must be called after a successful SPI_Write call. 00220 * 00221 * \param spi Pointer to an Spi instance. 00222 * 00223 * \return read data. 00224 */ 00225 extern uint32_t SPI_Read(Spi *spi) 00226 { 00227 while ((spi->SPI_SR & SPI_SR_RDRF) == 0); 00228 00229 return spi->SPI_RDR & 0xFFFF; 00230 } 00231 00232 /** 00233 * \brief Sends data through a SPI peripheral. If the SPI is configured to use a 00234 * fixed peripheral select, the npcs value is meaningless. Otherwise, 00235 * it identifies the component which shall be addressed. 00236 * 00237 * \param spi Pointer to an SPI instance. 00238 * \param npcs Chip select of the component to address (0, 1, 2 or 3). 00239 * \param data Word of data to send. 00240 */ 00241 extern void SPI_Write(Spi *spi, uint32_t dwNpcs, uint16_t wData) 00242 { 00243 /* Send data */ 00244 while ((spi->SPI_SR & SPI_SR_TXEMPTY) == 0); 00245 00246 spi->SPI_TDR = wData | SPI_PCS(dwNpcs); 00247 00248 while ((spi->SPI_SR & SPI_SR_TDRE) == 0); 00249 } 00250 00251 /** 00252 * \brief Sends last data through a SPI peripheral. 00253 * If the SPI is configured to use a fixed peripheral select, the npcs value is 00254 * meaningless. Otherwise, it identifies the component which shall be addressed. 00255 * 00256 * \param spi Pointer to an SPI instance. 00257 * \param npcs Chip select of the component to address (0, 1, 2 or 3). 00258 * \param data Word of data to send. 00259 */ 00260 extern void SPI_WriteLast(Spi *spi, uint32_t dwNpcs, uint16_t wData) 00261 { 00262 /* Send data */ 00263 while ((spi->SPI_SR & SPI_SR_TXEMPTY) == 0); 00264 00265 spi->SPI_TDR = wData | SPI_PCS(dwNpcs) | SPI_TDR_LASTXFER; 00266 00267 while ((spi->SPI_SR & SPI_SR_TDRE) == 0); 00268 } 00269 00270 /** 00271 * \brief Check if SPI transfer finish. 00272 * 00273 * \param spi Pointer to an SPI instance. 00274 * 00275 * \return Returns 1 if there is no pending write operation on the SPI; 00276 * otherwise returns 0. 00277 */ 00278 extern uint32_t SPI_IsFinished(Spi *spi) 00279 { 00280 return ((spi->SPI_SR & SPI_SR_TXEMPTY) != 0); 00281 } 00282