00001 /* ---------------------------------------------------------------------------- 00002 * SAM Software Package License 00003 * ---------------------------------------------------------------------------- 00004 * Copyright (c) 2011, 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 /** \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 /** 00207 * \brief Get the current status register of the given SPI peripheral. 00208 * \note This resets the internal value of the status register, so further 00209 * read may yield different values. 00210 * \param spi Pointer to a Spi instance. 00211 * \return SPI status register. 00212 */ 00213 extern uint32_t SPI_GetStatus( Spi* spi ) 00214 { 00215 return spi->SPI_SR ; 00216 } 00217 00218 /** 00219 * \brief Reads and returns the last word of data received by a SPI peripheral. 00220 * This method must be called after a successful SPI_Write call. 00221 * 00222 * \param spi Pointer to an Spi instance. 00223 * 00224 * \return read data. 00225 */ 00226 extern uint32_t SPI_Read( Spi* spi ) 00227 { 00228 while ( (spi->SPI_SR & SPI_SR_RDRF) == 0 ) ; 00229 00230 return spi->SPI_RDR & 0xFFFF ; 00231 } 00232 00233 /** 00234 * \brief Sends data through a SPI peripheral. If the SPI is configured to use a 00235 * fixed peripheral select, the npcs value is meaningless. Otherwise, 00236 * it identifies the component which shall be addressed. 00237 * 00238 * \param spi Pointer to an SPI instance. 00239 * \param npcs Chip select of the component to address (0, 1, 2 or 3). 00240 * \param data Word of data to send. 00241 */ 00242 extern void SPI_Write( Spi* spi, uint32_t dwNpcs, uint16_t wData ) 00243 { 00244 /* Send data */ 00245 while ( (spi->SPI_SR & SPI_SR_TXEMPTY) == 0 ) ; 00246 spi->SPI_TDR = wData | SPI_PCS( dwNpcs ) ; 00247 while ( (spi->SPI_SR & SPI_SR_TDRE) == 0 ) ; 00248 } 00249 00250 /** 00251 * \brief Sends last data through a SPI peripheral. 00252 * If the SPI is configured to use a fixed peripheral select, the npcs value is 00253 * meaningless. Otherwise, it identifies the component which shall be addressed. 00254 * 00255 * \param spi Pointer to an SPI instance. 00256 * \param npcs Chip select of the component to address (0, 1, 2 or 3). 00257 * \param data Word of data to send. 00258 */ 00259 extern void SPI_WriteLast( Spi* spi, uint32_t dwNpcs, uint16_t wData ) 00260 { 00261 /* Send data */ 00262 while ( (spi->SPI_SR & SPI_SR_TXEMPTY) == 0 ) ; 00263 spi->SPI_TDR = wData | SPI_PCS( dwNpcs ) | SPI_TDR_LASTXFER ; 00264 while ( (spi->SPI_SR & SPI_SR_TDRE) == 0 ) ; 00265 } 00266 00267 /** 00268 * \brief Check if SPI transfer finish. 00269 * 00270 * \param spi Pointer to an SPI instance. 00271 * 00272 * \return Returns 1 if there is no pending write operation on the SPI; 00273 * otherwise returns 0. 00274 */ 00275 extern uint32_t SPI_IsFinished( Spi* spi ) 00276 { 00277 return ((spi->SPI_SR & SPI_SR_TXEMPTY) != 0) ; 00278 } 00279