summaryrefslogtreecommitdiff
path: root/bsp/mm32f327x/Libraries/MM32F327x/HAL_Lib/Src/hal_spi.c
blob: 3d8c286a30c90fd4a89aa40f580120dc2dfd2578 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
////////////////////////////////////////////////////////////////////////////////
/// @file     hal_spi.c
/// @author   AE TEAM
/// @brief    THIS FILE PROVIDES ALL THE SPI FIRMWARE FUNCTIONS.
////////////////////////////////////////////////////////////////////////////////
/// @attention
///
/// THE EXISTING FIRMWARE IS ONLY FOR REFERENCE, WHICH IS DESIGNED TO PROVIDE
/// CUSTOMERS WITH CODING INFORMATION ABOUT THEIR PRODUCTS SO THEY CAN SAVE
/// TIME. THEREFORE, MINDMOTION SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT OR
/// CONSEQUENTIAL DAMAGES ABOUT ANY CLAIMS ARISING OUT OF THE CONTENT OF SUCH
/// HARDWARE AND/OR THE USE OF THE CODING INFORMATION CONTAINED HEREIN IN
/// CONNECTION WITH PRODUCTS MADE BY CUSTOMERS.
///
/// <H2><CENTER>&COPY; COPYRIGHT MINDMOTION </CENTER></H2>
////////////////////////////////////////////////////////////////////////////////

// Define to prevent recursive inclusion
#define _HAL_SPI_C_
#include <math.h>
// Files includes
#include "hal_spi.h"
#include "hal_rcc.h"

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup MM32_Hardware_Abstract_Layer
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup SPI_HAL
/// @{

////////////////////////////////////////////////////////////////////////////////
///@addtogroup SPI_Exported_Functions
///@{

////////////////////////////////////////////////////////////////////////////////
/// @brief  Deinitializes the spi peripheral registers to their
///         default reset values.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPI_DeInit(SPI_TypeDef* spi)
{
    switch (*(vu32*)&spi) {
        case (u32)SPI2:  // SPI2_BASE:
            RCC_APB1PeriphResetCmd(RCC_APB1ENR_SPI2, ENABLE);
            RCC_APB1PeriphResetCmd(RCC_APB1ENR_SPI2, DISABLE);
            break;
        case (u32)SPI3:  // SPI3_BASE:
            RCC_APB1PeriphResetCmd(RCC_APB1ENR_SPI3, ENABLE);
            RCC_APB1PeriphResetCmd(RCC_APB1ENR_SPI3, DISABLE);
            break;
        case (u32)SPI1:  // SPI1_BASE:
            RCC_APB2PeriphResetCmd(RCC_APB2ENR_SPI1, ENABLE);
            RCC_APB2PeriphResetCmd(RCC_APB2ENR_SPI1, DISABLE);
            break;
        default:
            break;
    }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Initializes the spi peripheral according to the specified
///         parameters in the init_struct .
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  init_struct: pointer to a SPI_InitTypeDef structure
///         that contains the configuration information for the
///         specified SPI peripheral.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPI_Init(SPI_TypeDef* spi, SPI_InitTypeDef* init_struct)
{
    if (init_struct->SPI_DataSize == SPI_DataSize_32b) {
        SET_BIT(spi->GCR, SPI_GCR_DWSEL);
    }
    else {
        CLEAR_BIT(spi->GCR, SPI_GCR_DWSEL);
    }
    MODIFY_REG(spi->GCR, SPI_GCR_NSS, init_struct->SPI_NSS);
    MODIFY_REG(spi->GCR, SPI_GCR_MODE, init_struct->SPI_Mode);
    MODIFY_REG(spi->CCR, SPI_CCR_LSBFE, init_struct->SPI_FirstBit);
    MODIFY_REG(spi->CCR, SPI_CCR_CPOL, init_struct->SPI_CPOL);
    MODIFY_REG(spi->CCR, SPI_CCR_CPHA, init_struct->SPI_CPHA);

    SET_BIT(spi->CCR, SPI_CCR_SPILEN);

    MODIFY_REG(spi->BRR, BRR_Mask, init_struct->SPI_BaudRatePrescaler);

    if (init_struct->SPI_DataWidth >= 32) {
        MODIFY_REG(spi->ECR, ECR_Mask, 0);
    }
    else {
        MODIFY_REG(spi->ECR, ECR_Mask, init_struct->SPI_DataWidth);
    }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Fills each init_struct member with its default value.
/// @param  init_struct: pointer to a SPI_InitTypeDef structure
///         which will be initialized.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPI_StructInit(SPI_InitTypeDef* init_struct)
{
    init_struct->SPI_Mode              = SPI_Mode_Slave;
    init_struct->SPI_DataSize          = SPI_DataSize_8b;
    init_struct->SPI_DataWidth         = 8;
    init_struct->SPI_CPOL              = SPI_CPOL_Low;
    init_struct->SPI_CPHA              = SPI_CPHA_1Edge;
    init_struct->SPI_NSS               = SPI_NSS_Soft;
    init_struct->SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
    init_struct->SPI_FirstBit          = SPI_FirstBit_MSB;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Enables or disables the specified SPI peripheral.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  state: new state of the spi peripheral.
///         This parameter can be: ENABLE or DISABLE.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPI_Cmd(SPI_TypeDef* spi, FunctionalState state)
{
    (state) ? SET_BIT(spi->GCR, SPI_GCR_SPIEN) : CLEAR_BIT(spi->GCR, SPI_GCR_SPIEN);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Enables or disables the specified SPI interrupts.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:SPI1, SPI2.
/// @param  interrupt: specifies the SPI interrupt sources to be
///         enabled or disabled.
///         This parameter can be one of the following values:
/// @arg    SPI_IT_TXEPT: Transmitter empty interrupt
/// @arg    SPI_IT_RXFULL: RX FIFO full interrupt
/// @arg    SPI_IT_RXMATCH: Receive data match the RXDNR number interrupt
/// @arg    SPI_IT_RXOERR: Receive overrun error interrupt
/// @arg    SPI_IT_UNDERRUN: underrun interrupt
/// @arg    SPI_IT_RX: Receive data available interrupt
/// @arg    SPI_IT_TX: Transmit FIFO available interrupt
/// @param  state: new state of the specified spi interrupts.
///         This parameter can be: ENABLE or DISABLE.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPI_ITConfig(SPI_TypeDef* spi, u8 interrupt, FunctionalState state)
{
    if (state) {
        SET_BIT(spi->GCR, (u32)SPI_GCR_IEN);
        SET_BIT(spi->IER, (u32)interrupt);
    }
    else {
        CLEAR_BIT(spi->IER, interrupt);
        CLEAR_BIT(spi->GCR, SPI_GCR_IEN);
    }
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Enables or disables the SPI DMA interface.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  state: new state of the DMA Request sources.
///         This parameter can be: ENABLE or DISABLE.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPI_DMACmd(SPI_TypeDef* spi, FunctionalState state)
{
    (state) ? SET_BIT(spi->GCR, SPI_GCR_DMAEN) : CLEAR_BIT(spi->GCR, SPI_GCR_DMAEN);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  configure tn Fifo trigger level bit.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  fifo_trigger_value: specifies the Fifo trigger level
///         This parameter can be any combination of the following values:
///         SPI_TXTLF : SPI TX FIFO Trigger value set
///         SPI_RXTLF : SPI RX FIFO Trigger value set
/// @param  state: new state of the selected SPI transfer request.
///         This parameter can be: ENABLE or DISABLE.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPI_FifoTrigger(SPI_TypeDef* spi, SPI_TLF_TypeDef fifo_trigger_value, FunctionalState state)
{
    (state) ? SET_BIT(spi->GCR, (u32)fifo_trigger_value) : CLEAR_BIT(spi->GCR, (u32)fifo_trigger_value);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Transmits a Data through the spi peripheral.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  data : Data to be transmitted.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPI_SendData(SPI_TypeDef* spi, u32 data)
{
    u16 templen;
    __asm volatile("cpsid i");

    WRITE_REG(spi->TDR, data);

    templen = READ_REG(spi->ECR);
    if(templen  == 0)
        templen = 32;
    if (templen > 8)
        WRITE_REG(spi->TDR, data >> 8);
    if (templen > 16)
        WRITE_REG(spi->TDR, data >> 16);
    if (templen > 24)
        WRITE_REG(spi->TDR, data >> 24);
    __asm volatile("cpsie i");
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Returns the most recent received data by the spi peripheral.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @retval The value of the received data.
////////////////////////////////////////////////////////////////////////////////
u32 SPI_ReceiveData(SPI_TypeDef* spi)
{
    u32 temp;
    u8 templen;
    __asm volatile("cpsid i");

    temp = READ_REG(spi->RDR);

    templen = READ_REG(spi->ECR);
    if(templen  == 0)
        templen = 32;
    if (templen > 8)
        temp |= (u32)(READ_REG(spi->RDR) << 8);
    if (templen > 16)
        temp |= (u32)(READ_REG(spi->RDR) << 16);
    if (templen > 24)
        temp |= (u32)(READ_REG(spi->RDR) << 24);

    __asm volatile("cpsie i");

    return temp;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Slave chip csn single by selected
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  state: new state of the selected SPI CS pin
///         request.
///         This parameter can be: ENABLE or DISABLE.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPI_CSInternalSelected(SPI_TypeDef* spi, FunctionalState state)
{
    (state) ? CLEAR_BIT(spi->NSSR, SPI_NSSR_NSS) : SET_BIT(spi->NSSR, SPI_NSSR_NSS);  // illogical
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Configures the NSS pin control mode for the selected SPI.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  nss: specifies the SPI NSS internal state.
///         This parameter can be one of the following values:
/// @arg    SPI_NSS_Soft: NSS pin control by software
/// @arg    SPI_NSS_Hard: NSS pin control by hardware
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPI_NSSInternalSoftwareConfig(SPI_TypeDef* spi, SPI_NSS_TypeDef nss)
{
    (nss != SPI_NSS_Soft) ? SET_BIT(spi->GCR, SPI_NSS_Hard) : CLEAR_BIT(spi->GCR, SPI_NSS_Hard);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Configures the data size for the selected SPI.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  data_size: specifies the SPI data size.
///         This parameter can be one of the following values:
///         0 to 31, 0 = 32b, 1 = 1b, 2 = 2b
/// @arg    DataSize : 0 to 31
/// @retval None.
/// @retval None.
bool SPI_DataSizeConfig(SPI_TypeDef* spi, u8 data_size)
{
    if (data_size > 32)
        return false;
    data_size &= 0x1F;
    WRITE_REG(spi->ECR, data_size);
    return true;
}

//////////////////////////////////////////////////////////////////////////////////
void SPI_DataSizeTypeConfig(SPI_TypeDef* spi, SPI_DataSize_TypeDef SPI_DataSize)
{
    CLEAR_BIT(spi->GCR, (u32)SPI_DataSize_32b);
    SET_BIT(spi->GCR, (u32)SPI_DataSize);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Selects the data transfer direction in bi-directional mode
///         for the specified SPI.
/// @param spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param direction: specifies the data transfer direction in
///         bi-directional mode.
///         This parameter can be one of the following values:
/// @arg    SPI_Direction_Tx: Selects Tx transmission direction
/// @arg    SPI_Direction_Rx: Selects Rx receive direction
/// @arg    SPI_Disable_Tx: Selects Rx receive direction
/// @arg    SPI_Disable_Rx: Selects Rx receive direction
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPI_BiDirectionalLineConfig(SPI_TypeDef* spi, SPI_Direction_TypeDef direction)
{
    switch (direction) {
        case SPI_Direction_Rx:
            SET_BIT(spi->GCR, SPI_GCR_RXEN);
            break;
        case SPI_Direction_Tx:
            SET_BIT(spi->GCR, SPI_GCR_TXEN);
            break;
        case SPI_Disable_Rx:
            CLEAR_BIT(spi->GCR, SPI_GCR_RXEN);
            break;
        case SPI_Disable_Tx:
            CLEAR_BIT(spi->GCR, SPI_GCR_TXEN);
            break;
        default:
            break;
    }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Checks whether the specified SPI flag is set or not.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  flag: specifies the SPI flag to check.
///         This parameter can be one of the following values:
/// @arg    SPI_FLAG_RXAVL: Rx buffer has bytes flag
/// @arg    SPI_FLAG_TXEPT: Tx buffer and tx shifter empty flag
/// @arg    SPI_FLAG_TXFULL: Tx buffer full flag
/// @arg    SPI_FLAG_RXAVL_4BYTE: Receive available 4 byte data message flag.
/// @retval The new state of SPI_FLAG (SET or RESET).
////////////////////////////////////////////////////////////////////////////////
FlagStatus SPI_GetFlagStatus(SPI_TypeDef* spi, SPI_FLAG_TypeDef flag)
{
//    u8 number;
    return (spi->SR & flag) ? SET : RESET;
//  if (spi->ECR == 8 || spi->ECR == 0)
//      return (spi->SR & SPI_FLAG) ? SET : RESET;
//  else {
//      if ((spi->ECR > 0) && (spi->ECR <= 8))
//          number = 1;
//      else if ((spi->ECR) <= 16)
//          number = 2;
//      else if ((spi->ECR) <= 24)
//          number = 3;
//      else if (((spi->ECR) <= 31) || (spi->ECR == 0))
//          number = 4;
//      return (((spi->SR & 0xf00) >> 8) >= number) ? SET : RESET;
//  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Checks whether the specified SPI interrupt has occurred or not.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  interrupt: specifies the SPI interrupt source to check.
///         This parameter can be one of the following values:
/// @arg    SPI_IT_TX: Tx buffer empty interrupt
/// @arg    SPI_IT_RX: Rx buffer  interrupt
/// @arg    SPI_IT_UNDERRUN: under Error interrupt in slave mode
/// @arg    SPI_IT_RXOVER: RX OVER Error interrupt
/// @arg    SPI_IT_RXMATCH: spectials rx data numbers  interrupt
/// @arg    SPI_IT_RXFULL: Rx buffer full interrupt
/// @arg    SPI_IT_TXEPT: Tx buffer  and tx shifter empty interrupt
/// @retval The new state of SPI_IT (SET or RESET).
////////////////////////////////////////////////////////////////////////////////
ITStatus SPI_GetITStatus(SPI_TypeDef* spi, SPI_IT_TypeDef interrupt)
{
    return (spi->ISR & interrupt) ? SET : RESET;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Clears the spi  interrupt pending bit.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  interrupt: specifies the SPI interrupt pending bit to clear.
/// @arg    SPI_IT_TX: Tx buffer empty interrupt
/// @arg    SPI_IT_RX: Rx buffer  interrupt
/// @arg    SPI_IT_UNDERRUN: under Error interrupt in slave mode
/// @arg    SPI_IT_RXOVER: RX OVER Error interrupt
/// @arg    SPI_IT_RXMATCH: spectials rx data numbers  interrupt
/// @arg    SPI_IT_RXFULL: Rx buffer full interrupt
/// @arg    SPI_IT_TXEPT: Tx buffer  and tx shifter empty interrupt
///         This function clears only ERR intetrrupt pending bit.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPI_ClearITPendingBit(SPI_TypeDef* spi, SPI_IT_TypeDef interrupt)
{
    SET_BIT(spi->ICR, interrupt);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  SPI Hole a count Received bytes in next receive process.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  number: specifies the SPI receive Number.
///         This parament can be 1-65535.
///         This function can use only in SPI master single receive mode.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPI_RxBytes(SPI_TypeDef* spi, u16 number)
{
    WRITE_REG(spi->RDNR, number);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  slave mode tx data transmit phase adjust set.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  adjust_value: slave mode tx data transmit phase adjust enum.
///         This parament can be :
///         SPI_SlaveAdjust_FAST:  fast speed use
///         SPI_SlaveAdjust_LOW:   low speed use
///         This function can use only in SPI master single receive mode.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPI_SlaveAdjust(SPI_TypeDef* spi, SPI_SlaveAdjust_TypeDef adjust_value)
{
    (adjust_value) ? SET_BIT(spi->CCR, SPI_CCR_RXEDGE) : CLEAR_BIT(spi->CCR, SPI_CCR_RXEDGE);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Enables or disables all SPI interrupts.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  state: new state of all spi interrupts.
///         This parameter can be: ENABLE or DISABLE.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void exSPI_ITCmd(SPI_TypeDef* spi, FunctionalState state)
{
    (state) ? SET_BIT(spi->IER, (u32)SPI_GCR_IEN) : CLEAR_BIT(spi->IER, (u32)SPI_GCR_IEN);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Enables or disables the specified SPI interrupts.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  interrupt: specifies the SPI interrupt sources to be enabled or disabled.
///         This parameter can be one of the following values:
/// @arg    SPI_IT_TXEPT: Transmitter empty interrupt
/// @arg    SPI_IT_RXFULL: RX FIFO full interrupt
/// @arg    SPI_IT_RXMATCH: Receive data match the RXDNR number interrupt
/// @arg    SPI_IT_RXOERR: Receive overrun error interrupt
/// @arg    SPI_IT_UNDERRUN: underrun interrupt
/// @arg    SPI_IT_RX: Receive data available interrupt
/// @arg    SPI_IT_TX: Transmit FIFO available interrupt
/// @param  state: new state of the specified spi interrupts.
///         This parameter can be: ENABLE or DISABLE.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void exSPI_ITConfig(SPI_TypeDef* spi, SPI_IT_TypeDef interrupt, FunctionalState state)
{
    (state) ? SET_BIT(spi->IER, (u32)interrupt) : CLEAR_BIT(spi->IER, (u32)interrupt);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Enables or disables the SPI DMA request.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  state: new state of the DMA Request.
///         This parameter can be: ENABLE or DISABLE.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void exSPI_DMACmd(SPI_TypeDef* spi, FunctionalState state)
{
    (state) ? SET_BIT(spi->GCR, SPI_GCR_DMAEN) : CLEAR_BIT(spi->GCR, SPI_GCR_DMAEN);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Set or reset Slave chip csn signal output
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  state: new state of Slave chip csn signal output.
///         This parameter can be: ENABLE or DISABLE.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void exSPI_CSInternalSelected(SPI_TypeDef* spi, FunctionalState state)
{
    (state) ? CLEAR_BIT(spi->NSSR, SPI_NSSR_NSS) : SET_BIT(spi->NSSR, SPI_NSSR_NSS);  // illogical
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  tx data and rx data phase adjust.
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2.
/// @param  adjust_value: choose adjust mode.
///         This parament can be :
///         SPI_DataEdgeAdjust_LOW,
///         SPI_DataEdgeAdjust_FAST
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void exSPI_DataEdgeAdjust(SPI_TypeDef* spi, SPI_DataEdgeAdjust_TypeDef adjust_value)
{
    // master mode
    if (spi->GCR & SPI_GCR_MODE) {
        adjust_value ? SET_BIT(spi->CCR, SPI_CCR_RXEDGE) : CLEAR_BIT(spi->CCR, SPI_CCR_RXEDGE);
    }
    // slave mode
    else {
        adjust_value ? SET_BIT(spi->CCR, SPI_CCR_TXEDGE) : CLEAR_BIT(spi->CCR, SPI_CCR_TXEDGE);
    }
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Set or reset i2s
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2, SPI3.
/// @param  state: new state of Slave chip csn signal output.
///         This parameter can be: ENABLE or DISABLE.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void I2S_Cmd(SPI_TypeDef* spi, FunctionalState state)
{
    (state) ? SET_BIT(spi->CFGR, I2S_CFGR_SPI_I2S) : CLEAR_BIT(spi->CFGR, I2S_CFGR_SPI_I2S);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  i2s Config
/// @param  spi: Select the SPI peripheral.
///         This parameter can be one of the following values:
///         SPI1, SPI2, SPI3.
/// @param  state: new state of Slave chip csn signal output.
///         This parameter can be: ENABLE or DISABLE.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void I2S_Init(SPI_TypeDef* spi, I2S_InitTypeDef* I2S_InitStruct)
{
    u32 i2sdiv = 2;
    u32 tmpreg = 0;
    u32 packetlength = 1;
    u32 result = 0, yushu = 0;
    u32 sourceclock = 0;
    RCC_ClocksTypeDef RCC_Clocks;

    if(I2S_InitStruct->I2S_AudioFreq == I2S_AudioFreq_Default) {
        i2sdiv = 2;
    }
    else {
        if(I2S_InitStruct->I2S_DataFormat == I2S_DataFormat_16b) {
            packetlength = 1;
        }
        else {
            packetlength = 2;
        }
        RCC_GetClocksFreq(&RCC_Clocks);

        if((SPI2 == spi) || (SPI3 == spi))  {
            sourceclock = RCC_Clocks.PCLK1_Frequency;
        }
        else {
            sourceclock = RCC_Clocks.PCLK2_Frequency;
        }
        if(I2S_InitStruct->I2S_MCLKOutput == I2S_MCLKOutput_Enable) {
            result = (sourceclock) / (256 * (I2S_InitStruct->I2S_AudioFreq));
            yushu = (sourceclock) % (256 * (I2S_InitStruct->I2S_AudioFreq));
            if(yushu > (128 * (I2S_InitStruct->I2S_AudioFreq))) {
                result = result + 1;
            }
            i2sdiv = result;
            if ((i2sdiv < 2) || (i2sdiv > 0x1FF)) {
                i2sdiv = 2;
            }
        }
        else {
            result = (sourceclock) / (16 * 2 * packetlength * (I2S_InitStruct->I2S_AudioFreq));
            yushu = (sourceclock) % (16 * 2 * packetlength * (I2S_InitStruct->I2S_AudioFreq));
            if(yushu > ((16 * packetlength * (I2S_InitStruct->I2S_AudioFreq)))) {
                result = result + 1;
            }
            if ((i2sdiv < 1) || (i2sdiv > 0x1FF)) {
                i2sdiv = 1;
            }
        }
    }
    if(I2S_CPOL_High  == I2S_InitStruct->I2S_CPOL) {
        spi->CCTL |= SPI_CCR_CPOL;
    }
    else {
        spi->CCTL &= ~SPI_CCR_CPOL;
    }

    spi->CFGR = 0x2 << I2S_CFGR_I2SDIV_Pos;

    if((I2S_InitStruct->I2S_Mode == I2S_Mode_MasterTx) || (I2S_InitStruct->I2S_Mode == I2S_Mode_MasterRx)) {
        spi->GCTL |= SPI_GCR_MODE;
    }
    else {
        spi->GCTL &= ~SPI_GCR_MODE;
    }
    if((I2S_InitStruct->I2S_Mode == I2S_Mode_MasterTx) || (I2S_InitStruct->I2S_Mode == I2S_Mode_SlaveTx)) {
        spi->GCTL |= SPI_GCR_TXEN;
        spi->GCTL &= ~SPI_GCR_RXEN;
    }
    else {
        spi->GCTL &= ~SPI_GCR_TXEN;
        spi->GCTL |= SPI_GCR_RXEN;
    }
//    tmpreg = spi->GCTL;
//    tmpreg &= ~(1 << 2);
//    tmpreg |= (u16)(I2S_InitStruct->I2S_Mode);
//    spi->GCTL = tmpreg;
//
    tmpreg = 0;
    tmpreg |= (i2sdiv << I2S_CFGR_I2SDIV_Pos) | \
              (I2S_InitStruct->I2S_MCLKOutput) | \
              (I2S_CFGR_SPI_I2S) | \
              (I2S_InitStruct->I2S_Standard) | \
              (I2S_InitStruct->I2S_DataFormat);
    spi->CFGR &= ~I2S_CFGR_I2SDIV;
    spi->CFGR |= tmpreg;

}
/// @}

/// @}

/// @}