-
Notifications
You must be signed in to change notification settings - Fork 41
/
NXP_SDHC.cpp
1441 lines (1204 loc) · 59.9 KB
/
NXP_SDHC.cpp
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
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// adapted for Arduino SD library by Paul Stoffregen
// following code is modified by Walter Zimmer from
// from version provided by
// Petr Gargulak (NXP Employee)
//https://community.nxp.com/servlet/JiveServlet/download/339474-1-263510/SDHC_K60_Baremetal.ZIP
//see also
//https://community.nxp.com/thread/99202
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__)
#include "core_pins.h" // include calls to kinetis.h or imxrt.h
#include "usb_serial.h" // for Serial
#include "NXP_SDHC.h"
/******************************************************************************
Constants
******************************************************************************/
enum {
SDHC_RESULT_OK = 0, /* 0: Successful */
SDHC_RESULT_ERROR, /* 1: R/W Error */
SDHC_RESULT_WRPRT, /* 2: Write Protected */
SDHC_RESULT_NOT_READY, /* 3: Not Ready */
SDHC_RESULT_PARERR, /* 4: Invalid Parameter */
SDHC_RESULT_NO_RESPONSE /* 5: No Response */ // from old diskio.h
};
/*void print_result(int n)
{
switch (n) {
case SDHC_RESULT_OK: serial_print("OK\n"); break;
case SDHC_RESULT_ERROR: serial_print("R/W Error\n"); break;
case SDHC_RESULT_WRPRT: serial_print("Write Protect\n"); break;
case SDHC_RESULT_NOT_READY: serial_print("Not Ready\n"); break;
case SDHC_RESULT_PARERR: serial_print("Invalid Param\n"); break;
case SDHC_RESULT_NO_RESPONSE: serial_print("No Response\n"); break;
default: serial_print("Unknown result\n");
}
}*/
#define IO_SDHC_ATTRIBS (IO_DEV_ATTR_READ | IO_DEV_ATTR_REMOVE | IO_DEV_ATTR_SEEK | IO_DEV_ATTR_WRITE | IO_DEV_ATTR_BLOCK_MODE)
#define SDHC_XFERTYP_RSPTYP_NO (0x00)
#define SDHC_XFERTYP_RSPTYP_136 (0x01)
#define SDHC_XFERTYP_RSPTYP_48 (0x02)
#define SDHC_XFERTYP_RSPTYP_48BUSY (0x03)
#define SDHC_XFERTYP_CMDTYP_ABORT (0x03)
#define SDHC_PROCTL_EMODE_INVARIANT (0x02)
#define SDHC_PROCTL_DTW_1BIT (0x00)
#define SDHC_PROCTL_DTW_4BIT (0x01)
#define SDHC_PROCTL_DTW_8BIT (0x10)
#define SDHC_INITIALIZATION_MAX_CNT 100000
/* SDHC commands */
#define SDHC_CMD0 (0)
#define SDHC_CMD1 (1)
#define SDHC_CMD2 (2)
#define SDHC_CMD3 (3)
#define SDHC_CMD4 (4)
#define SDHC_CMD5 (5)
#define SDHC_CMD6 (6)
#define SDHC_CMD7 (7)
#define SDHC_CMD8 (8)
#define SDHC_CMD9 (9)
#define SDHC_CMD10 (10)
#define SDHC_CMD11 (11)
#define SDHC_CMD12 (12)
#define SDHC_CMD13 (13)
#define SDHC_CMD15 (15)
#define SDHC_CMD16 (16)
#define SDHC_CMD17 (17)
#define SDHC_CMD18 (18)
#define SDHC_CMD20 (20)
#define SDHC_CMD24 (24)
#define SDHC_CMD25 (25)
#define SDHC_CMD26 (26)
#define SDHC_CMD27 (27)
#define SDHC_CMD28 (28)
#define SDHC_CMD29 (29)
#define SDHC_CMD30 (30)
#define SDHC_CMD32 (32)
#define SDHC_CMD33 (33)
#define SDHC_CMD34 (34)
#define SDHC_CMD35 (35)
#define SDHC_CMD36 (36)
#define SDHC_CMD37 (37)
#define SDHC_CMD38 (38)
#define SDHC_CMD39 (39)
#define SDHC_CMD40 (40)
#define SDHC_CMD42 (42)
#define SDHC_CMD52 (52)
#define SDHC_CMD53 (53)
#define SDHC_CMD55 (55)
#define SDHC_CMD56 (56)
#define SDHC_CMD59 (59)
#define SDHC_CMD60 (60)
#define SDHC_CMD61 (61)
#define SDHC_ACMD6 (0x40 + 6)
#define SDHC_ACMD13 (0x40 + 13)
#define SDHC_ACMD22 (0x40 + 22)
#define SDHC_ACMD23 (0x40 + 23)
#define SDHC_ACMD41 (0x40 + 41)
#define SDHC_ACMD42 (0x40 + 42)
#define SDHC_ACMD51 (0x40 + 51)
#define SDHC_FIFO_BUFFER_SIZE 16
#define SDHC_BLOCK_SIZE 512
#if defined(__IMXRT1062__)
#define MAKE_REG_MASK(m,s) (((uint32_t)(((uint32_t)(m) << s))))
#define MAKE_REG_GET(x,m,s) (((uint32_t)(((uint32_t)(x)>>s) & m)))
#define MAKE_REG_SET(x,m,s) (((uint32_t)(((uint32_t)(x) & m) << s)))
#define SDHC_BLKATTR_BLKSIZE_MASK MAKE_REG_MASK(0x1FFF,0) //uint32_t)(((n) & 0x1FFF)<<0) // Transfer Block Size Mask
#define SDHC_BLKATTR_BLKSIZE(n) MAKE_REG_SET(n,0x1FFF,0) //uint32_t)(((n) & 0x1FFF)<<0) // Transfer Block Size
#define SDHC_BLKATTR_BLKCNT_MASK MAKE_REG_MASK(0x1FFF,16) //((uint32_t)0x1FFF<<16)
#define SDHC_BLKATTR_BLKCNT(n) MAKE_REG_SET(n,0x1FFF,16) //(uint32_t)(((n) & 0x1FFF)<<16) // Blocks Count For Current Transfer
#define SDHC_XFERTYP_CMDINX(n) MAKE_REG_SET(n,0x3F,24) //(uint32_t)(((n) & 0x3F)<<24)// Command Index
#define SDHC_XFERTYP_CMDTYP(n) MAKE_REG_SET(n,0x3,22) //(uint32_t)(((n) & 0x3)<<22) // Command Type
#define SDHC_XFERTYP_DPSEL MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data Present Select
#define SDHC_XFERTYP_CICEN MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Command Index Check Enable
#define SDHC_XFERTYP_CCCEN MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command CRC Check Enable
#define SDHC_XFERTYP_RSPTYP(n) MAKE_REG_SET(n,0x3,16) //(uint32_t)(((n) & 0x3)<<16) // Response Type Select
#define SDHC_XFERTYP_MSBSEL MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Multi/Single Block Select
#define SDHC_XFERTYP_DTDSEL MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Data Transfer Direction Select
#define SDHC_XFERTYP_AC12EN MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Auto CMD12 Enable
#define SDHC_XFERTYP_BCEN MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Block Count Enable
#define SDHC_XFERTYP_DMAEN MAKE_REG_MASK(0x3,0) //((uint32_t)0x00000001) // DMA Enable
#define SDHC_PRSSTAT_DLSL_MASK MAKE_REG_MASK(0xFF,24) //((uint32_t)0xFF000000) // DAT Line Signal Level
#define SDHC_PRSSTAT_CLSL MAKE_REG_MASK(0x1,23) //((uint32_t)0x00800000) // CMD Line Signal Level
#define SDHC_PRSSTAT_WPSPL MAKE_REG_MASK(0x1,19) //
#define SDHC_PRSSTAT_CDPL MAKE_REG_MASK(0x1,18) //
#define SDHC_PRSSTAT_CINS MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Card Inserted
#define SDHC_PRSSTAT_TSCD MAKE_REG_MASK(0x1,15)
#define SDHC_PRSSTAT_RTR MAKE_REG_MASK(0x1,12)
#define SDHC_PRSSTAT_BREN MAKE_REG_MASK(0x1,11) //((uint32_t)0x00000800) // Buffer Read Enable
#define SDHC_PRSSTAT_BWEN MAKE_REG_MASK(0x1,10) //((uint32_t)0x00000400) // Buffer Write Enable
#define SDHC_PRSSTAT_RTA MAKE_REG_MASK(0x1,9) //((uint32_t)0x00000200) // Read Transfer Active
#define SDHC_PRSSTAT_WTA MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Write Transfer Active
#define SDHC_PRSSTAT_SDOFF MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // SD Clock Gated Off Internally
#define SDHC_PRSSTAT_PEROFF MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // SDHC clock Gated Off Internally
#define SDHC_PRSSTAT_HCKOFF MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // System Clock Gated Off Internally
#define SDHC_PRSSTAT_IPGOFF MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Bus Clock Gated Off Internally
#define SDHC_PRSSTAT_SDSTB MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // SD Clock Stable
#define SDHC_PRSSTAT_DLA MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Data Line Active
#define SDHC_PRSSTAT_CDIHB MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Command Inhibit (DAT)
#define SDHC_PRSSTAT_CIHB MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Inhibit (CMD)
#define SDHC_PROTCT_NONEXACT_BLKRD MAKE_REG_MASK(0x1,30) //
#define SDHC_PROTCT_BURST_LENEN(n) MAKE_REG_SET(n,0x7,12) //
#define SDHC_PROCTL_WECRM MAKE_REG_MASK(0x1,26) //((uint32_t)0x04000000) // Wakeup Event Enable On SD Card Removal
#define SDHC_PROCTL_WECINS MAKE_REG_MASK(0x1,25) //((uint32_t)0x02000000) // Wakeup Event Enable On SD Card Insertion
#define SDHC_PROCTL_WECINT MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Wakeup Event Enable On Card Interrupt
#define SDHC_PROCTL_RD_DONE_NOBLK MAKE_REG_MASK(0x1,20) //
#define SDHC_PROCTL_IABG MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Interrupt At Block Gap
#define SDHC_PROCTL_RWCTL MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Read Wait Control
#define SDHC_PROCTL_CREQ MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Continue Request
#define SDHC_PROCTL_SABGREQ MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Stop At Block Gap Request
#define SDHC_PROCTL_DMAS(n) MAKE_REG_SET(n,0x3,8) //(uint32_t)(((n) & 0x3)<<8) // DMA Select
#define SDHC_PROCTL_CDSS MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Detect Signal Selection
#define SDHC_PROCTL_CDTL MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Detect Test Level
#define SDHC_PROCTL_EMODE(n) MAKE_REG_SET(n,0x3,4) //(uint32_t)(((n) & 0x3)<<4) // Endian Mode
#define SDHC_PROCTL_EMODE_MASK MAKE_REG_MASK(0x3,4) //(uint32_t)((0x3)<<4) // Endian Mode
#define SDHC_PROCTL_D3CD MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DAT3 As Card Detection Pin
#define SDHC_PROCTL_DTW(n) MAKE_REG_SET(n,0x3,1) //(uint32_t)(((n) & 0x3)<<1) // Data Transfer Width, 0=1bit, 1=4bit, 2=8bit
#define SDHC_PROCTL_DTW_MASK MAKE_REG_MASK(0x3,1) //((uint32_t)0x00000006)
#define SDHC_PROCTL_LCTL MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // LED Control
#define SDHC_SYSCTL_RSTT MAKE_REG_MASK(0x1,28) //
#define SDHC_SYSCTL_INITA MAKE_REG_MASK(0x1,27) //((uint32_t)0x08000000) // Initialization Active
#define SDHC_SYSCTL_RSTD MAKE_REG_MASK(0x1,26) //((uint32_t)0x04000000) // Software Reset For DAT Line
#define SDHC_SYSCTL_RSTC MAKE_REG_MASK(0x1,25) //((uint32_t)0x02000000) // Software Reset For CMD Line
#define SDHC_SYSCTL_RSTA MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Software Reset For ALL
#define SDHC_SYSCTL_DTOCV(n) MAKE_REG_SET(n,0xF,16) //(uint32_t)(((n) & 0xF)<<16) // Data Timeout Counter Value
#define SDHC_SYSCTL_DTOCV_MASK MAKE_REG_MASK(0xF,16) //((uint32_t)0x000F0000)
#define SDHC_SYSCTL_SDCLKFS(n) MAKE_REG_SET(n,0xFF,8) //(uint32_t)(((n) & 0xFF)<<8) // SDCLK Frequency Select
#define SDHC_SYSCTL_SDCLKFS_MASK MAKE_REG_MASK(0xFF,8) //((uint32_t)0x0000FF00)
#define SDHC_SYSCTL_DVS(n) MAKE_REG_SET(n,0xF,4) //(uint32_t)(((n) & 0xF)<<4) // Divisor
#define SDHC_SYSCTL_DVS_MASK MAKE_REG_MASK(0xF,4) //((uint32_t)0x000000F0)
#define SDHC_SYSCTL_SDCLKEN ((uint32_t)0x00000008) // SD Clock Enable
#define SDHC_SYSCTL_PEREN ((uint32_t)0x00000004) // Peripheral Clock Enable
#define SDHC_SYSCTL_HCKEN ((uint32_t)0x00000002) // System Clock Enable
#define SDHC_SYSCTL_IPGEN ((uint32_t)0x00000001) // IPG Clock Enable
#define SDHC_IRQSTAT_DMAE MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // DMA Error
#define SDHC_IRQSTAT_TNE MAKE_REG_MASK(0x1,26) //
#define SDHC_IRQSTAT_AC12E MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Auto CMD12 Error
#define SDHC_IRQSTAT_DEBE MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Data End Bit Error
#define SDHC_IRQSTAT_DCE MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data CRC Error
#define SDHC_IRQSTAT_DTOE MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Data Timeout Error
#define SDHC_IRQSTAT_CIE MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command Index Error
#define SDHC_IRQSTAT_CEBE MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Command End Bit Error
#define SDHC_IRQSTAT_CCE MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Command CRC Error
#define SDHC_IRQSTAT_CTOE MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Command Timeout Error
#define SDHC_IRQSTAT_TP MAKE_REG_MASK(0x1,14) //
#define SDHC_IRQSTAT_RTE MAKE_REG_MASK(0x1,12) //
#define SDHC_IRQSTAT_CINT MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Card Interrupt
#define SDHC_IRQSTAT_CRM MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Removal
#define SDHC_IRQSTAT_CINS MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Insertion
#define SDHC_IRQSTAT_BRR MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Buffer Read Ready
#define SDHC_IRQSTAT_BWR MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Buffer Write Ready
#define SDHC_IRQSTAT_DINT MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DMA Interrupt
#define SDHC_IRQSTAT_BGE MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Block Gap Event
#define SDHC_IRQSTAT_TC MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Transfer Complete
#define SDHC_IRQSTAT_CC MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Complete
#define SDHC_IRQSTATEN_DMAESEN MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // DMA Error Status Enable
#define SDHC_IRQSTATEN_TNESEN MAKE_REG_MASK(0x1,26) //
#define SDHC_IRQSTATEN_AC12ESEN MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Auto CMD12 Error Status Enable
#define SDHC_IRQSTATEN_DEBESEN MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Data End Bit Error Status Enable
#define SDHC_IRQSTATEN_DCESEN MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data CRC Error Status Enable
#define SDHC_IRQSTATEN_DTOESEN MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Data Timeout Error Status Enable
#define SDHC_IRQSTATEN_CIESEN MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command Index Error Status Enable
#define SDHC_IRQSTATEN_CEBESEN MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Command End Bit Error Status Enable
#define SDHC_IRQSTATEN_CCESEN MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Command CRC Error Status Enable
#define SDHC_IRQSTATEN_CTOESEN MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Command Timeout Error Status Enable
#define SDHC_IRQSTATEN_TPSEN MAKE_REG_MASK(0x1,14) //
#define SDHC_IRQSTATEN_RTESEN MAKE_REG_MASK(0x1,12) //
#define SDHC_IRQSTATEN_CINTSEN MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Card Interrupt Status Enable
#define SDHC_IRQSTATEN_CRMSEN MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Removal Status Enable
#define SDHC_IRQSTATEN_CINSEN MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Insertion Status Enable
#define SDHC_IRQSTATEN_BRRSEN MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Buffer Read Ready Status Enable
#define SDHC_IRQSTATEN_BWRSEN MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Buffer Write Ready Status Enable
#define SDHC_IRQSTATEN_DINTSEN MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DMA Interrupt Status Enable
#define SDHC_IRQSTATEN_BGESEN MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Block Gap Event Status Enable
#define SDHC_IRQSTATEN_TCSEN MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Transfer Complete Status Enable
#define SDHC_IRQSTATEN_CCSEN MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Complete Status Enable
#define SDHC_IRQSIGEN_DMAEIEN MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // DMA Error Interrupt Enable
#define SDHC_IRQSIGEN_TNEIEN MAKE_REG_MASK(0x1,26) //
#define SDHC_IRQSIGEN_AC12EIEN MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Auto CMD12 Error Interrupt Enable
#define SDHC_IRQSIGEN_DEBEIEN MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Data End Bit Error Interrupt Enable
#define SDHC_IRQSIGEN_DCEIEN MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data CRC Error Interrupt Enable
#define SDHC_IRQSIGEN_DTOEIEN MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Data Timeout Error Interrupt Enable
#define SDHC_IRQSIGEN_CIEIEN MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command Index Error Interrupt Enable
#define SDHC_IRQSIGEN_CEBEIEN MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Command End Bit Error Interrupt Enable
#define SDHC_IRQSIGEN_CCEIEN MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Command CRC Error Interrupt Enable
#define SDHC_IRQSIGEN_CTOEIEN MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Command Timeout Error Interrupt Enable
#define SDHC_IRQSIGEN_TPIEN MAKE_REG_MASK(0x1,14) //
#define SDHC_IRQSIGEN_RTEIEN MAKE_REG_MASK(0x1,12) //
#define SDHC_IRQSIGEN_CINTIEN MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Card Interrupt Interrupt Enable
#define SDHC_IRQSIGEN_CRMIEN MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Removal Interrupt Enable
#define SDHC_IRQSIGEN_CINSIEN MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Insertion Interrupt Enable
#define SDHC_IRQSIGEN_BRRIEN MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Buffer Read Ready Interrupt Enable
#define SDHC_IRQSIGEN_BWRIEN MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Buffer Write Ready Interrupt Enable
#define SDHC_IRQSIGEN_DINTIEN MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DMA Interrupt Interrupt Enable
#define SDHC_IRQSIGEN_BGEIEN MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Block Gap Event Interrupt Enable
#define SDHC_IRQSIGEN_TCIEN MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Transfer Complete Interrupt Enable
#define SDHC_IRQSIGEN_CCIEN MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Complete Interrupt Enable
#define SDHC_AC12ERR_SMPLCLK_SEL MAKE_REG_MASK(0x1,23) //
#define SDHC_AC12ERR_EXEC_TUNING MAKE_REG_MASK(0x1,22) //
#define SDHC_AC12ERR_CNIBAC12E MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Command Not Issued By Auto CMD12 Error
#define SDHC_AC12ERR_AC12IE MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Auto CMD12 Index Error
#define SDHC_AC12ERR_AC12CE MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // Auto CMD12 CRC Error
#define SDHC_AC12ERR_AC12EBE MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Auto CMD12 End Bit Error
#define SDHC_AC12ERR_AC12TOE MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Auto CMD12 Timeout Error
#define SDHC_AC12ERR_AC12NE MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Auto CMD12 Not Executed
#define SDHC_HTCAPBLT_VS18 MAKE_REG_MASK(0x1,26) //
#define SDHC_HTCAPBLT_VS30 MAKE_REG_MASK(0x1,25) //
#define SDHC_HTCAPBLT_VS33 MAKE_REG_MASK(0x1,24) //
#define SDHC_HTCAPBLT_SRS MAKE_REG_MASK(0x1,23) //
#define SDHC_HTCAPBLT_DMAS MAKE_REG_MASK(0x1,22) //
#define SDHC_HTCAPBLT_HSS MAKE_REG_MASK(0x1,21) //
#define SDHC_HTCAPBLT_ADMAS MAKE_REG_MASK(0x1,20) //
#define SDHC_HTCAPBLT_MBL_VAL MAKE_REG_GET((USDHC1_HOST_CTRL_CAP),0x7,16) //
#define SDHC_HTCAPBLT_RETUN_MODE MAKE_REG_GET((USDHC1_HOST_CTRL_CAP),0x3,14) //
#define SDHC_HTCAPBLT_TUNE_SDR50 MAKE_REG_MASK(0x1,13) //
#define SDHC_HTCAPBLT_TIME_RETUN(n) MAKE_REG_SET(n,0xF,8) //
#define SDHC_WML_WR_BRSTLEN_MASK MAKE_REG_MASK(0x1F,24) //
#define SDHC_WML_RD_BRSTLEN_MASK MAKE_REG_MASK(0x1F,8) //
#define SDHC_WML_WR_WML_MASK MAKE_REG_MASK(0xFF,16) //
#define SDHC_WML_RD_WML_MASK MAKE_REG_MASK(0xFF,0) //
#define SDHC_WML_WR_BRSTLEN(n) MAKE_REG_SET(n,0x1F,24) //(uint32_t)(((n) & 0x7F)<<16) // Write Burst Len
#define SDHC_WML_RD_BRSTLEN(n) MAKE_REG_SET(n,0x1F,8) //(uint32_t)(((n) & 0x7F)<<0) // Read Burst Len
#define SDHC_WML_WR_WML(n) MAKE_REG_SET(n,0xFF,16) //(uint32_t)(((n) & 0x7F)<<16) // Write Watermark Level
#define SDHC_WML_RD_WML(n) MAKE_REG_SET(n,0xFF,0) //(uint32_t)(((n) & 0x7F)<<0) // Read Watermark Level
#define SDHC_WML_WRWML(n) MAKE_REG_SET(n,0xFF,16) //(uint32_t)(((n) & 0x7F)<<16) // Write Watermark Level
#define SDHC_WML_RDWML(n) MAKE_REG_SET(n,0xFF,0) //(uint32_t)(((n) & 0x7F)<<0) // Read Watermark Level
// Teensy 4.0 only
#define SDHC_MIX_CTRL_DMAEN MAKE_REG_MASK(0x1,0) //
#define SDHC_MIX_CTRL_BCEN MAKE_REG_MASK(0x1,1) //
#define SDHC_MIX_CTRL_AC12EN MAKE_REG_MASK(0x1,2) //
#define SDHC_MIX_CTRL_DDR_EN MAKE_REG_MASK(0x1,3) //
#define SDHC_MIX_CTRL_DTDSEL MAKE_REG_MASK(0x1,4) //
#define SDHC_MIX_CTRL_MSBSEL MAKE_REG_MASK(0x1,5) //
#define SDHC_MIX_CTRL_NIBBLE_POS MAKE_REG_MASK(0x1,6) //
#define SDHC_MIX_CTRL_AC23EN MAKE_REG_MASK(0x1,7) //
#define SDHC_FEVT_CINT MAKE_REG_MASK(0x1,31) //((uint32_t)0x80000000) // Force Event Card Interrupt
#define SDHC_FEVT_DMAE MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // Force Event DMA Error
#define SDHC_FEVT_AC12E MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Force Event Auto CMD12 Error
#define SDHC_FEVT_DEBE MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Force Event Data End Bit Error
#define SDHC_FEVT_DCE MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Force Event Data CRC Error
#define SDHC_FEVT_DTOE MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Force Event Data Timeout Error
#define SDHC_FEVT_CIE MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Force Event Command Index Error
#define SDHC_FEVT_CEBE MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Force Event Command End Bit Error
#define SDHC_FEVT_CCE MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Force Event Command CRC Error
#define SDHC_FEVT_CTOE MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Force Event Command Timeout Error
#define SDHC_FEVT_CNIBAC12E MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Force Event Command Not Executed By Auto Command 12 Error
#define SDHC_FEVT_AC12IE MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Force Event Auto Command 12 Index Error
#define SDHC_FEVT_AC12EBE MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // Force Event Auto Command 12 End Bit Error
#define SDHC_FEVT_AC12CE MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Force Event Auto Command 12 CRC Error
#define SDHC_FEVT_AC12TOE MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Force Event Auto Command 12 Time Out Error
#define SDHC_FEVT_AC12NE MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Force Event Auto Command 12 Not Executed
#define SDHC_ADMAES_ADMADCE MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008)
#define SDHC_ADMAES_ADMALME MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004)
#define SDHC_ADMAES_ADMAES_MASK MAKE_REG_MASK(0x3,0) //((uint32_t)0x00000003)
#define SDHC_MMCBOOT_BOOTBLKCNT(n) MAKE_REG_MASK(0xFF,16) //(uint32_t)(((n) & 0xFFF)<<16) // stop at block gap value of automatic mode
#define SDHC_MMCBOOT_AUTOSABGEN MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // enable auto stop at block gap function
#define SDHC_MMCBOOT_BOOTEN MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Boot Mode Enable
#define SDHC_MMCBOOT_BOOTMODE MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Boot Mode Select
#define SDHC_MMCBOOT_BOOTACK MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Boot Ack Mode Select
#define SDHC_MMCBOOT_DTOCVACK(n) MAKE_REG_MASK(0xF,0) //(uint32_t)(((n) & 0xF)<<0) // Boot ACK Time Out Counter Value
//#define SDHC_HOSTVER (*(volatile uint32_t *)0x400B10FC) // Host Controller Version
#define CCM_ANALOG_PFD_528_PFD0_FRAC_MASK 0x3f
#define CCM_ANALOG_PFD_528_PFD0_FRAC(n) ((n) & CCM_ANALOG_PFD_528_PFD0_FRAC_MASK)
#define CCM_ANALOG_PFD_528_PFD1_FRAC_MASK (0x3f<<8)
#define CCM_ANALOG_PFD_528_PFD1_FRAC(n) (((n)<<8) & CCM_ANALOG_PFD_528_PFD1_FRAC_MASK)
#define CCM_ANALOG_PFD_528_PFD2_FRAC_MASK (0x3f<<16)
#define CCM_ANALOG_PFD_528_PFD2_FRAC(n) (((n)<<16) & CCM_ANALOG_PFD_528_PFD2_FRAC_MASK)
#define CCM_ANALOG_PFD_528_PFD3_FRAC_MASK ((0x3f<<24)
#define CCM_ANALOG_PFD_528_PFD3_FRAC(n) (((n)<<24) & CCM_ANALOG_PFD_528_PFD3_FRAC_MASK)
#define SDHC_DSADDR (USDHC1_DS_ADDR ) // DMA System Address register
#define SDHC_BLKATTR (USDHC1_BLK_ATT) // Block Attributes register
#define SDHC_CMDARG (USDHC1_CMD_ARG) // Command Argument register
#define SDHC_XFERTYP (USDHC1_CMD_XFR_TYP) // Transfer Type register
#define SDHC_CMDRSP0 (USDHC1_CMD_RSP0) // Command Response 0
#define SDHC_CMDRSP1 (USDHC1_CMD_RSP1) // Command Response 1
#define SDHC_CMDRSP2 (USDHC1_CMD_RSP2) // Command Response 2
#define SDHC_CMDRSP3 (USDHC1_CMD_RSP3) // Command Response 3
#define SDHC_DATPORT (USDHC1_DATA_BUFF_ACC_PORT) // Buffer Data Port register
#define SDHC_PRSSTAT (USDHC1_PRES_STATE) // Present State register
#define SDHC_PROCTL (USDHC1_PROT_CTRL) // Protocol Control register
#define SDHC_SYSCTL (USDHC1_SYS_CTRL) // System Control register
#define SDHC_IRQSTAT (USDHC1_INT_STATUS) // Interrupt Status register
#define SDHC_IRQSTATEN (USDHC1_INT_STATUS_EN) // Interrupt Status Enable register
#define SDHC_IRQSIGEN (USDHC1_INT_SIGNAL_EN) // Interrupt Signal Enable register
#define SDHC_AC12ERR (USDHC1_AUTOCMD12_ERR_STATUS) // Auto CMD12 Error Status Register
#define SDHC_HTCAPBLT (USDHC1_HOST_CTRL_CAP) // Host Controller Capabilities
#define SDHC_WML (USDHC1_WTMK_LVL) // Watermark Level Register
#define SDHC_MIX_CTRL (USDHC1_MIX_CTRL) // Mixer Control
#define SDHC_FEVT (USDHC1_FORCE_EVENT) // Force Event register
#define SDHC_ADMAES (USDHC1_ADMA_ERR_STATUS) // ADMA Error Status register
#define SDHC_ADSADDR (USDHC1_ADMA_SYS_ADDR) // ADMA System Addressregister
#define SDHC_VENDOR (USDHC1_VEND_SPEC) // Vendor Specific register
#define SDHC_MMCBOOT (USDHC1_MMC_BOOT) // MMC Boot register
#define SDHC_VENDOR2 (USDHC2_VEND_SPEC2) // Vendor Specific2 register
//
//#define IRQ_SDHC IRQ_SDHC1
#define SDHC_MAX_DVS (0xF + 1U)
#define SDHC_MAX_CLKFS (0xFF + 1U)
#define SDHC_PREV_DVS(x) ((x) -= 1U)
#define SDHC_PREV_CLKFS(x, y) ((x) >>= (y))
#define CCM_CSCDR1_USDHC1_CLK_PODF_MASK (0x7<<11)
#define CCM_CSCDR1_USDHC1_CLK_PODF(n) (((n)&0x7)<<11)
#define IOMUXC_SW_PAD_CTL_PAD_SRE ((0x1<)<0)
#define IOMUXC_SW_PAD_CTL_PAD_PKE ((0x1)<<12)
#define IOMUXC_SW_PAD_CTL_PAD_PUE ((0x1)<<13)
#define IOMUXC_SW_PAD_CTL_PAD_HYS ((0x1)<<16)
#define IOMUXC_SW_PAD_CTL_PAD_SPEED(n) (((n)&0x3)<<6)
#define IOMUXC_SW_PAD_CTL_PAD_PUS(n) (((n)&0x3)<<14)
#define IOMUXC_SW_PAD_CTL_PAD_PUS_MASK ((0x3)<<14)
#define IOMUXC_SW_PAD_CTL_PAD_DSE(n) (((n)&0x7)<<3)
#define IOMUXC_SW_PAD_CTL_PAD_DSE_MASK ((0x7)<<3)
#endif // __IMXRT1062__
#define SDHC_IRQSIGEN_DMA_MASK (SDHC_IRQSIGEN_TCIEN | SDHC_IRQSIGEN_DINTIEN | SDHC_IRQSIGEN_DMAEIEN)
#define CARD_STATUS_READY_FOR_DATA (1UL << 8)
/******************************************************************************
Types
******************************************************************************/
typedef struct {
uint8_t status;
uint8_t highCapacity;
uint8_t version2;
uint8_t tranSpeed;
uint32_t address;
uint32_t numBlocks;
uint32_t lastCardStatus;
} SD_CARD_DESCRIPTOR;
/******************************************************************************
Global functions
******************************************************************************/
/******************************************************************************
Private variables
******************************************************************************/
static SD_CARD_DESCRIPTOR sdCardDesc;
static volatile uint32_t dmaDone=0;
//
/******************************************************************************
Forward declaration of private functions
******************************************************************************/
static void sdhc_setSdclk(uint32_t kHzMax);
static uint8_t SDHC_Init(void);
static void SDHC_InitGPIO(void);
static void SDHC_ReleaseGPIO(void);
//static void SDHC_SetClock(uint32_t sysctl);
static uint32_t SDHC_WaitStatus(uint32_t mask);
static int SDHC_ReadBlock(uint32_t* pData);
static int SDHC_WriteBlock(const uint32_t* pData);
static int SDHC_CMD_Do(uint32_t xfertyp);
static int SDHC_CMD0_GoToIdle(void);
static int SDHC_CMD2_Identify(void);
static int SDHC_CMD3_GetAddress(void);
static int SDHC_ACMD6_SetBusWidth(uint32_t address, uint32_t width);
static int SDHC_CMD7_SelectCard(uint32_t address);
static int SDHC_CMD8_SetInterface(uint32_t cond);
static int SDHC_CMD9_GetParameters(uint32_t address);
static int SDHC_CMD12_StopTransfer(void);
static int SDHC_CMD12_StopTransferWaitForBusy(void);
static int SDHC_CMD16_SetBlockSize(uint32_t block_size);
static int SDHC_CMD17_ReadBlock(uint32_t sector);
static int SDHC_CMD24_WriteBlock(uint32_t sector);
static int SDHC_ACMD41_SendOperationCond(uint32_t cond);
/******************************************************************************
Public functions
******************************************************************************/
uint8_t SDHC_CardGetType(void)
{
if (sdCardDesc.status) return 0;
if (sdCardDesc.version2 == 0) return 1; // SD_CARD_TYPE_SD1
if (sdCardDesc.highCapacity == 0) return 2; // SD_CARD_TYPE_SD2
return 3; // SD_CARD_TYPE_SDHC
}
//-----------------------------------------------------------------------------
// initialize the SDHC Controller and SD Card
// returns status of initialization(OK, nonInit, noCard, CardProtected)
uint8_t SDHC_CardInit(void)
{
uint8_t resS;
int resR;
resS = SDHC_Init();
sdCardDesc.status = resS;
sdCardDesc.address = 0;
sdCardDesc.highCapacity = 0;
sdCardDesc.version2 = 0;
sdCardDesc.numBlocks = 0;
if (resS)
return resS;
SDHC_IRQSIGEN = 0;
resR = SDHC_CMD0_GoToIdle();
if (resR) {
sdCardDesc.status = SDHC_STATUS_NOINIT;
return SDHC_STATUS_NOINIT;
}
resR = SDHC_CMD8_SetInterface(0x000001AA); // 3.3V and AA check pattern
if (resR == SDHC_RESULT_OK) {
if (SDHC_CMDRSP0 != 0x000001AA) {
sdCardDesc.status = SDHC_STATUS_NOINIT;
return SDHC_STATUS_NOINIT;
}
sdCardDesc.highCapacity = 1;
} else if (resR == SDHC_RESULT_NO_RESPONSE) {
// version 1 cards do not respond to CMD8
} else {
sdCardDesc.status = SDHC_STATUS_NOINIT;
return SDHC_STATUS_NOINIT;
}
if (SDHC_ACMD41_SendOperationCond(0)) return sdCardDesc.status = SDHC_STATUS_NOINIT;
if (SDHC_CMDRSP0 & 0x300000) {
uint32_t condition = 0x00300000;
if (sdCardDesc.highCapacity) condition |= 0x40000000;
//
uint32_t ii = 0;
do {
ii++;
if (SDHC_ACMD41_SendOperationCond(condition)) {
resS = SDHC_STATUS_NOINIT;
break;
}
} while ((!(SDHC_CMDRSP0 & 0x80000000)) && (ii < SDHC_INITIALIZATION_MAX_CNT));
if (resS) return resS;
if ((ii >= SDHC_INITIALIZATION_MAX_CNT) || (!(SDHC_CMDRSP0 & 0x40000000)))
sdCardDesc.highCapacity = 0;
}
// Card identify
if (SDHC_CMD2_Identify()) return sdCardDesc.status = SDHC_STATUS_NOINIT;
// Get card address
if (SDHC_CMD3_GetAddress()) return sdCardDesc.status = SDHC_STATUS_NOINIT;
sdCardDesc.address = SDHC_CMDRSP0 & 0xFFFF0000;
// Get card parameters
if (SDHC_CMD9_GetParameters(sdCardDesc.address)) return sdCardDesc.status = SDHC_STATUS_NOINIT;
if (!(SDHC_CMDRSP3 & 0x00C00000)) {
uint32_t read_bl_len, c_size, c_size_mult;
read_bl_len = (SDHC_CMDRSP2 >> 8) & 0x0F;
c_size = SDHC_CMDRSP2 & 0x03;
c_size = (c_size << 10) | (SDHC_CMDRSP1 >> 22);
c_size_mult = (SDHC_CMDRSP1 >> 7) & 0x07;
sdCardDesc.numBlocks = (c_size + 1) * (1 << (c_size_mult + 2)) * (1 << (read_bl_len - 9));
} else {
uint32_t c_size;
sdCardDesc.version2 = 1;
c_size = (SDHC_CMDRSP1 >> 8) & 0x003FFFFF;
sdCardDesc.numBlocks = (c_size + 1) << 10;
}
// Select card
if (SDHC_CMD7_SelectCard(sdCardDesc.address)) return sdCardDesc.status = SDHC_STATUS_NOINIT;
// Set Block Size to 512
// Block Size in SDHC Controller is already set to 512 by SDHC_Init();
// Set 512 Block size in SD card
if (SDHC_CMD16_SetBlockSize(SDHC_BLOCK_SIZE)) return sdCardDesc.status = SDHC_STATUS_NOINIT;
// Set 4 bit data bus width
if (SDHC_ACMD6_SetBusWidth(sdCardDesc.address, 2)) return sdCardDesc.status = SDHC_STATUS_NOINIT;
// Set Data bus width also in SDHC controller
SDHC_PROCTL &= ~SDHC_PROCTL_DTW_MASK;
SDHC_PROCTL |= SDHC_PROCTL_DTW(SDHC_PROCTL_DTW_4BIT);
// De-Init GPIO
SDHC_ReleaseGPIO();
// Set the SDHC default baud rate
sdhc_setSdclk(25000);
// SDHC_SetClock(SDHC_SYSCTL_25MHZ);
// TODO: use CMD6 and CMD9 to detect if card supports 50 MHz
// then use CMD4 to configure card to high speed mode,
// and SDHC_SetClock() for 50 MHz config
// Init GPIO
SDHC_InitGPIO();
return sdCardDesc.status;
}
//-----------------------------------------------------------------------------
// FUNCTION: SDHC_CardReadBlock (disk_read)
// SCOPE: SDHC public related function
// DESCRIPTION: Function read block to disk
//
// PARAMETERS: buff - pointer on buffer where read data should be stored
// sector - index of sector
//
// RETURNS: result of operation
//-----------------------------------------------------------------------------
#if 1
// read a block from disk, using polling
// buff - pointer on buffer where read data should be stored
// sector - index of start sector
int SDHC_CardReadBlock(void * buff, uint32_t sector)
{
int result;
uint32_t* pData = (uint32_t*)buff;
// Check if this is ready
if (sdCardDesc.status != 0)
return SDHC_RESULT_NOT_READY;
// Convert LBA to uint8_t address if needed
if (!sdCardDesc.highCapacity)
sector *= 512;
SDHC_IRQSTAT = 0xffff;
#if defined(__IMXRT1062__)
SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DTDSEL;
#endif
// Just single block mode is needed
result = SDHC_CMD17_ReadBlock(sector);
if(result != SDHC_RESULT_OK) return result;
result = SDHC_ReadBlock(pData);
// finish up
while (!(SDHC_IRQSTAT & SDHC_IRQSTAT_TC)) { } // wait for transfer to complete
SDHC_IRQSTAT = (SDHC_IRQSTAT_TC | SDHC_IRQSTAT_BRR | SDHC_IRQSTAT_AC12E);
return result;
}
#else
// read a block from disk, using DMA & interrupts
int SDHC_CardReadBlock(void * buff, uint32_t sector)
{
int result=0;
uint32_t* pData = (uint32_t*)buff;
/* check alignment for DMA */
if (reinterpret_cast<uintptr_t>(static_cast<const void*>(buff)) % 4) {
return -1;
}
// Serial.print("Sector: "); Serial.println(sector); Serial.flush();
// Check if this is ready
if (sdCardDesc.status != 0) return SDHC_RESULT_NOT_READY;
while ((SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB) || (SDHC_PRSSTAT & SDHC_PRSSTAT_CDIHB));
// Convert LBA to BYTE address if needed
if (!sdCardDesc.highCapacity) sector *= 512;
// clear status
SDHC_IRQSTAT = SDHC_IRQSTAT;
// use dma: disabling polling
uint32_t irqstat = SDHC_IRQSTATEN;
irqstat &= ~(SDHC_IRQSTATEN_BRRSEN | SDHC_IRQSTATEN_BWRSEN | SDHC_IRQSTATEN_CCSEN) ;
irqstat &= ~(SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_CCESEN) ;
// enable status
irqstat |= SDHC_IRQSTATEN_DMAESEN | SDHC_IRQSTATEN_DINTSEN | SDHC_IRQSTATEN_TCSEN ;
SDHC_IRQSTATEN = irqstat;
uint32_t sigen = SDHC_IRQSIGEN;
sigen |= SDHC_IRQSIGEN_DMA_MASK ;
SDHC_SYSCTL |= SDHC_SYSCTL_HCKEN;
#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DTDSEL ; // read
SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DMAEN ; // DMA
#endif
uint32_t xfertyp = SDHC_XFERTYP_CMDINX(SDHC_CMD17) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48) | SDHC_XFERTYP_DPSEL
| SDHC_XFERTYP_DTDSEL | SDHC_XFERTYP_DMAEN;
dmaDone=0;
SDHC_DSADDR = (uint32_t)buff;
SDHC_CMDARG = sector;
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(512);
SDHC_IRQSIGEN = sigen;
SDHC_XFERTYP = xfertyp;
//
while(!dmaDone);
SDHC_IRQSTAT &= (SDHC_IRQSTAT_CC | SDHC_IRQSTAT_TC);
return result;
}
#endif
//-----------------------------------------------------------------------------
// FUNCTION: SDHC_CardWriteBlock (disk_write)
// SCOPE: SDHC public related function
// DESCRIPTION: Function write block to disk
//
// PARAMETERS: buff - pointer on buffer where is stored data
// sector - index of sector
//
// RETURNS: result of operation
//-----------------------------------------------------------------------------
#if 1
int SDHC_CardWriteBlock(const void * buff, uint32_t sector)
{
int result;
const uint32_t *pData = (const uint32_t *)buff;
// Check if this is ready
if (sdCardDesc.status != 0) return SDHC_RESULT_NOT_READY;
// Convert LBA to uint8_t address if needed
if(!sdCardDesc.highCapacity)
sector *= 512;
//SDHC_IRQSTAT = 0xffff;
SDHC_IRQSTAT = SDHC_IRQSTAT;
#if defined(__IMXRT1062__)
SDHC_MIX_CTRL &= ~SDHC_MIX_CTRL_DTDSEL;
#endif
// Just single block mode is needed
result = SDHC_CMD24_WriteBlock(sector);
if (result != SDHC_RESULT_OK) return result;
result = SDHC_WriteBlock(pData);
// finish up
while (!(SDHC_IRQSTAT & SDHC_IRQSTAT_TC)) { } // wait for transfer to complete
SDHC_IRQSTAT = (SDHC_IRQSTAT_TC | SDHC_IRQSTAT_BWR | SDHC_IRQSTAT_AC12E);
return result;
}
#else
int SDHC_CardWriteBlock(const void * buff, uint32_t sector)
{
int result=0;
const uint32_t *pData = (const uint32_t *)buff;
/* check alignment for DMA */
if (reinterpret_cast<uintptr_t>(static_cast<const void*>(buff)) % 4) {
return -1;
}
// Check if this is ready
if (sdCardDesc.status != 0) return SDHC_RESULT_NOT_READY;
while ((SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB) || (SDHC_PRSSTAT & SDHC_PRSSTAT_CDIHB)) ;
// Convert LBA to uint8_t address if needed
if (!sdCardDesc.highCapacity) sector *= 512;
// clear status
SDHC_IRQSTAT = SDHC_IRQSTAT;
uint32_t irqstat = SDHC_IRQSTATEN;
// use dma: disabling polling
irqstat &= ~(SDHC_IRQSTATEN_BRRSEN | SDHC_IRQSTATEN_BWRSEN | SDHC_IRQSTATEN_CCSEN) ;
irqstat &= ~(SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_CCESEN) ;
// enable status
irqstat |= /*SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_CCESEN | */SDHC_IRQSTATEN_DMAESEN ;
irqstat |= SDHC_IRQSTATEN_DINTSEN | SDHC_IRQSTATEN_TCSEN ;
SDHC_IRQSTATEN = irqstat;
uint32_t sigen = SDHC_IRQSIGEN;
sigen |= SDHC_IRQSIGEN_DMA_MASK ;
SDHC_SYSCTL |= SDHC_SYSCTL_HCKEN;
#if defined(__IMXRT1052__)
SDHC_MIX_CTRL &= ~ SDHC_MIX_CTRL_DTDSEL; // write
SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DMAEN ; //DMA
#endif
uint32_t xfertyp = SDHC_XFERTYP_CMDINX(SDHC_CMD24) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48) | SDHC_XFERTYP_DPSEL
| SDHC_XFERTYP_DMAEN;
dmaDone=0;
SDHC_DSADDR = (uint32_t)buff;
SDHC_CMDARG = sector;
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(512);
SDHC_IRQSIGEN = sigen;
SDHC_XFERTYP = xfertyp;
//
while(!dmaDone);
SDHC_IRQSTAT &= (SDHC_IRQSTAT_CC | SDHC_IRQSTAT_TC);
while(SDHC_PRSSTAT & SDHC_PRSSTAT_DLA);
//check for uSD status
do
{ while ((SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB) || (SDHC_PRSSTAT & SDHC_PRSSTAT_CDIHB)) ;
SDHC_IRQSTATEN |= SDHC_IRQSTATEN_CCSEN;
SDHC_IRQSTAT=SDHC_IRQSTAT;
// CMD13 to check uSD status
xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD13) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48));
//
SDHC_CMDARG = sdCardDesc.address;
SDHC_XFERTYP = xfertyp;
while(!(SDHC_IRQSTAT & SDHC_IRQSTAT_CC)); SDHC_IRQSTAT &= SDHC_IRQSTAT_CC;
} while(SDHC_CMDRSP0 & 0x200); // while data?
// } while(!(SDHC_CMDRSP0 & CARD_STATUS_READY_FOR_DATA ));
return result;
}
#endif
/******************************************************************************
Private functions
******************************************************************************/
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
// Teensy 3.5 & 3.6
// initialize the SDHC Controller signals
static void SDHC_InitGPIO(void)
{
PORTE_PCR0 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.D1 */
PORTE_PCR1 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.D0 */
PORTE_PCR2 = PORT_PCR_MUX(4) | PORT_PCR_DSE; /* SDHC.CLK */
PORTE_PCR3 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.CMD */
PORTE_PCR4 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.D3 */
PORTE_PCR5 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.D2 */
}
// release the SDHC Controller signals
static void SDHC_ReleaseGPIO(void)
{
PORTE_PCR0 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D1 */
PORTE_PCR1 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D0 */
PORTE_PCR2 = 0; /* SDHC.CLK */
PORTE_PCR3 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.CMD */
PORTE_PCR4 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D3 */
PORTE_PCR5 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D2 */
}
void initClock()
{
#ifdef HAS_KINETIS_MPU
// Allow SDHC Bus Master access.
MPU_RGDAAC0 |= 0x0C000000;
#endif
// Enable SDHC clock.
SIM_SCGC3 |= SIM_SCGC3_SDHC;
}
uint32_t sdhcClock()
{ return F_CPU;
}
#else
// Teensy 4.0
static void SDHC_InitGPIO(void)
{
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_04 = 0; //DAT2
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_05 = 0; //DAT3
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_00 = 0; //CMD
//3.3V
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_01 = 0; //CLK
//GND
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_02 = 0; //DAT0
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_03 = 0; //DAT1
const uint32_t CLOCK_MASK = IOMUXC_SW_PAD_CTL_PAD_PKE |
IOMUXC_SW_PAD_CTL_PAD_DSE(1) |
IOMUXC_SW_PAD_CTL_PAD_SPEED(2);
const uint32_t DATA_MASK = CLOCK_MASK |
(IOMUXC_SW_PAD_CTL_PAD_PUE | IOMUXC_SW_PAD_CTL_PAD_PUS(1));
IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_04 = DATA_MASK;
IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_05 = DATA_MASK;
IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_00 = DATA_MASK;
IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_01 = CLOCK_MASK;
IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_02 = DATA_MASK;
IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_03 = DATA_MASK;
}
static void SDHC_ReleaseGPIO(void)
{
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_04 = 5; //GPIO3_IO16
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_05 = 5; //GPIO3_IO17
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_00 = 5; //GPIO3_IO12
//3.3V
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_01 = 5; //GPIO3_IO13
//GND
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_02 = 5; //GPIO3_IO14
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_03 = 5; //GPIO3_IO15
}
void initClock()
{
/* set PDF_528 PLL2PFD0 */
CCM_ANALOG_PFD_528 |= (1 << 7);
CCM_ANALOG_PFD_528 &= ~(0x3F << 0);
CCM_ANALOG_PFD_528 |= ((24) & 0x3F << 0); // 12 - 35
CCM_ANALOG_PFD_528 &= ~(1 << 7);
/* Enable USDHC clock. */
CCM_CCGR6 |= CCM_CCGR6_USDHC1(CCM_CCGR_ON);
CCM_CSCDR1 &= ~(CCM_CSCDR1_USDHC1_CLK_PODF_MASK);
//
// CCM_CSCMR1 &= ~(CCM_CSCMR1_USDHC1_CLK_SEL); // PLL2PFD2
CCM_CSCMR1 |= CCM_CSCMR1_USDHC1_CLK_SEL; // PLL2PFD0
CCM_CSCDR1 |= CCM_CSCDR1_USDHC1_CLK_PODF((7)); // &0x7
// for testing
//CCM_CCOSR = CCM_CCOSR_CLKO1_EN | CCM_CCOSR_CLKO1_DIV(7) | CCM_CCOSR_CLKO1_SEL(1); //(1: SYS_PLL/2)
//IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_04 = 6; //CCM_CLKO1 (0 is USDHC1_DAT2)
// for testing
//CCM_CCOSR |= (CCM_CCOSR_CLKO2_EN | CCM_CCOSR_CLKO2_DIV(7) | CCM_CCOSR_CLKO2_SEL(3)); //(3: usdhc1_clk_root))
//IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_05 = 6; //CCM_CLKO2 (0 is USDHC1_DAT3)
}
uint32_t sdhcClock()
{
uint32_t divider = ((CCM_CSCDR1 >> 11) & 0x7) + 1;
uint32_t PLL2PFD0 = (528000000U * 3) / ((CCM_ANALOG_PFD_528 & 0x3F) / 6) / divider;
return PLL2PFD0;
}
#endif
/* //may be useful for debugging
static void printRegs()
{
// Serial.print("DS_ADDR: "); Serial.println(SDHC_DSADDR,HEX); // DMA System Address register
Serial.print("BLK_ATT: "); Serial.println(SDHC_BLKATTR,HEX); // Block Attributes register
// Serial.print("CMD_ARG: "); Serial.println(SDHC_CMDARG,HEX); // Command Argument register
// Serial.print("CMD_XFR_TYP: "); Serial.println(SDHC_XFERTYP,HEX); // Transfer Type register
// Serial.print("CMD_RSP0: "); Serial.println(SDHC_CMDRSP0,HEX); // Command Response 0
// Serial.print("CMD_RSP1: "); Serial.println(SDHC_CMDRSP1,HEX); // Command Response 1
// Serial.print("CMD_RSP2: "); Serial.println(SDHC_CMDRSP2,HEX); // Command Response 2
// Serial.print("CMD_RSP3: "); Serial.println(SDHC_CMDRSP3,HEX); // Command Response 3
// Serial.print("DATA_BUFF_ACC_POR: "); Serial.println(SDHC_DATPORT,HEX); // Buffer Data Port register
Serial.print("PRES_STATE: "); Serial.println(SDHC_PRSSTAT,HEX); // Present State register
Serial.print("PROT_CTRL: "); Serial.println(SDHC_PROCTL,HEX); // Protocol Control register
Serial.print("SYS_CTRL: "); Serial.println(SDHC_SYSCTL,HEX); // System Control register
Serial.print("INT_STATUS: "); Serial.println(SDHC_IRQSTAT,HEX); // Interrupt Status register
Serial.print("INT_STATUS_EN: "); Serial.println(SDHC_IRQSTATEN,HEX); // Interrupt Status Enable register
Serial.print("INT_SIGNAL_EN: "); Serial.println(SDHC_IRQSIGEN,HEX); // Interrupt Signal Enable register
// Serial.print("AUTOCMD12_ERR_STATUS: "); Serial.println(SDHC_AC12ERR,HEX); // Auto CMD12 Error Status Register
Serial.print("HOST_CTRL_CAP: "); Serial.println(SDHC_HTCAPBLT,HEX); // Host Controller Capabilities
Serial.print("WTMK_LVL: "); Serial.println(SDHC_WML,HEX); // Watermark Level Register
#if defined(__IMXRT1052__)
Serial.print("MIX_CTRL: "); Serial.println(SDHC_MIX_CTRL,HEX); // Mixer Control
#endif
// Serial.print("FORCE_EVENT: "); Serial.println(SDHC_FEVT,HEX); // Force Event register
// Serial.print("ADMA_ERR_STATUS: "); Serial.println(SDHC_ADMAES,HEX); // ADMA Error Status register
// Serial.print("ADMA_SYS_ADDR: "); Serial.println(SDHC_ADSADDR,HEX); // ADMA System Addressregister
Serial.print("VEND_SPEC: "); Serial.println(SDHC_VENDOR,HEX); // Vendor Specific register
// Serial.print("MMC_BOOT: "); Serial.println(SDHC_MMCBOOT,HEX); // MMC Boot register
#if defined(__IMXRT1052__)
Serial.print("VEND_SPEC2: "); Serial.println(SDHC_VENDOR2,HEX); // Vendor Specific2 register
#endif
}
*/
static void sdhc_setSdclk(uint32_t kHzMax) {
const uint32_t DVS_LIMIT = 0X10;
const uint32_t SDCLKFS_LIMIT = 0X100;
uint32_t dvs = 1;
uint32_t sdclkfs = 1;
uint32_t maxSdclk = 1000 * kHzMax;
// uint32_t f_pll = F_CPU;
uint32_t f_pll = sdhcClock();
while ((f_pll / (sdclkfs * DVS_LIMIT) > maxSdclk) && (sdclkfs < SDCLKFS_LIMIT)) {
sdclkfs <<= 1;
}
while ((f_pll / (sdclkfs * dvs) > maxSdclk) && (dvs < DVS_LIMIT)) {
dvs++;
}
//uint32_t m_sdClkKhz = f_pll / (1000 * sdclkfs * dvs);
sdclkfs >>= 1;
dvs--;
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
// Disable SDHC clock.
SDHC_SYSCTL &= ~SDHC_SYSCTL_SDCLKEN;
#endif
// Change dividers.
uint32_t sysctl = SDHC_SYSCTL & ~(SDHC_SYSCTL_DTOCV_MASK
| SDHC_SYSCTL_DVS_MASK | SDHC_SYSCTL_SDCLKFS_MASK);
SDHC_SYSCTL = sysctl | SDHC_SYSCTL_DTOCV(0x0E) | SDHC_SYSCTL_DVS(dvs)
| SDHC_SYSCTL_SDCLKFS(sdclkfs);
// Wait until the SDHC clock is stable.
while (!(SDHC_PRSSTAT & SDHC_PRSSTAT_SDSTB)) { }
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
// Enable the SDHC clock.
SDHC_SYSCTL |= SDHC_SYSCTL_SDCLKEN;
#endif
// Serial.printf("setSdclk: %d %d : %x %x\n\r", f_pll, m_sdClkKhz, sdclkfs, dvs);
}
#if 0
void sdhc_isr(void)
{ SDHC_IRQSIGEN &= ~SDHC_IRQSIGEN_DMA_MASK;
//
// Serial.print("IRQ1: "); Serial.println(SDHC_IRQSTAT,HEX);
while(!(SDHC_IRQSTAT & SDHC_IRQSTAT_TC));// SDHC_IRQSTAT &= ~SDHC_IRQSTAT_TC;
#if defined(__IMXRT1052__)
SDHC_MIX_CTRL &= ~(SDHC_MIX_CTRL_AC23EN | SDHC_MIX_CTRL_DMAEN) ;
#endif
// for T3.6, seems not to hurt for T4
if(SDHC_SYSCTL & SDHC_SYSCTL_HCKEN) SDHC_SYSCTL &= ~SDHC_SYSCTL_HCKEN;
SDHC_PROCTL &= ~SDHC_PROCTL_D3CD; SDHC_PROCTL |= SDHC_PROCTL_D3CD;
dmaDone=1;
}
#endif
// initialize the SDHC Controller