1 /*!
2  * @file        apm32s10x_spi.c
3  *
4  * @brief       This file provides all the SPI firmware functions
5  *
6  * @version     V1.0.1
7  *
8  * @date        2022-12-31
9  *
10  * @attention
11  *
12  *  Copyright (C) 2022-2023 Geehy Semiconductor
13  *
14  *  You may not use this file except in compliance with the
15  *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
16  *
17  *  The program is only for reference, which is distributed in the hope
18  *  that it will be usefull and instructional for customers to develop
19  *  their software. Unless required by applicable law or agreed to in
20  *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
21  *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
22  *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
23  *  and limitations under the License.
24  */
25 
26 /* Includes */
27 #include "apm32s10x_spi.h"
28 #include "apm32s10x_rcm.h"
29 
30 /** @addtogroup APM32S10x_StdPeriphDriver
31   @{
32 */
33 
34 /** @addtogroup SPI_Driver SPI Driver
35   @{
36 */
37 
38 /** @defgroup SPI_Functions Functions
39   @{
40 */
41 
42 /*!
43  * @brief     Reset the specified SPIx peripheral
44  *
45  * @param     spi: The SPIx can be 1,2
46  *
47  * @retval    None
48  */
SPI_Reset(SPI_T * spi)49 void SPI_Reset(SPI_T* spi)
50 {
51     if (spi == SPI1)
52     {
53         RCM_EnableAPB2PeriphReset(RCM_APB2_PERIPH_SPI1);
54         RCM_DisableAPB2PeriphReset(RCM_APB2_PERIPH_SPI1);
55     }
56     else if (spi == SPI2)
57     {
58         RCM_EnableAPB1PeriphReset(RCM_APB1_PERIPH_SPI2);
59         RCM_DisableAPB1PeriphReset(RCM_APB1_PERIPH_SPI2);
60     }
61 }
62 
63 /*!
64  * @brief     Configure the SPI peripheral according to the specified parameters in the spiConfig
65  *
66  * @param     spi: The SPIx can be 1,2
67  *
68  * @param     spiConfig: pointer to a SPI_Config_T structure
69  *
70  * @retval    None
71  */
SPI_Config(SPI_T * spi,SPI_Config_T * spiConfig)72 void SPI_Config(SPI_T* spi, SPI_Config_T* spiConfig)
73 {
74     spi->CTRL1 &= 0x3040;
75     spi->CTRL1 |= (uint16_t)((uint32_t)spiConfig->direction | spiConfig->mode |
76                              spiConfig->length | spiConfig->polarity |
77                              spiConfig->phase | spiConfig->nss |
78                              spiConfig->baudrateDiv | spiConfig->firstBit);
79     spi->CRCPOLY = spiConfig->crcPolynomial;
80 }
81 
82 /*!
83  * @brief     Fill each SPI_Config_T member with its default value
84  *
85  * @param     spiConfig: pointer to a SPI_Config_T structure
86  *
87  * @retval    None
88  */
SPI_ConfigStructInit(SPI_Config_T * spiConfig)89 void SPI_ConfigStructInit(SPI_Config_T* spiConfig)
90 {
91     spiConfig->direction = SPI_DIRECTION_2LINES_FULLDUPLEX;
92     spiConfig->mode = SPI_MODE_SLAVE;
93     spiConfig->length = SPI_DATA_LENGTH_8B;
94     spiConfig->polarity = SPI_CLKPOL_LOW;
95     spiConfig->phase = SPI_CLKPHA_1EDGE;
96     spiConfig->nss = SPI_NSS_HARD;
97     spiConfig->baudrateDiv = SPI_BAUDRATE_DIV_2;
98     spiConfig->firstBit = SPI_FIRSTBIT_MSB;
99     spiConfig->crcPolynomial = 7;
100 }
101 
102 /*!
103  * @brief     Enable the specified SPI peripheral
104  *
105  * @param     spi: The SPIx can be 1,2
106  *
107  * @retval    None
108  */
SPI_Enable(SPI_T * spi)109 void SPI_Enable(SPI_T* spi)
110 {
111     spi->CTRL1_B.SPIEN = BIT_SET;
112 }
113 
114 /*!
115  * @brief     Disable the specified SPI peripheral
116  *
117  * @param     spi: The SPIx can be 1,2
118  *
119  * @retval    None
120  */
SPI_Disable(SPI_T * spi)121 void SPI_Disable(SPI_T* spi)
122 {
123     spi->CTRL1_B.SPIEN = BIT_RESET;
124 }
125 
126 /*!
127  * @brief     Enable the SPIx DMA interface.
128  *
129  * @param     spi: The SPIx can be 1,2
130  *
131  * @param     dmaReq: specify the SPI DMA transfer request
132  *              The parameter can be one of following values:
133  *              @arg SPI_DMA_REQ_TX: Tx buffer DMA transfer request
134  *              @arg SPI_DMA_REQ_RX: Rx buffer DMA transfer request
135  * @retval    None
136  */
SPI_EnableDMA(SPI_T * spi,SPI_DMA_REQ_T dmaReq)137 void SPI_EnableDMA(SPI_T* spi, SPI_DMA_REQ_T dmaReq)
138 {
139     if (dmaReq == SPI_DMA_REQ_TX)
140     {
141         spi->CTRL2_B.TXDEN = ENABLE;
142     }
143     else
144     {
145         spi->CTRL2_B.RXDEN = ENABLE;
146     }
147 }
148 
149 /*!
150  * @brief     Disable the SPIx DMA interface.
151  *
152  * @param     spi: The SPIx can be 1,2
153  *
154  * @param     dmaReq: specify the SPI DMA transfer request
155  *              The parameter can be one of following values:
156  *              @arg SPI_DMA_REQ_TX: Tx buffer DMA transfer request
157  *              @arg SPI_DMA_REQ_RX: Rx buffer DMA transfer request
158  * @retval    None
159  */
SPI_DisableDMA(SPI_T * spi,SPI_DMA_REQ_T dmaReq)160 void SPI_DisableDMA(SPI_T* spi, SPI_DMA_REQ_T dmaReq)
161 {
162     if (dmaReq == SPI_DMA_REQ_TX)
163     {
164         spi->CTRL2_B.TXDEN = DISABLE;
165     }
166     else
167     {
168         spi->CTRL2_B.RXDEN = DISABLE;
169     }
170 }
171 
172 /*!
173  * @brief     Transmit a Data through the SPIx peripheral.
174  *
175  * @param     spi: The SPIx can be 1,2
176  *
177  * @param     data: Data to be transmitted
178  *
179  * @retval    None
180  */
SPI_TxData(SPI_T * spi,uint16_t data)181 void SPI_TxData(SPI_T* spi, uint16_t data)
182 {
183     spi->DATA = data;
184 }
185 
186 /*!
187  * @brief     Return the most recent received data by the SPIx peripheral.
188  *
189  * @param     spi: The SPIx can be 1,2
190  *
191  * @retval    data :The value of the received data
192  *
193  * @retval    None
194  */
SPI_RxData(SPI_T * spi)195 uint16_t SPI_RxData(SPI_T* spi)
196 {
197     return spi->DATA;
198 }
199 
200 /*!
201  * @brief     Set the SPI NSS internal by Software
202  *
203  * @param     spi: The SPIx can be 1,2
204  *
205  * @retval    None
206  */
SPI_SetSoftwareNSS(SPI_T * spi)207 void SPI_SetSoftwareNSS(SPI_T* spi)
208 {
209     spi->CTRL1_B.ISSEL = BIT_SET;
210 }
211 
212 /*!
213  * @brief     Reset the SPI NSS internal by Software
214  *
215  * @param     spi: The SPIx can be 1,2
216  *
217  * @retval    None
218  */
SPI_ResetSoftwareNSS(SPI_T * spi)219 void SPI_ResetSoftwareNSS(SPI_T* spi)
220 {
221     spi->CTRL1_B.ISSEL = BIT_RESET;
222 }
223 
224 /*!
225  * @brief     Enable the specified SPI SS output
226  *
227  * @param     spi: The SPIx can be 1,2
228  *
229  * @retval    None
230  */
SPI_EnableSSOutput(SPI_T * spi)231 void SPI_EnableSSOutput(SPI_T* spi)
232 {
233     spi->CTRL2_B.SSOEN = BIT_SET;
234 }
235 
236 /*!
237  * @brief     Disable the specified SPI SS output
238  *
239  * @param     spi: The SPIx can be 1,2
240  *
241  * @retval    None
242  */
SPI_DisableSSOutput(SPI_T * spi)243 void SPI_DisableSSOutput(SPI_T* spi)
244 {
245     spi->CTRL2_B.SSOEN = BIT_RESET;
246 }
247 
248 /*!
249  * @brief     Configure the specified SPI data size
250  *
251  * @param     spi: The SPIx can be 1,2
252  *
253  * @param     length: specify the SPI data size.
254  *              This parameter can be one of the following values:
255  *              @arg SPI_DATA_LENGTH_16B: Set data frame format to 16bit
256  *              @arg SPI_DATA_LENGTH_8B : Set data frame format to 8bit
257  *
258  * @retval    None
259  */
SPI_ConfigDataSize(SPI_T * spi,SPI_DATA_LENGTH_T length)260 void SPI_ConfigDataSize(SPI_T* spi, SPI_DATA_LENGTH_T length)
261 {
262     spi->CTRL1_B.DFLSEL = BIT_RESET;
263     spi->CTRL1 |= length;
264 }
265 
266 /*!
267  * @brief     Transmit CRC value
268  *
269  * @param     spi: The SPIx can be 1,2
270  *
271  * @retval    None
272  */
SPI_TxCRC(SPI_T * spi)273 void SPI_TxCRC(SPI_T* spi)
274 {
275     spi->CTRL1_B.CRCNXT = BIT_SET;
276 }
277 
278 /*!
279  * @brief     Enable the specified SPI CRC value calculation of the transferred bytes
280  *
281  * @param     spi: The SPIx can be 1,2
282  *
283  * @retval    None
284  */
SPI_EnableCRC(SPI_T * spi)285 void SPI_EnableCRC(SPI_T* spi)
286 {
287     spi->CTRL1_B.CRCEN = BIT_SET;
288 }
289 
290 /*!
291  * @brief     Disable the specified SPI CRC value calculation of the transferred bytes
292  *
293  * @param     spi: The SPIx can be 1,2
294  *
295  * @retval    None
296  */
SPI_DisableCRC(SPI_T * spi)297 void SPI_DisableCRC(SPI_T* spi)
298 {
299     spi->CTRL1_B.CRCEN = BIT_RESET;
300 }
301 
302 /*!
303  * @brief     Read the specified SPI transmit CRC register value
304  *
305  * @param     spi: The SPIx can be 1,2
306  *
307  * @retval    The SPI transmit CRC register value
308  */
SPI_ReadTxCRC(SPI_T * spi)309 uint16_t SPI_ReadTxCRC(SPI_T* spi)
310 {
311     return spi->TXCRC_B.TXCRC;
312 }
313 
314 /*!
315  * @brief     Read the specified SPI receive CRC register value
316  *
317  * @param     spi: The SPIx can be 1,2
318  *
319  * @retval    The SPI receive CRC register value
320  */
SPI_ReadRxCRC(SPI_T * spi)321 uint16_t SPI_ReadRxCRC(SPI_T* spi)
322 {
323     return spi->RXCRC_B.RXCRC;
324 }
325 
326 /*!
327  * @brief     Read the specified SPI CRC Polynomial register value
328  *
329  * @param     spi: The SPIx can be 1,2
330  *
331  * @retval    The SPI CRC Polynomial register value
332  */
SPI_ReadCRCPolynomial(SPI_T * spi)333 uint16_t SPI_ReadCRCPolynomial(SPI_T* spi)
334 {
335     return spi->CRCPOLY_B.CRCPOLY;
336 }
337 
338 /*!
339  * @brief     Configure the specified SPI data transfer direction
340  *
341  * @param     spi: The SPIx can be 1,2
342  *
343  * @param     direction: Select the SPI data transfer direction
344  *              The parameter can be one of following values:
345  *              @arg SPI_DIRECTION_RX: Selects Rx receive direction
346  *              @arg SPI_DIRECTION_TX: Selects Tx transmission direction
347  *
348  * @retval    None
349  */
SPI_ConfigBiDirectionalLine(SPI_T * spi,SPI_DIRECTION_SELECT_T direction)350 void SPI_ConfigBiDirectionalLine(SPI_T* spi, SPI_DIRECTION_SELECT_T direction)
351 {
352     if (direction == SPI_DIRECTION_TX)
353     {
354         spi->CTRL1 |= SPI_DIRECTION_TX;
355     }
356     else
357     {
358         spi->CTRL1 &= SPI_DIRECTION_RX;
359     }
360 }
361 
362 /*!
363  * @brief     Enable the specified SPI interrupts.
364  *
365  * @param     spi: The SPIx can be 1,2
366  *
367  * @param     interrupt: specify the TMR interrupts sources
368  *              The parameter can be one of following values:
369  *              @arg SPI_INT_TXBE: Tx buffer empty interrupt
370  *              @arg SPI_INT_RXBNE: Rx buffer not empty interrupt
371  *              @arg SPI_INT_ERR: Error interrupt
372  *
373  * @retval    None
374  */
SPI_EnableInterrupt(SPI_T * spi,SPI_INT_T interrupt)375 void SPI_EnableInterrupt(SPI_T* spi, SPI_INT_T interrupt)
376 {
377     spi->CTRL2 |= (interrupt >> 8);
378 }
379 
380 /*!
381  * @brief     Disable the specified SPI interrupts.
382  *
383  * @param     spi: The SPIx can be 1,2
384  *
385  * @param     interrupt: specify the TMR interrupts sources
386  *              The parameter can be one of following values:
387  *              @arg SPI_INT_TXBE: Tx buffer empty interrupt
388  *              @arg SPI_INT_RXBNE: Rx buffer not empty interrupt
389  *              @arg SPI_INT_ERR: Error interrupt
390  * @retval    None
391  */
SPI_DisableInterrupt(SPI_T * spi,SPI_INT_T interrupt)392 void SPI_DisableInterrupt(SPI_T* spi, SPI_INT_T interrupt)
393 {
394     spi->CTRL2 &= ~(interrupt >> 8);
395 }
396 
397 /*!
398  * @brief     Check whether the specified SPI flag is set or not.
399  *
400  * @param     spi: The SPIx can be 1,2
401  *
402  * @param     flag: specify the SPI flag to check
403  *              The parameter can be one of following values:
404  *              @arg SPI_FLAG_RXBNE: Receive buffer not empty flag
405  *              @arg SPI_FLAG_TXBE: Transmit buffer empty flag
406  *              @arg SPI_FLAG_SCHDIR: Side Channel flag
407  *              @arg SPI_FLAG_UDR: Underrun Error flag
408  *              @arg SPI_FLAG_CRCE: CRC Error flag
409  *              @arg SPI_FLAG_ME: Mode Error flag
410  *              @arg SPI_FLAG_OVR: Overrun flag
411  *              @arg SPI_FLAG_BSY: Busy flag
412  *
413  * @retval     SET or RESET
414  */
SPI_ReadStatusFlag(SPI_T * spi,SPI_FLAG_T flag)415 uint8_t SPI_ReadStatusFlag(SPI_T* spi, SPI_FLAG_T flag)
416 {
417     if ((spi->STS & flag) != RESET)
418     {
419         return SET;
420     }
421     else
422     {
423         return RESET;
424     }
425 }
426 
427 /*!
428  * @brief     Clear the SPIx CRC Error flag
429  *
430  * @param     spi: The SPIx can be 1,2
431  *
432  * @param     flag: only clear SPI_FLAG_CRCE(CRC Error flag)
433  *
434  * @retval    None
435  *
436  * @note      1)SPI_FLAG_OVR: (OverRun error) flag is cleared by software sequence:
437  *              a read operation to SPI_DATA register (SPI_RxData())
438  *              followed by a read operation to SPI_STS register (SPI_ReadStatusFlag()).
439  *            2)SPI_FLAG_UDR: (UnderRun error) flag is cleared:
440  *              a read operation to SPI_STS register (SPI_ReadStatusFlag()).
441  *            3)SPI_FLAG_ME: (Mode Fault) flag is cleared by software sequence:
442  *              a read/write operation to SPI_STS register (SPI_ReadStatusFlag())
443  *              followed by a write operation to SPI_CTRL1 register (SPI_Enable()).
444  */
SPI_ClearStatusFlag(SPI_T * spi,SPI_FLAG_T flag)445 void SPI_ClearStatusFlag(SPI_T* spi, SPI_FLAG_T flag)
446 {
447     spi->STS_B.CRCEFLG = BIT_RESET;
448 }
449 
450 /*!
451  * @brief     Check whether the specified SPI interrupt has occurred or not.
452  *
453  * @param     spi: The SPIx can be 1,2
454  *
455  * @param     flag: specify the SPI interrupt flag to check.
456  *              The parameter can be one of following values:
457  *              @arg SPI_INT_RXBNE : Receive buffer not empty interrupt flag
458  *              @arg SPI_INT_TXBE  : Transmit buffer empty interrupt flag
459  *              @arg SPI_INT_OVR   : Overrun interrupt flag
460  *              @arg SPI_INT_CRCE  : CRC Error interrupt flag
461  *              @arg SPI_INT_ME    :  Mode Error interrupt flag
462  *              @arg SPI_INT_UDR   : Underrun Error interrupt flag
463  *
464  * @retval       SET or RESET
465  */
SPI_ReadIntFlag(SPI_T * spi,SPI_INT_T flag)466 uint8_t SPI_ReadIntFlag(SPI_T* spi, SPI_INT_T flag)
467 {
468     uint32_t intEnable;
469     uint32_t intStatus;
470 
471     intEnable = (uint32_t)(spi->CTRL2 & (flag >> 8));
472     intStatus = (uint32_t)(spi->STS & flag);
473 
474     if (intEnable && intStatus)
475     {
476         return SET;
477     }
478 
479     return RESET;
480 }
481 
482 /*!
483  * @brief     Clear the SPIx CRC Error interrupt flag
484  *
485  * @param     spi: The SPIx can be 1,2
486  *
487  * @param     flag: only clear SPI_INT_CRCE(CRC Error interrupt flag)
488  *
489  * @retval    None
490  *
491  * @note      1)SPI_INT_OVR: (OverRun interrupt error) flag is cleared by software sequence:
492  *              a read operation to SPI_DATA register (SPI_RxData())
493  *              followed by a read operation to SPI_STS register (SPI_ReadIntFlag()).
494  *            2)SPI_INT_UDR: (UnderRun interrupt error) flag is cleared:
495  *              a read operation to SPI_STS register (SPI_ReadIntFlag()).
496  *            3)SPI_INT_ME: (Mode interrupt Fault) flag is cleared by software sequence:
497  *              a read/write operation to SPI_STS register (SPI_ReadIntFlag())
498  *              followed by a write operation to SPI_CTRL1 register (SPI_Enable()).
499  */
SPI_ClearIntFlag(SPI_T * spi,SPI_INT_T flag)500 void SPI_ClearIntFlag(SPI_T* spi, SPI_INT_T flag)
501 {
502     spi->STS_B.CRCEFLG = BIT_RESET;
503 }
504 
505 /**@} end of group SPI_Functions */
506 /**@} end of group SPI_Driver */
507 /**@} end of group APM32S10x_StdPeriphDriver */
508