]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_SAMV71_Xplained_IAR_Keil/libchip_samv7/source/spi.c
Final V8.2.1 release ready for tagging:
[freertos] / FreeRTOS / Demo / CORTEX_M7_SAMV71_Xplained_IAR_Keil / libchip_samv7 / source / spi.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License \r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2011, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\r
8  * Redistribution and use in source and binary forms, with or without\r
9  * modification, are permitted provided that the following conditions are met:\r
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\r
14  * Atmel's name may not be used to endorse or promote products derived from\r
15  * this software without specific prior written permission.\r
16  *\r
17  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
20  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  * ----------------------------------------------------------------------------\r
28  */\r
29 \r
30 /** \addtogroup spi_module Working with SPI\r
31  * The SPI driver provides the interface to configure and use the SPI\r
32  * peripheral.\r
33  *\r
34  * The Serial Peripheral Interface (SPI) circuit is a synchronous serial\r
35  * data link that provides communication with external devices in Master\r
36  * or Slave Mode.\r
37  *\r
38  * To use the SPI, the user has to follow these few steps:\r
39  * -# Enable the SPI pins required by the application (see pio.h).\r
40  * -# Configure the SPI using the \ref SPI_Configure(). This enables the\r
41  *    peripheral clock. The mode register is loaded with the given value.\r
42  * -# Configure all the necessary chip selects with \ref SPI_ConfigureNPCS().\r
43  * -# Enable the SPI by calling \ref SPI_Enable().\r
44  * -# Send/receive data using \ref SPI_Write() and \ref SPI_Read(). Note that \ref SPI_Read()\r
45  *    must be called after \ref SPI_Write() to retrieve the last value read. \r
46  * -# Disable the SPI by calling \ref SPI_Disable().\r
47  *\r
48  * For more accurate information, please look at the SPI section of the\r
49  * Datasheet.\r
50  *\r
51  * Related files :\n\r
52  * \ref spi.c\n\r
53  * \ref spi.h.\n\r
54 */\r
55 /*@{*/\r
56 /*@}*/\r
57 \r
58 /**\r
59  * \file\r
60  *\r
61  * Implementation of Serial Peripheral Interface (SPI) controller.\r
62  *\r
63  */\r
64 \r
65 /*----------------------------------------------------------------------------\r
66  *        Headers\r
67  *----------------------------------------------------------------------------*/\r
68 \r
69 #include "chip.h"\r
70 \r
71 #include <stdint.h>\r
72 \r
73 /*----------------------------------------------------------------------------\r
74  *        Exported functions\r
75  *----------------------------------------------------------------------------*/\r
76 \r
77 /**\r
78  * \brief Enables a SPI peripheral.\r
79  *\r
80  * \param spi  Pointer to an Spi instance.\r
81  */\r
82 extern void SPI_Enable( Spi* spi )\r
83 {\r
84     spi->SPI_CR = SPI_CR_SPIEN ;\r
85 }\r
86 \r
87 /**\r
88  * \brief Disables a SPI peripheral.\r
89  *\r
90  * \param spi  Pointer to an Spi instance.\r
91  */\r
92 extern void SPI_Disable( Spi* spi )\r
93 {\r
94     spi->SPI_CR = SPI_CR_SPIDIS ;\r
95 }\r
96 \r
97 /**\r
98  * \brief Enables one or more interrupt sources of a SPI peripheral.\r
99  *\r
100  * \param spi  Pointer to an Spi instance.\r
101  * \param sources Bitwise OR of selected interrupt sources.\r
102  */\r
103 extern void SPI_EnableIt( Spi* spi, uint32_t dwSources )\r
104 {\r
105     spi->SPI_IER = dwSources ;\r
106 }\r
107 \r
108 /**\r
109  * \brief Disables one or more interrupt sources of a SPI peripheral.\r
110  *\r
111  * \param spi  Pointer to an Spi instance.\r
112  * \param sources Bitwise OR of selected interrupt sources.\r
113  */\r
114 extern void SPI_DisableIt( Spi* spi, uint32_t dwSources )\r
115 {\r
116     spi->SPI_IDR = dwSources ;\r
117 }\r
118 \r
119 /**\r
120  * \brief Configures a SPI peripheral as specified. The configuration can be computed\r
121  * using several macros (see \ref spi_configuration_macros).\r
122  *\r
123  * \param spi  Pointer to an Spi instance.\r
124  * \param id   Peripheral ID of the SPI.\r
125  * \param configuration  Value of the SPI configuration register.\r
126  */\r
127 extern void SPI_Configure( Spi* spi, uint32_t dwId, uint32_t dwConfiguration )\r
128 {\r
129     PMC_EnablePeripheral( dwId ) ;\r
130     \r
131     spi->SPI_CR = SPI_CR_SPIDIS ;\r
132 \r
133     /* Execute a software reset of the SPI twice */\r
134     spi->SPI_CR = SPI_CR_SWRST ;\r
135     spi->SPI_CR = SPI_CR_SWRST ;\r
136     spi->SPI_MR = dwConfiguration ;\r
137 }\r
138 \r
139 /**\r
140  * \brief Configures SPI chip select.\r
141  *\r
142  * \param spi  Pointer to an Spi instance.\r
143  * \param cS  Chip select of NPSCx.\r
144  */\r
145 extern void SPI_ChipSelect( Spi* spi, uint8_t cS)\r
146 {\r
147     spi->SPI_MR |= SPI_MR_PCS_Msk ;\r
148     spi->SPI_MR &= ~(SPI_MR_PCS ( cS )) ;\r
149 }\r
150 \r
151 /**\r
152  * \brief Configures SPI Mode Register.\r
153  *\r
154  * \param spi  Pointer to an Spi instance.\r
155  * \param configuration  Value of the SPI mode register.\r
156  */\r
157 extern void SPI_SetMode( Spi* spi, \r
158                          uint32_t dwConfiguration )\r
159 {\r
160     spi->SPI_MR = dwConfiguration ;\r
161 }\r
162 \r
163 /**\r
164  * \brief Configures SPI to release last used CS line.\r
165  *\r
166  * \param spi  Pointer to an Spi instance.\r
167  */\r
168 extern void SPI_ReleaseCS( Spi* spi )\r
169 {\r
170     spi->SPI_CR = SPI_CR_LASTXFER ;\r
171 }\r
172 \r
173 \r
174 /**\r
175  * \brief Configures a chip select of a SPI peripheral. The chip select configuration\r
176  * is computed using several macros (see \ref spi_configuration_macros).\r
177  *\r
178  * \param spi   Pointer to an Spi instance.\r
179  * \param npcs  Chip select to configure (0, 1, 2 or 3).\r
180  * \param configuration  Desired chip select configuration.\r
181  */\r
182 void SPI_ConfigureNPCS( Spi* spi, uint32_t dwNpcs, uint32_t dwConfiguration )\r
183 {\r
184     spi->SPI_CSR[dwNpcs] = dwConfiguration ;\r
185 }\r
186 \r
187 /**\r
188  * \brief Configures a chip select active mode of a SPI peripheral.\r
189  *\r
190  * \param spi   Pointer to an Spi instance.\r
191  * \param dwNpcs  Chip select to configure (0, 1, 2 or 3).\r
192  * \param bReleaseOnLast CS controlled by last transfer.\r
193  *                       SPI_ReleaseCS() is used to deactive CS. \r
194  */\r
195 void SPI_ConfigureCSMode( Spi* spi, uint32_t dwNpcs, uint32_t bReleaseOnLast )\r
196 {\r
197     if (bReleaseOnLast)\r
198     {\r
199         spi->SPI_CSR[dwNpcs] |=  SPI_CSR_CSAAT;\r
200     }\r
201     else\r
202     {\r
203         spi->SPI_CSR[dwNpcs] &= ~SPI_CSR_CSAAT;\r
204     }\r
205 }\r
206 \r
207 /**\r
208  * \brief Get the current status register of the given SPI peripheral.\r
209  * \note This resets the internal value of the status register, so further\r
210  * read may yield different values.\r
211  * \param spi   Pointer to a Spi instance.\r
212  * \return  SPI status register.\r
213  */\r
214 extern uint32_t SPI_GetStatus( Spi* spi )\r
215 {\r
216     return spi->SPI_SR ;\r
217 }\r
218 \r
219 /**\r
220  * \brief Reads and returns the last word of data received by a SPI peripheral. This\r
221  * method must be called after a successful SPI_Write call.\r
222  *\r
223  * \param spi  Pointer to an Spi instance.\r
224  *\r
225  * \return readed data.\r
226  */\r
227 extern uint32_t SPI_Read( Spi* spi )\r
228 {\r
229     while ( (spi->SPI_SR & SPI_SR_RDRF) == 0 ) ;\r
230 \r
231     return spi->SPI_RDR & 0xFFFF ;\r
232 }\r
233 \r
234 /**\r
235  * \brief Sends data through a SPI peripheral. If the SPI is configured to use a fixed\r
236  * peripheral select, the npcs value is meaningless. Otherwise, it identifies\r
237  * the component which shall be addressed.\r
238  *\r
239  * \param spi   Pointer to an Spi instance.\r
240  * \param npcs  Chip select of the component to address (0, 1, 2 or 3).\r
241  * \param data  Word of data to send.\r
242  */\r
243 extern void SPI_Write( Spi* spi, uint32_t dwNpcs, uint16_t wData )\r
244 {\r
245     /* Send data */\r
246     while ( (spi->SPI_SR & SPI_SR_TXEMPTY) == 0 ) ;\r
247     spi->SPI_TDR = wData | SPI_PCS( dwNpcs ) ;\r
248     while ( (spi->SPI_SR & SPI_SR_TDRE) == 0 ) ;\r
249 }\r
250 \r
251 /**\r
252  * \brief Sends last data through a SPI peripheral.\r
253  * If the SPI is configured to use a fixed peripheral select, the npcs value is\r
254  * meaningless. Otherwise, it identifies the component which shall be addressed.\r
255  *\r
256  * \param spi   Pointer to an Spi instance.\r
257  * \param npcs  Chip select of the component to address (0, 1, 2 or 3).\r
258  * \param data  Word of data to send.\r
259  */\r
260 extern void SPI_WriteLast( Spi* spi, uint32_t dwNpcs, uint16_t wData )\r
261 {\r
262     /* Send data */\r
263     while ( (spi->SPI_SR & SPI_SR_TXEMPTY) == 0 ) ;\r
264     spi->SPI_TDR = wData | SPI_PCS( dwNpcs ) | SPI_TDR_LASTXFER ;\r
265     while ( (spi->SPI_SR & SPI_SR_TDRE) == 0 ) ;\r
266 }\r
267 \r
268 /**\r
269  * \brief Check if SPI transfer finish.\r
270  *\r
271  * \param spi  Pointer to an Spi instance.\r
272  *\r
273  * \return Returns 1 if there is no pending write operation on the SPI; otherwise\r
274  * returns 0.\r
275  */\r
276 extern uint32_t SPI_IsFinished( Spi* spi )\r
277 {\r
278     return ((spi->SPI_SR & SPI_SR_TXEMPTY) != 0) ;\r
279 }\r
280 \r