blob: 8e4b965294143edb6b0b62c2de13b9d029baf9d6 [file] [log] [blame]
Christina Quastb0a05702014-11-28 10:27:32 +01001/* ----------------------------------------------------------------------------
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 */
86extern 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 */
96extern 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 */
107extern 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 */
118extern 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 */
131extern 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 */
151void 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 */
163extern 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 */
176extern 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 */
192extern 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 */
208extern 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*/
217extern 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*/
226extern 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*/
235extern 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*/
244extern 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 */
258extern 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 */
275extern 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 */
291extern 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 */
326extern 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