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