1 /*!
2  * @file        apm32f10x_spi.c
3  *
4  * @brief       This file provides all the SPI firmware functions
5  *
6  * @version     V1.0.4
7  *
8  * @date        2022-12-01
9  *
10  * @attention
11  *
12  *  Copyright (C) 2020-2022 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 useful 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 #include "apm32f10x_spi.h"
27 #include "apm32f10x_rcm.h"
28 
29 /** @addtogroup APM32F10x_StdPeriphDriver
30   @{
31 */
32 
33 /** @addtogroup SPI_Driver SPI Driver
34   * @brief SPI driver modules
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,3
46  *
47  * @retval    None
48  */
SPI_I2S_Reset(SPI_T * spi)49 void SPI_I2S_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     else if (spi == SPI3)
62     {
63         RCM_EnableAPB1PeriphReset(RCM_APB1_PERIPH_SPI3);
64         RCM_DisableAPB1PeriphReset(RCM_APB1_PERIPH_SPI3);
65     }
66 }
67 
68 /*!
69  * @brief     Configures the SPI peripheral according to the specified parameters in the spiConfig
70  *
71  * @param     spi: The SPIx can be 1,2,3
72  *
73  * @param     spiConfig: pointer to a SPI_Config_T structure
74  *
75  * @retval    None
76  */
SPI_Config(SPI_T * spi,SPI_Config_T * spiConfig)77 void SPI_Config(SPI_T* spi, SPI_Config_T* spiConfig)
78 {
79     spi->CTRL1 &= 0x3040;
80     spi->CTRL1 |= (uint16_t)((uint32_t)spiConfig->direction | spiConfig->mode |
81                              spiConfig->length | spiConfig->polarity |
82                              spiConfig->phase | spiConfig->nss |
83                              spiConfig->baudrateDiv | spiConfig->firstBit);
84     spi->CRCPOLY = spiConfig->crcPolynomial;
85 }
86 
87 /*!
88  * @brief     Configures the I2S peripheral according to the specified parameters in the spiConfig
89  *
90  * @param     spi: The SPIx can be 2,3
91  *
92  * @param     i2sConfig: pointer to a I2S_Config_T structure
93  *
94  * @retval    None
95  */
I2S_Config(SPI_T * spi,I2S_Config_T * i2sConfig)96 void I2S_Config(SPI_T* spi, I2S_Config_T* i2sConfig)
97 {
98     uint16_t i2sDiv = 2, i2sOdd = 0, packetSize = 1;
99     uint32_t tmp = 0;
100     uint32_t sysClock = 0;
101 
102     /* Clear MODESEL, I2SEN, I2SMOD, PFSSEL, I2SSSEL, CPOL, DATALEN and CHLEN bits */
103     spi->I2SCFG &= 0xF040;
104     spi->I2SPSC = 0x0002;
105 
106     if (i2sConfig->audioDiv == I2S_AUDIO_DIV_DEFAULT)
107     {
108         spi->I2SPSC_B.ODDPSC = 0;
109         spi->I2SPSC_B.I2SPSC = 2;
110     }
111     else
112     {
113         if (i2sConfig->length == I2S_DATA_LENGHT_16B)
114         {
115             packetSize = 1;
116         }
117         else
118         {
119             packetSize = 2;
120         }
121 
122         sysClock = RCM_ReadSYSCLKFreq();
123 
124         if (i2sConfig->MCLKOutput == I2S_MCLK_OUTPUT_ENABLE)
125         {
126             tmp = (uint16_t)(((((sysClock / 256) * 10) / i2sConfig ->audioDiv)) + 5);
127         }
128         else
129         {
130             tmp = (uint16_t)(((((sysClock / (32 * packetSize)) * 10) / i2sConfig ->audioDiv)) + 5);
131         }
132         tmp = tmp / 10;
133 
134         i2sOdd = (uint16_t)(tmp & (uint16_t)0x0001);
135         i2sDiv = (uint16_t)((tmp - i2sOdd) / 2);
136 
137         if ((i2sDiv < 2) || (i2sDiv > 0xFF))
138         {
139             i2sDiv = 2;
140             i2sOdd = 0;
141         }
142     }
143 
144     spi->I2SPSC_B.I2SPSC = i2sDiv;
145     spi->I2SPSC_B.ODDPSC = i2sOdd;
146     spi->I2SPSC |= i2sConfig->MCLKOutput;
147 
148     spi->I2SCFG = (uint32_t)i2sConfig->mode | \
149                   (uint32_t)i2sConfig->standard | \
150                   (uint32_t)i2sConfig->length | \
151                   (uint32_t)i2sConfig->polarity;
152 
153     /* select I2S mode */
154     spi->I2SCFG_B.MODESEL = BIT_SET;
155 }
156 
157 /*!
158  * @brief     Fills each SPI_Config_T member with its default value
159  *
160  * @param     spiConfig: pointer to a SPI_Config_T structure
161  *
162  * @retval    None
163  */
SPI_ConfigStructInit(SPI_Config_T * spiConfig)164 void SPI_ConfigStructInit(SPI_Config_T* spiConfig)
165 {
166     spiConfig->direction = SPI_DIRECTION_2LINES_FULLDUPLEX;
167     spiConfig->mode = SPI_MODE_SLAVE;
168     spiConfig->length = SPI_DATA_LENGTH_8B;
169     spiConfig->polarity = SPI_CLKPOL_LOW;
170     spiConfig->phase = SPI_CLKPHA_1EDGE;
171     spiConfig->nss = SPI_NSS_HARD;
172     spiConfig->baudrateDiv = SPI_BAUDRATE_DIV_2;
173     spiConfig->firstBit = SPI_FIRSTBIT_MSB;
174     spiConfig->crcPolynomial = 7;
175 }
176 
177 /*!
178  * @brief     Fills each I2S_Config_T member with its default value
179  *
180  * @param     i2sConfig: pointer to a I2S_Config_T structure
181  *
182  * @retval    None
183  */
I2S_ConfigStructInit(I2S_Config_T * i2sConfig)184 void I2S_ConfigStructInit(I2S_Config_T* i2sConfig)
185 {
186     i2sConfig->mode = I2S_MODE_SLAVE_TX;
187     i2sConfig->standard = I2S_STANDARD_PHILLIPS;
188     i2sConfig->length = I2S_DATA_LENGHT_16B;
189     i2sConfig->MCLKOutput = I2S_MCLK_OUTPUT_DISABLE;
190     i2sConfig->audioDiv = I2S_AUDIO_DIV_DEFAULT;
191     i2sConfig->polarity = I2S_CLKPOL_LOW;
192 }
193 /*!
194  * @brief     Enable the specified SPI peripheral
195  *
196  * @param     spi: The SPIx can be 1,2,3
197  *
198  * @retval    None
199  */
SPI_Enable(SPI_T * spi)200 void SPI_Enable(SPI_T* spi)
201 {
202     spi->CTRL1_B.SPIEN = BIT_SET;
203 }
204 
205 /*!
206  * @brief     Disable the specified SPI peripheral
207  *
208  * @param     spi: The SPIx can be 1,2,3
209  *
210  * @retval    None
211  */
SPI_Disable(SPI_T * spi)212 void SPI_Disable(SPI_T* spi)
213 {
214     spi->CTRL1_B.SPIEN = BIT_RESET;
215 }
216 
217 /*!
218  * @brief     Enable the specified I2S peripheral
219  *
220  * @param     spi: The I2S can be SPI2,SPI3
221  *
222  * @retval    None
223  */
I2S_Enable(SPI_T * spi)224 void I2S_Enable(SPI_T* spi)
225 {
226     spi->I2SCFG_B.I2SEN = BIT_SET;
227 }
228 
229 /*!
230  * @brief     Disable the specified I2S peripheral
231  *
232  * @param     spi: The I2S can be SPI2,SPI3
233  *
234  * @retval    None
235  */
I2S_Disable(SPI_T * spi)236 void I2S_Disable(SPI_T* spi)
237 {
238     spi->I2SCFG_B.I2SEN = BIT_RESET;
239 }
240 
241 /*!
242  * @brief     Enable the SPIx/I2Sx DMA interface.
243  *
244  * @param     spi: The SPIx can be 1,2,3, When the I2S can be 2,3
245  *
246  * @param     dmaReq: specifies the SPI/I2S DMA transfer request
247  *                    The parameter can be one of following values:
248  *                    @arg SPI_I2S_DMA_REQ_TX: Tx buffer DMA transfer request
249  *                    @arg SPI_I2S_DMA_REQ_RX: Rx buffer DMA transfer request
250  * @retval    None
251  */
SPI_I2S_EnableDMA(SPI_T * spi,SPI_I2S_DMA_REQ_T dmaReq)252 void SPI_I2S_EnableDMA(SPI_T* spi, SPI_I2S_DMA_REQ_T dmaReq)
253 {
254     if (dmaReq == SPI_I2S_DMA_REQ_TX)
255     {
256         spi->CTRL2_B.TXDEN = ENABLE;
257     }
258     else
259     {
260         spi->CTRL2_B.RXDEN = ENABLE;
261     }
262 }
263 
264 /*!
265  * @brief     Disable the SPIx/I2Sx DMA interface.
266  *
267  * @param     spi: The SPIx can be 1,2,3, When the I2S can be 2,3
268  *
269  * @param     dmaReq: specifies the SPI/I2S DMA transfer request
270  *                    The parameter can be one of following values:
271  *                    @arg SPI_I2S_DMA_REQ_TX: Tx buffer DMA transfer request
272  *                    @arg SPI_I2S_DMA_REQ_RX: Rx buffer DMA transfer request
273  * @retval    None
274  */
SPI_I2S_DisableDMA(SPI_T * spi,SPI_I2S_DMA_REQ_T dmaReq)275 void SPI_I2S_DisableDMA(SPI_T* spi, SPI_I2S_DMA_REQ_T dmaReq)
276 {
277     if (dmaReq == SPI_I2S_DMA_REQ_TX)
278     {
279         spi->CTRL2_B.TXDEN = DISABLE;
280     }
281     else
282     {
283         spi->CTRL2_B.RXDEN = DISABLE;
284     }
285 }
286 
287 /*!
288  * @brief     Transmit a Data through the SPIx/I2Sx peripheral.
289  *
290  * @param     spi: The SPIx can be 1,2,3, When the I2S can be 2,3
291  *
292  * @param     data: Data to be transmitted
293  *
294  * @retval    None
295  */
SPI_I2S_TxData(SPI_T * spi,uint16_t data)296 void SPI_I2S_TxData(SPI_T* spi, uint16_t data)
297 {
298     spi->DATA = data;
299 }
300 
301 /*!
302  * @brief     Return the most recent received data by the SPIx/I2Sx peripheral.
303  *
304  * @param     spi: The SPIx can be 1,2,3, When the I2S can be 2,3
305  *
306  * @retval    data :The value of the received data
307  *
308  * @retval    None
309  */
SPI_I2S_RxData(SPI_T * spi)310 uint16_t SPI_I2S_RxData(SPI_T* spi)
311 {
312     return spi->DATA;
313 }
314 
315 /*!
316  * @brief     Set the SPI NSS internal by Software
317  *
318  * @param     spi: The SPIx can be 1,2,3
319  *
320  * @retval    None
321  */
SPI_SetSoftwareNSS(SPI_T * spi)322 void SPI_SetSoftwareNSS(SPI_T* spi)
323 {
324     spi->CTRL1_B.ISSEL = BIT_SET;
325 }
326 
327 /*!
328  * @brief     Reset the SPI NSS internal by Software
329  *
330  * @param     spi: The SPIx can be 1,2,3
331  *
332  * @retval    None
333  */
SPI_ResetSoftwareNSS(SPI_T * spi)334 void SPI_ResetSoftwareNSS(SPI_T* spi)
335 {
336     spi->CTRL1_B.ISSEL = BIT_RESET;
337 }
338 
339 /*!
340  * @brief     Enable the specified SPI SS output
341  *
342  * @param     spi: The SPIx can be 1,2,3
343  *
344  * @retval    None
345  */
SPI_EnableSSOutput(SPI_T * spi)346 void SPI_EnableSSOutput(SPI_T* spi)
347 {
348     spi->CTRL2_B.SSOEN = BIT_SET;
349 }
350 
351 /*!
352  * @brief     Disable the specified SPI SS output
353  *
354  * @param     spi: The SPIx can be 1,2,3
355  *
356  * @retval    None
357  */
SPI_DisableSSOutput(SPI_T * spi)358 void SPI_DisableSSOutput(SPI_T* spi)
359 {
360     spi->CTRL2_B.SSOEN = BIT_RESET;
361 }
362 
363 /*!
364  * @brief     Configures the specified SPI data size
365  *
366  * @param     spi: The SPIx can be 1,2,3
367  *
368  * @param     length: specifies the SPI data size.
369  *                    This parameter can be one of the following values:
370  *                    @arg SPI_DATA_LENGTH_16B: Set data frame format to 16bit
371  *                    @arg SPI_DATA_LENGTH_8B : Set data frame format to 8bit
372  *
373  * @retval    None
374  */
SPI_ConfigDataSize(SPI_T * spi,SPI_DATA_LENGTH_T length)375 void SPI_ConfigDataSize(SPI_T* spi, SPI_DATA_LENGTH_T length)
376 {
377     spi->CTRL1_B.DFLSEL = BIT_RESET;
378     spi->CTRL1 |= length;
379 }
380 
381 /*!
382  * @brief     Transmit CRC value
383  *
384  * @param     spi: The SPIx can be 1,2,3
385  *
386  * @retval    None
387  */
SPI_TxCRC(SPI_T * spi)388 void SPI_TxCRC(SPI_T* spi)
389 {
390     spi->CTRL1_B.CRCNXT = BIT_SET;
391 }
392 
393 /*!
394  * @brief     Enable the specified SPI CRC value calculation of the transferred bytes
395  *
396  * @param     spi: The SPIx can be 1,2,3
397  *
398  * @retval    None
399  */
SPI_EnableCRC(SPI_T * spi)400 void SPI_EnableCRC(SPI_T* spi)
401 {
402     spi->CTRL1_B.CRCEN = BIT_SET;
403 }
404 
405 /*!
406  * @brief     Disable the specified SPI CRC value calculation of the transferred bytes
407  *
408  * @param     spi: The SPIx can be 1,2,3
409  *
410  */
SPI_DisableCRC(SPI_T * spi)411 void SPI_DisableCRC(SPI_T* spi)
412 {
413     spi->CTRL1_B.CRCEN = BIT_RESET;
414 }
415 
416 /*!
417  * @brief     Read the specified SPI transmit CRC register value
418  *
419  * @param     spi: The SPIx can be 1,2,3
420  *
421  * @retval    The SPI transmit CRC register value
422  */
SPI_ReadTxCRC(SPI_T * spi)423 uint16_t SPI_ReadTxCRC(SPI_T* spi)
424 {
425     return spi->TXCRC_B.TXCRC;
426 }
427 
428 /*!
429  * @brief     Read the specified SPI receive CRC register value
430  *
431  * @param     spi: The SPIx can be 1,2,3
432  *
433  * @retval    The SPI receive CRC register value
434  */
SPI_ReadRxCRC(SPI_T * spi)435 uint16_t SPI_ReadRxCRC(SPI_T* spi)
436 {
437     return spi->RXCRC_B.RXCRC;
438 }
439 
440 /*!
441  * @brief     Read the specified SPI CRC Polynomial register value
442  *
443  * @param     spi: The SPIx can be 1,2,3
444  *
445  * @retval    The SPI CRC Polynomial register value
446  */
SPI_ReadCRCPolynomial(SPI_T * spi)447 uint16_t SPI_ReadCRCPolynomial(SPI_T* spi)
448 {
449     return spi->CRCPOLY_B.CRCPOLY;
450 }
451 
452 /*!
453  * @brief     Configures the specified SPI data transfer direction
454  *
455  * @param     spi: The SPIx can be 1,2,3
456  *
457  * @param     direction: Select the SPI data transfer direction
458  *                       The parameter can be one of following values:
459  *                       @arg SPI_DIRECTION_RX: Selects Rx receive direction
460  *                       @arg SPI_DIRECTION_TX: Selects Tx transmission direction
461  * @retval    None
462  */
SPI_ConfigBiDirectionalLine(SPI_T * spi,SPI_DIRECTION_SELECT_T direction)463 void SPI_ConfigBiDirectionalLine(SPI_T* spi, SPI_DIRECTION_SELECT_T direction)
464 {
465     if (direction == SPI_DIRECTION_TX)
466     {
467         spi->CTRL1 |= SPI_DIRECTION_TX;
468     }
469     else
470     {
471         spi->CTRL1 &= SPI_DIRECTION_RX;
472     }
473 }
474 
475 /*!
476  * @brief     Enable the specified SPI/I2S interrupts.
477  *
478  * @param     spi: The SPIx can be 1,2,3, When the I2S can be 2,3
479  *
480  * @param     interrupt: specifies the TMR interrupts sources
481  *                       The parameter can be one of following values:
482  *                       @arg SPI_I2S_INT_TXBE: Tx buffer empty interrupt
483  *                       @arg SPI_I2S_INT_RXBNE: Rx buffer not empty interrupt
484  *                       @arg SPI_I2S_INT_ERR: Error interrupt
485  * @retval       None
486  */
SPI_I2S_EnableInterrupt(SPI_T * spi,SPI_I2S_INT_T interrupt)487 void SPI_I2S_EnableInterrupt(SPI_T* spi, SPI_I2S_INT_T interrupt)
488 {
489     spi->CTRL2 |= (interrupt >> 8);
490 }
491 
492 /*!
493  * @brief     Disable the specified SPI/I2S interrupts.
494  *
495  * @param     spi: The SPIx can be 1,2,3, When the I2S can be 2,3
496  *
497  * @param     interrupt: specifies the TMR interrupts sources
498  *                       The parameter can be one of following values:
499  *                       @arg SPI_I2S_INT_TXBE: Tx buffer empty interrupt
500  *                       @arg SPI_I2S_INT_RXBNE: Rx buffer not empty interrupt
501  *                       @arg SPI_I2S_INT_ERR: Error interrupt
502  * @retval    None
503  */
SPI_I2S_DisableInterrupt(SPI_T * spi,SPI_I2S_INT_T interrupt)504 void SPI_I2S_DisableInterrupt(SPI_T* spi, SPI_I2S_INT_T interrupt)
505 {
506     spi->CTRL2 &= ~(interrupt >> 8);
507 }
508 
509 /*!
510  * @brief     Check whether the specified SPI/I2S flag is set or not.
511  *
512  * @param     spi: The SPIx can be 1,2,3, When the I2S can be 2,3
513  *
514  * @param     flag: specifies the SPI/I2S flag to check
515  *                  The parameter can be one of following values:
516  *                  @arg SPI_FLAG_RXBNE: Receive buffer not empty flag
517  *                  @arg SPI_FLAG_TXBE: Transmit buffer empty flag
518  *                  @arg I2S_FLAG_SCHDIR: Side Channel flag
519  *                  @arg I2S_FLAG_UDR: Underrun Error flag
520  *                  @arg SPI_FLAG_CRCE: CRC Error flag
521  *                  @arg SPI_FLAG_ME: Mode Error flag
522  *                  @arg SPI_FLAG_OVR: Overrun flag
523  *                  @arg SPI_FLAG_BSY: Busy flag
524  *
525  * @retval     SET or RESET
526  */
SPI_I2S_ReadStatusFlag(SPI_T * spi,SPI_FLAG_T flag)527 uint8_t SPI_I2S_ReadStatusFlag(SPI_T* spi, SPI_FLAG_T flag)
528 {
529     if ((spi->STS & flag) != RESET)
530     {
531         return SET;
532     }
533     else
534     {
535         return RESET;
536     }
537 }
538 
539 /*!
540  * @brief     Clear the SPIx CRC Error flag
541  *
542  * @param     spi: The SPIx can be 1,2,3
543  *
544  * @param     flag: only Clear SPI_FLAG_CRCE(CRC Error flag)
545  *
546  * @retval    None
547  *
548  * @note      1)SPI_FLAG_OVR: (OverRun error) flag is cleared by software sequence:
549  *              a read operation to SPI_DATA register (SPI_I2S_RxData())
550  *              followed by a read operation to SPI_STS register (SPI_I2S_ReadStatusFlag()).
551  *            2)I2S_FLAG_UDR: (UnderRun error) flag is cleared:
552  *              a read operation to SPI_STS register (SPI_I2S_ReadStatusFlag()).
553  *            3)SPI_FLAG_ME: (Mode Fault) flag is cleared by software sequence:
554  *              a read/write operation to SPI_STS register (SPI_I2S_ReadStatusFlag())
555  *              followed by a write operation to SPI_CTRL1 register (SPI_Enable()).
556  */
SPI_I2S_ClearStatusFlag(SPI_T * spi,SPI_FLAG_T flag)557 void SPI_I2S_ClearStatusFlag(SPI_T* spi, SPI_FLAG_T flag)
558 {
559     spi->STS_B.CRCEFLG = BIT_RESET;
560 }
561 
562 /*!
563  * @brief     Check whether the specified SPI/I2S interrupt has occurred or not.
564  *
565  * @param     spi: The SPIx can be 1,2,3, When the I2S can be 2,3
566  *
567  * @param     flag: specifies the SPI/I2S interrupt flag to check.
568  *                  The parameter can be one of following values:
569  *                  @arg SPI_I2S_INT_RXBNE: Receive buffer not empty interrupt flag
570  *                  @arg SPI_I2S_INT_TXBE: Transmit buffer empty interrupt flag
571  *                  @arg SPI_I2S_INT_OVR: Overrun interrupt flag
572  *                  @arg SPI_INT_CRCE: CRC Error interrupt flag
573  *                  @arg SPI_INT_ME:  Mode Error interrupt flag
574  *                  @arg I2S_INT_UDR: Underrun Error interrupt flag
575  *
576  * @retval       SET or RESET
577  */
SPI_I2S_ReadIntFlag(SPI_T * spi,SPI_I2S_INT_T flag)578 uint8_t SPI_I2S_ReadIntFlag(SPI_T* spi, SPI_I2S_INT_T flag)
579 {
580     uint32_t intEnable;
581     uint32_t intStatus;
582 
583     intEnable = (uint32_t)(spi->CTRL2 & (flag >> 8));
584     intStatus = (uint32_t)(spi->STS & flag);
585 
586     if (intEnable && intStatus)
587     {
588         return SET;
589     }
590 
591     return RESET;
592 }
593 
594 /*!
595  * @brief     Clear the SPIx CRC Error interrupt flag
596  *
597  * @param     spi: The SPIx can be 1,2,3
598  *
599  * @param     flag: only Clear SPI_INT_CRCE(CRC Error interrupt flag)
600  *
601  * @retval    None
602  *
603  * @note      1)SPI_I2S_INT_OVR: (OverRun interrupt error) flag is cleared by software sequence:
604  *              a read operation to SPI_DATA register (SPI_I2S_RxData())
605  *              followed by a read operation to SPI_STS register (SPI_I2S_ReadIntFlag()).
606  *            2)I2S_INT_UDR: (UnderRun interrupt error) flag is cleared:
607  *              a read operation to SPI_STS register (SPI_I2S_ReadIntFlag()).
608  *            3)SPI_INT_ME: (Mode interrupt Fault) flag is cleared by software sequence:
609  *              a read/write operation to SPI_STS register (SPI_I2S_ReadIntFlag())
610  *              followed by a write operation to SPI_CTRL1 register (SPI_Enable()).
611  */
SPI_I2S_ClearIntFlag(SPI_T * spi,SPI_I2S_INT_T flag)612 void SPI_I2S_ClearIntFlag(SPI_T* spi, SPI_I2S_INT_T flag)
613 {
614     spi->STS_B.CRCEFLG = BIT_RESET;
615 }
616 
617 /**@} end of group SPI_Functions */
618 /**@} end of group SPI_Driver */
619 /**@} end of group APM32F10x_StdPeriphDriver */
620