Christina Quast | b0a0570 | 2014-11-28 10:27:32 +0100 | [diff] [blame^] | 1 | /* ----------------------------------------------------------------------------
|
| 2 | * ATMEL Microcontroller Software Support
|
| 3 | * ----------------------------------------------------------------------------
|
| 4 | * Copyright (c) 2009, Atmel Corporation
|
| 5 | *
|
| 6 | * All rights reserved.
|
| 7 | *
|
| 8 | * Redistribution and use in source and binary forms, with or without
|
| 9 | * modification, are permitted provided that the following conditions are met:
|
| 10 | *
|
| 11 | * - Redistributions of source code must retain the above copyright notice,
|
| 12 | * this list of conditions and the disclaimer below.
|
| 13 | *
|
| 14 | * Atmel's name may not be used to endorse or promote products derived from
|
| 15 | * this software without specific prior written permission.
|
| 16 | *
|
| 17 | * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
| 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
| 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
| 20 | * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
| 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| 22 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
| 23 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
| 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
| 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
| 26 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 27 | * ----------------------------------------------------------------------------
|
| 28 | */
|
| 29 |
|
| 30 | /** \addtogroup spi_module Working with SPI
|
| 31 | * The SPI driver provides the interface to configure and use the SPI
|
| 32 | * peripheral.
|
| 33 | *
|
| 34 | * The Serial Peripheral Interface (SPI) circuit is a synchronous serial
|
| 35 | * data link that provides communication with external devices in Master
|
| 36 | * or Slave Mode.
|
| 37 | *
|
| 38 | * To use the SPI, the user has to follow these few steps:
|
| 39 | * -# Enable the SPI pins required by the application (see pio.h).
|
| 40 | * -# Configure the SPI using the \ref SPI_Configure(). This enables the
|
| 41 | * peripheral clock. The mode register is loaded with the given value.
|
| 42 | * -# Configure all the necessary chip selects with \ref SPI_ConfigureNPCS().
|
| 43 | * -# Enable the SPI by calling \ref SPI_Enable().
|
| 44 | * -# Send/receive data using \ref SPI_Write() and \ref SPI_Read(). Note that \ref SPI_Read()
|
| 45 | * must be called after \ref SPI_Write() to retrieve the last value read.
|
| 46 | * -# Send/receive data using the PDC with the \ref SPI_WriteBuffer() and
|
| 47 | * \ref SPI_ReadBuffer() functions.
|
| 48 | * -# Disable the SPI by calling \ref SPI_Disable().
|
| 49 | *
|
| 50 | * For more accurate information, please look at the SPI section of the
|
| 51 | * Datasheet.
|
| 52 | *
|
| 53 | * Related files :\n
|
| 54 | * \ref spi.c\n
|
| 55 | * \ref spi.h.\n
|
| 56 | */
|
| 57 | /*@{*/
|
| 58 | /*@}*/
|
| 59 |
|
| 60 | /**
|
| 61 | * \file
|
| 62 | *
|
| 63 | * Implementation of Serial Peripheral Interface (SPI) controller.
|
| 64 | *
|
| 65 | */
|
| 66 |
|
| 67 | /*----------------------------------------------------------------------------
|
| 68 | * Headers
|
| 69 | *----------------------------------------------------------------------------*/
|
| 70 |
|
| 71 | #include "chip.h"
|
| 72 | #include "pmc.h"
|
| 73 | #include "spi.h"
|
| 74 |
|
| 75 | #include <stdint.h>
|
| 76 |
|
| 77 | /*----------------------------------------------------------------------------
|
| 78 | * Exported functions
|
| 79 | *----------------------------------------------------------------------------*/
|
| 80 |
|
| 81 | /**
|
| 82 | * \brief Enables a SPI peripheral.
|
| 83 | *
|
| 84 | * \param spi Pointer to an Spi instance.
|
| 85 | */
|
| 86 | extern void SPI_Enable( Spi* spi )
|
| 87 | {
|
| 88 | spi->SPI_CR = SPI_CR_SPIEN ;
|
| 89 | }
|
| 90 |
|
| 91 | /**
|
| 92 | * \brief Disables a SPI peripheral.
|
| 93 | *
|
| 94 | * \param spi Pointer to an Spi instance.
|
| 95 | */
|
| 96 | extern void SPI_Disable( Spi* spi )
|
| 97 | {
|
| 98 | spi->SPI_CR = SPI_CR_SPIDIS ;
|
| 99 | }
|
| 100 |
|
| 101 | /**
|
| 102 | * \brief Enables one or more interrupt sources of a SPI peripheral.
|
| 103 | *
|
| 104 | * \param spi Pointer to an Spi instance.
|
| 105 | * \param sources Bitwise OR of selected interrupt sources.
|
| 106 | */
|
| 107 | extern void SPI_EnableIt( Spi* spi, uint32_t dwSources )
|
| 108 | {
|
| 109 | spi->SPI_IER = dwSources ;
|
| 110 | }
|
| 111 |
|
| 112 | /**
|
| 113 | * \brief Disables one or more interrupt sources of a SPI peripheral.
|
| 114 | *
|
| 115 | * \param spi Pointer to an Spi instance.
|
| 116 | * \param sources Bitwise OR of selected interrupt sources.
|
| 117 | */
|
| 118 | extern void SPI_DisableIt( Spi* spi, uint32_t dwSources )
|
| 119 | {
|
| 120 | spi->SPI_IDR = dwSources ;
|
| 121 | }
|
| 122 |
|
| 123 | /**
|
| 124 | * \brief Configures a SPI peripheral as specified. The configuration can be computed
|
| 125 | * using several macros (see \ref spi_configuration_macros).
|
| 126 | *
|
| 127 | * \param spi Pointer to an Spi instance.
|
| 128 | * \param id Peripheral ID of the SPI.
|
| 129 | * \param configuration Value of the SPI configuration register.
|
| 130 | */
|
| 131 | extern void SPI_Configure( Spi* spi, uint32_t dwId, uint32_t dwConfiguration )
|
| 132 | {
|
| 133 | PMC_EnablePeripheral( dwId ) ;
|
| 134 | spi->SPI_CR = SPI_CR_SPIDIS ;
|
| 135 |
|
| 136 | /* Execute a software reset of the SPI twice */
|
| 137 | spi->SPI_CR = SPI_CR_SWRST ;
|
| 138 | spi->SPI_CR = SPI_CR_SWRST ;
|
| 139 | spi->SPI_MR = dwConfiguration ;
|
| 140 | }
|
| 141 |
|
| 142 |
|
| 143 | /**
|
| 144 | * \brief Configures a chip select of a SPI peripheral. The chip select configuration
|
| 145 | * is computed using several macros (see \ref spi_configuration_macros).
|
| 146 | *
|
| 147 | * \param spi Pointer to an Spi instance.
|
| 148 | * \param npcs Chip select to configure (0, 1, 2 or 3).
|
| 149 | * \param configuration Desired chip select configuration.
|
| 150 | */
|
| 151 | void SPI_ConfigureNPCS( Spi* spi, uint32_t dwNpcs, uint32_t dwConfiguration )
|
| 152 | {
|
| 153 | spi->SPI_CSR[dwNpcs] = dwConfiguration ;
|
| 154 | }
|
| 155 |
|
| 156 | /**
|
| 157 | * \brief Get the current status register of the given SPI peripheral.
|
| 158 | * \note This resets the internal value of the status register, so further
|
| 159 | * read may yield different values.
|
| 160 | * \param spi Pointer to a Spi instance.
|
| 161 | * \return SPI status register.
|
| 162 | */
|
| 163 | extern uint32_t SPI_GetStatus( Spi* spi )
|
| 164 | {
|
| 165 | return spi->SPI_SR ;
|
| 166 | }
|
| 167 |
|
| 168 | /**
|
| 169 | * \brief Reads and returns the last word of data received by a SPI peripheral. This
|
| 170 | * method must be called after a successful SPI_Write call.
|
| 171 | *
|
| 172 | * \param spi Pointer to an Spi instance.
|
| 173 | *
|
| 174 | * \return readed data.
|
| 175 | */
|
| 176 | extern uint32_t SPI_Read( Spi* spi )
|
| 177 | {
|
| 178 | while ( (spi->SPI_SR & SPI_SR_RDRF) == 0 ) ;
|
| 179 |
|
| 180 | return spi->SPI_RDR & 0xFFFF ;
|
| 181 | }
|
| 182 |
|
| 183 | /**
|
| 184 | * \brief Sends data through a SPI peripheral. If the SPI is configured to use a fixed
|
| 185 | * peripheral select, the npcs value is meaningless. Otherwise, it identifies
|
| 186 | * the component which shall be addressed.
|
| 187 | *
|
| 188 | * \param spi Pointer to an Spi instance.
|
| 189 | * \param npcs Chip select of the component to address (0, 1, 2 or 3).
|
| 190 | * \param data Word of data to send.
|
| 191 | */
|
| 192 | extern void SPI_Write( Spi* spi, uint32_t dwNpcs, uint16_t wData )
|
| 193 | {
|
| 194 | /* Send data */
|
| 195 | while ( (spi->SPI_SR & SPI_SR_TXEMPTY) == 0 ) ;
|
| 196 | spi->SPI_TDR = wData | SPI_PCS( dwNpcs ) ;
|
| 197 | while ( (spi->SPI_SR & SPI_SR_TDRE) == 0 ) ;
|
| 198 | }
|
| 199 |
|
| 200 | /**
|
| 201 | * \brief Check if SPI transfer finish.
|
| 202 | *
|
| 203 | * \param spi Pointer to an Spi instance.
|
| 204 | *
|
| 205 | * \return Returns 1 if there is no pending write operation on the SPI; otherwise
|
| 206 | * returns 0.
|
| 207 | */
|
| 208 | extern uint32_t SPI_IsFinished( Spi* spi )
|
| 209 | {
|
| 210 | return ((spi->SPI_SR & SPI_SR_TXEMPTY) != 0) ;
|
| 211 | }
|
| 212 |
|
| 213 | /**
|
| 214 | * \brief Enable Spi PDC transmit
|
| 215 | * \param spi Pointer to an Spi instance.
|
| 216 | */
|
| 217 | extern void SPI_PdcEnableTx( Spi* spi )
|
| 218 | {
|
| 219 | spi->SPI_PTCR = SPI_PTCR_TXTEN ;
|
| 220 | }
|
| 221 |
|
| 222 | /**
|
| 223 | * \brief Disable Spi PDC transmit
|
| 224 | * \param spi Pointer to an Spi instance.
|
| 225 | */
|
| 226 | extern void SPI_PdcDisableTx( Spi* spi )
|
| 227 | {
|
| 228 | spi->SPI_PTCR = SPI_PTCR_TXTDIS ;
|
| 229 | }
|
| 230 |
|
| 231 | /**
|
| 232 | * \brief Enable Spi PDC receive
|
| 233 | * \param spi Pointer to an Spi instance.
|
| 234 | */
|
| 235 | extern void SPI_PdcEnableRx( Spi* spi )
|
| 236 | {
|
| 237 | spi->SPI_PTCR = SPI_PTCR_RXTEN ;
|
| 238 | }
|
| 239 |
|
| 240 | /**
|
| 241 | * \brief Disable Spi PDC receive
|
| 242 | * \param spi Pointer to an Spi instance.
|
| 243 | */
|
| 244 | extern void SPI_PdcDisableRx( Spi* spi )
|
| 245 | {
|
| 246 | spi->SPI_PTCR = SPI_PTCR_RXTDIS ;
|
| 247 | }
|
| 248 |
|
| 249 | /**
|
| 250 | * \brief Set PDC transmit and next transmit buffer address and size.
|
| 251 | *
|
| 252 | * \param spi Pointer to an Spi instance.
|
| 253 | * \param txBuf PDC transmit buffer address.
|
| 254 | * \param txCount Length in bytes of the transmit buffer.
|
| 255 | * \param txNextBuf PDC next transmit buffer address.
|
| 256 | * \param txNextCount Length in bytes of the next transmit buffer.
|
| 257 | */
|
| 258 | extern void SPI_PdcSetTx( Spi* spi, void* pvTxBuf, uint32_t dwTxCount, void* pvTxNextBuf, uint32_t dwTxNextCount )
|
| 259 | {
|
| 260 | spi->SPI_TPR = (uint32_t)pvTxBuf ;
|
| 261 | spi->SPI_TCR = dwTxCount ;
|
| 262 | spi->SPI_TNPR = (uint32_t)pvTxNextBuf ;
|
| 263 | spi->SPI_TNCR = dwTxNextCount ;
|
| 264 | }
|
| 265 |
|
| 266 | /**
|
| 267 | * \brief Set PDC receive and next receive buffer address and size.
|
| 268 | *
|
| 269 | * \param spi Pointer to an Spi instance.
|
| 270 | * \param rxBuf PDC receive buffer address.
|
| 271 | * \param rxCount Length in bytes of the receive buffer.
|
| 272 | * \param rxNextBuf PDC next receive buffer address.
|
| 273 | * \param rxNextCount Length in bytes of the next receive buffer.
|
| 274 | */
|
| 275 | extern void SPI_PdcSetRx( Spi* spi, void* pvRxBuf, uint32_t dwRxCount, void* pvRxNextBuf, uint32_t dwRxNextCount )
|
| 276 | {
|
| 277 | spi->SPI_RPR = (uint32_t)pvRxBuf ;
|
| 278 | spi->SPI_RCR = dwRxCount ;
|
| 279 | spi->SPI_RNPR = (uint32_t)pvRxNextBuf ;
|
| 280 | spi->SPI_RNCR = dwRxNextCount ;
|
| 281 | }
|
| 282 |
|
| 283 | /**
|
| 284 | * \brief Sends the contents of buffer through a SPI peripheral, using the PDC to
|
| 285 | * take care of the transfer.
|
| 286 | *
|
| 287 | * \param spi Pointer to an Spi instance.
|
| 288 | * \param buffer Data buffer to send.
|
| 289 | * \param length Length of the data buffer.
|
| 290 | */
|
| 291 | extern uint32_t SPI_WriteBuffer( Spi* spi, void* pvBuffer, uint32_t dwLength )
|
| 292 | {
|
| 293 | /* Check if first bank is free */
|
| 294 | if ( spi->SPI_TCR == 0 )
|
| 295 | {
|
| 296 | spi->SPI_TPR = (uint32_t)pvBuffer ;
|
| 297 | spi->SPI_TCR = dwLength ;
|
| 298 | spi->SPI_PTCR = PERIPH_PTCR_TXTEN ;
|
| 299 |
|
| 300 | return 1 ;
|
| 301 | }
|
| 302 | /* Check if second bank is free */
|
| 303 | else
|
| 304 | {
|
| 305 | if ( spi->SPI_TNCR == 0 )
|
| 306 | {
|
| 307 | spi->SPI_TNPR = (uint32_t)pvBuffer ;
|
| 308 | spi->SPI_TNCR = dwLength ;
|
| 309 |
|
| 310 | return 1 ;
|
| 311 | }
|
| 312 | }
|
| 313 |
|
| 314 | /* No free banks */
|
| 315 | return 0 ;
|
| 316 | }
|
| 317 |
|
| 318 | /**
|
| 319 | * \brief Reads data from a SPI peripheral until the provided buffer is filled. This
|
| 320 | * method does NOT need to be called after SPI_Write or SPI_WriteBuffer.
|
| 321 | *
|
| 322 | * \param spi Pointer to an Spi instance.
|
| 323 | * \param buffer Data buffer to store incoming bytes.
|
| 324 | * \param length Length in bytes of the data buffer.
|
| 325 | */
|
| 326 | extern uint32_t SPI_ReadBuffer( Spi* spi, void *pvBuffer, uint32_t dwLength )
|
| 327 | {
|
| 328 | /* Check if the first bank is free */
|
| 329 | if ( spi->SPI_RCR == 0 )
|
| 330 | {
|
| 331 | spi->SPI_RPR = (uint32_t)pvBuffer ;
|
| 332 | spi->SPI_RCR = dwLength ;
|
| 333 | spi->SPI_PTCR = PERIPH_PTCR_RXTEN ;
|
| 334 |
|
| 335 | return 1 ;
|
| 336 | }
|
| 337 | /* Check if second bank is free */
|
| 338 | else
|
| 339 | {
|
| 340 | if ( spi->SPI_RNCR == 0 )
|
| 341 | {
|
| 342 | spi->SPI_RNPR = (uint32_t)pvBuffer ;
|
| 343 | spi->SPI_RNCR = dwLength ;
|
| 344 | return 1 ;
|
| 345 | }
|
| 346 | }
|
| 347 |
|
| 348 | /* No free bank */
|
| 349 | return 0 ;
|
| 350 | }
|
| 351 |
|
| 352 |
|