-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathmmc_api.c
More file actions
2355 lines (1905 loc) · 71.4 KB
/
mmc_api.c
File metadata and controls
2355 lines (1905 loc) · 71.4 KB
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
//---------------------------------------------------------------------------
// P/ECE MMC制御関連ルーチン
// 2004/05/02 by まどか 作成開始
// 2004/05/16 by まどか 読み込み時のセクタやクラスタの計算が
// 少し間違っていたのを修正。
// 2004/08/29 by まどか mmcFileReadSctでmmcFileReadSct(&pfa, NULL, sct, 0);
// とした場合に、内部の代替バッファに何も読み込まれて
// いなかった不具合を修正。また、mmcFileReadMMCSctでも
// 同様に修正。そして、mmcFileReadMMCSctでは代替バッファ
// アクセス保証サイズを512バイトに変更。
// 2004/08/30 by まどか SDカードと初期化に時間がかかるMMCに対応。
// 情報提供してくださったnsawaさん(http://piece.no-ip.org/)
// ありがとうございますm(-_-)m
// 2004/11/06 by まどか スーパーフロッピー形式に対応しました。
// 情報提供してくださったnsawaさん(http://piece.no-ip.org/)
// ありがとうございますm(-_-)m
// 2004/11/15 by N.SAWA MS-DOSのショートファイル名として許される文字を使っている
// エントリを検索結果に含める処理を追加しました
// ディレクトリ・エントリまたはボリュームラベルの属性を持つ
// エントリを検索から除外する処理を追加しました。
// アプリケーションに直接組み込んでコンパイルする場合に
// 必要の無い部分を#ifdef __PCEKN__マクロにて除外しました。
// 2004/12/12 by N.SAWA mmcInit()にpceFile系APIをフックし、本体FlashROMとMMCを
// 区別なく扱えるようにしました。
// また、mmcExit()時にフックを解除します。
// 2004/12/12 by N.SAWA mmcFileReadSct()にて、ファイル終端を超える読み込みバイト
// 数が指定された場合は、読み込みバイト数を切り詰めるように
// 変更しました。pceFileReadSct()との互換のためです。
// 2004/12/12 by N.SAWA mmcFileReadSct()にて、ファイル終端を超える読み込みバイト
// 数が指定された場合は、読み込みバイト数を切り詰めるように
// 変更しました。pceFileReadSct()との互換のためです。
// 2004/12/12 by N.SAWA 高速化のため、mmcByteSend()とmmcRecvData()をmmc_fram.cへ
// 移動しました。
// 2004/12/12 by N.SAWA mmcByteRecv()は使われていないので削除しました。
// SEND_CLOCK_WAITも不要になったので削除しました。
// 2004/12/12 by N.SAWA 高速化のため、mmcFileReadSct()とmmcFileReadMMCSct()での
// 接続確認は省きました。
// 2004/12/12 by N.SAWA mmcFileReadSct()は割り込み内から利用します。割り込み中
// はスタックをFRAM2エリアに切り替えるためスタック領域が少
// なく、ucaBuff[512]によってスタックが溢れるのを防ぐため、
// staticに変更しました。
// その他の関数にもやや大きめのローカル配列がありますが、
// 割り込み内から利用しないので、そのままにしてあります。
// 2005/03/20 追記 by まどか
// 上記の修正を加えようとしたのですが、カーネル内で512バイト
// のstatic変数を取ることは、メモリ残量の関係で見送らざるを
// 得なくなりました。
// ですので、高速RAM上にスタックを切り替えて利用する場合は、
// ご注意ください。
// 2004/12/12 by N.SAWA 代替バッファ未割り当ての状態で、割り込み中に初回読み込み
// を行った場合、割り込み内でpceHeapAlloc()を使ってしまうこ
// とになり危険ですので、代替バッファは無条件で最初に確保し
// てしまうことにしました。
// 2004/12/13 by N.SAWA mmcWriteSector()を追加しました。
// それに伴い、mmcByteRecv()を復元しました。
// 2005/02/09 by まどか PMFプレイヤーを製作する際に、読み込み速度が間に合わないので
// いくつかの個所を微妙に高速化。
// そして、mmcSendDataCoreとmmcSendCommandAndRecvResponseを
// 高速RAM上に移動。※カーネル側では高速RAM上に置きません。
// 2005/03/12 by まどか mmcFileReadSct内でグローバル変数をローカルに移して使用し
// 微妙に高速化を図ってみました。
// また、nsawaさんの書き込み関連関数を#if 0で隠しました。
// 2005/03/12 by まどか Ver.1.27からカーネル側でMMCの初期化を試みるようにしたの
// で、その実行結果を取得する
// unsigned char mmcGetInitResult(void) を追加。
// 2005/03/20 by まどか 512MB以上1GB以内のメモリカードに対応しました。
// 2005/03/20 by まどか 高速化のため、mmcFileFindNext()での接続確認は省きました。
// 2005/04/02 by まどか システムメニューで設定するカーネル側MMC初期化有効フラグ
// を追加しました。
// 2005/04/05 by まどか mmcFileReadSctでptr=NULL,len=0がまた正常に動かなくなって
// しまっていた不具合を修正しました。
// この修正に伴ない、mmcFileReadMMCSctに切り詰め処理も追加。
// 2005/04/24 by まどか ファイル検索時に扱える最大サイズぴったりのファイルがはじ
// かれる条件式だったのを修正。(情報提供:nsawaさん)
// 2005/05/04 by まどか MMCライブラリをカーネルではなくアプリ側で利用する場合は、
// ワークエリアをヒープから確保しないで、グローバル配列とし
// て定義できるように変更。従来どおりヒープから取ることも
// 可能です。ワークエリアをグローバル配列で取る場合は、
// Makefileで__MMC_WORK_GLOBAL__を定義してください。
// 2005/05/04 by まどか pceFile系APIのフックは__PCEFILE_API_HOOK__の定義をもって
// フックする・しないを制御することにしました。
// 2005/05/07 by まどか 扱える最大ファイルサイズがカードの容量を超える場合は、最大
// ファイルサイズをカードの容量に切り詰めるように修正しました。
// これにより、64MBのカードで50MB以上のファイルが扱えなかった
// 不具合も修正されます。
//
//
// H P:http://www2.plala.or.jp/madoka/
// E-mail:madoka@olive.plala.or.jp
//
//タブは4で見てください
//---------------------------------------------------------------------------
//■■ ファイルインクルード ■■■■■■■■■■■■■■■■■■■■■■■■■
//---------------------------------------------------------------------------
#include <s1c33cpu.h>
#include <string.h>
#include <stdio.h>
#include <piece.h>
#include "mmc_api.h"
#ifdef __PCEKN__ // 2004/11/15 Add by N.SAWA
#include "pcekn.h"
#endif //#ifdef PCEKN // 2004/11/15 Add by N.SAWA
//---------------------------------------------------------------------------
//■■ レジスタアクセス定義 ■■■■■■■■■■■■■■■■■■■■■■■■■
//---------------------------------------------------------------------------
//各レジスタへのアドレス
//入出力兼用ポート関連
//CPUデータシートP.370,P.372参照
#define P0CF (*(volatile unsigned char*)0x402D0) //P0機能選択レジスタ
#define P0D (*(volatile unsigned char*)0x402D1) //P0入出力兼用ポートデータレジスタ
#define P0IOC (*(volatile unsigned char*)0x402D2) //P0I/O制御レジスタ
#define P1CF (*(volatile unsigned char*)0x402D4) //P1機能選択レジスタ
#define P1D (*(volatile unsigned char*)0x402D5) //P1入出力兼用ポートデータレジスタ
#define P1IOC (*(volatile unsigned char*)0x402D6) //P1I/O制御レジスタ
#define PCFEX (*(volatile unsigned char*)0x402DF) //ポート機能拡張レジスタ
//マクロ定義
#define CARD_ENABLE { P1D &= ~(1 << 4); } //カードをActiveにします
#define CARD_DISABLE { P1D |= (1 << 4); } //カードをNonActiveにします
//---------------------------------------------------------------------------
//■■ ファイル内定数定義 ■■■■■■■■■■■■■■■■■■■■■■■■■■
//---------------------------------------------------------------------------
//#define MMC_RECV_TIMEOUT 0xFFFF //受信タイムアウト値
//#define MMC_POLLING_TIMEOUT 1000 //受信ポーリング時のタイムアウト回数
// //2004/08/30 SDカードおよび、初期化に時間が
// //かかるMMCカードに対応
// //(情報提供:nsawaさん)
//→2004/12/13 Move to mmc_api.h by N.SAWA
#define VALIDFILEACC 0x9ce6 //"file.c"から抜粋
//#define SEND_CLOCK_WAIT 10 //速すぎるクロック用のウエイト(48MHzモード時に使用)
// //こういう調整をしても、曲に寄ってはデコード処理に
// //読み込みが間に合わない、または、速過ぎる通信処理に
// //データが化ける等の原因で途中でフレームエラーになり
// //曲が途中で終る場合もあります。
// //今のところ、これ以上の調整は難しそうなので、いったん
// //このくらいの調整で止めておくことにします。
// //
// //ちなみにこのMMC版MP3プレイヤーでは32kHz 48kbpsの
// //ファイルしか処理が間に合いません。
// //かといって32kbpsのファイルは音質が悪いので、オススメ
// //できません(^^;
//→2004/12/12 Delete by N.SAWA
//2005/05/04 Added by Madoka >>>ここから
//ワークエリアがヒープから取れなくなった時に、
//グローバル変数として定義するために利用する
//定数たち
#define PIECE_SECTOR_SIZE (4096) //P/ECEでのセクタサイズ
#define MMC_MIN_CLUSTER_SIZE (512) //MMCでの最小クラスタサイズ
#define MMC_FATCHAIN_MAX (((MMC_FILESIZE_MAX / MMC_MIN_CLUSTER_SIZE) + 1) * sizeof(unsigned short)) //最大サイズファイルのFATチェインテーブルサイズ
#define MMC_WORKAREA_MAX (MMC_FATCHAIN_MAX + PIECE_SECTOR_SIZE) //MMCライブラリで利用するワークエリアの最大サイズ
//2005/05/04 Added by Madoka <<<ここまで
//---------------------------------------------------------------------------
//■■ ファイル内構造体定義 ■■■■■■■■■■■■■■■■■■■■■■■■■■
//---------------------------------------------------------------------------
//MMCの情報構造体
typedef struct tag_MMC_INFO
{
unsigned char bInit; //初期化済みフラグ
MMC_CID_INFO tCIDInfo; //CID情報
MMC_CSD_INFO tCSDInfo; //CSD情報
} MMC_INFO;
//MBRのパーティションエントリ構造体
typedef struct tag_PARTITIONENTRY_AT
{
unsigned char ucStatus; //領域状態(0x00:スリープ、0x80:アクティブ)
unsigned char ucStartHead; //領域の開始ヘッド
unsigned short usStartCylinderSecter; //領域の開始シリンダ・セクタ
unsigned char ucType; //領域の種類
unsigned char ucEndHead; //領域の終了ヘッド
unsigned short usEndCylinderSecter; //領域の終了シリンダ・セクタ
unsigned long ulOffsetSectors; //MBRの先頭から領域の先頭までのセクタ数
unsigned long ulSizeSector; //領域のセクタ数
} PARTITIONENTRY_AT;
//ディレクトリエントリ構造体
typedef struct tag_DIR_ENTRY
{
char sFileName[8]; //ファイル名(削除ファイルは1文字目が0xE5、未使用エントリは1文字目が0x00)
char sExtension[3]; //拡張子(3文字に満たない場合の残りの部分は0x20、ファイル名も同様)
unsigned char ucAttribute; //属性(R:0x01、H:0x02、S:0x04、A:0x20、Dir:0x10、Vol:0x08)
unsigned char ucaReserved[10]; //予約(VFATで利用、利用しない場合は0フィル)
unsigned short usTime; //作成時間
unsigned short usDate; //作成日
unsigned short usCluster; //ファイルまたはディレクトリの先頭クラスタ
unsigned long ulFileSize; //ファイルサイズ(Dir、Volは常に0、それ以外のファイルで0のとき、クラスタも0)
} DIR_ENTRY;
//ファイルシステム情報構造体
typedef struct tag_FILESYSTEM_INFO
{
unsigned char ucSectorsParCluster; //1クラスタ当たりのセクタ数
unsigned char ucSectorsParClusterShift; //1クラスタ当たりのセクタ数を計算で使用する時のシフト数
unsigned char ucClustorSizeShift; //1クラスタ当たりのバイト数を計算に使用する時のシフト数
unsigned short usFATOffsetSecters; //論理セクタ0(いわゆるブートセクタ)からFAT領域までのセクタ数(実はブートレコードのサイズですが)
unsigned short usRootDirEntryMax; //ルートディレクトリエントリの最大数(FAT12/16用)
unsigned short usFATSize; //FATのセクタ数(FAT12/16用)
unsigned long ulVolumeSerialID; //ボリュームシリアルID(フォーマット時にランダムに割り当てられる)
unsigned long ulFATAddress; //FATの物理セクタ番号
unsigned long ulRootDirAddress; //ルートディレクトリの物理セクタ番号
unsigned long ulFirstClusterAddress; //先頭クラスタ(クラスタ番号2)の物理セクタ番号
unsigned short *pusaFATchain; //FATチェインテーブル(最大5MB分まで) 注:この仕様により5MBを超えるファイルは扱えません
DIR_ENTRY *ptaDirTable; //ディレクトリエントリテーブル(1セクタ分)
unsigned char *pucaReadSubBuff; //mmcFileReadSct用の代替バッファ(4096バイト分)
} FILESYSTEM_INFO;
//内部作業用ファイル検索情報構造体
typedef struct tag_MMC_FILEFIND_INFO
{
unsigned short usDirIndex; //検索中のディレクトリエントリインデックス
unsigned char ucDummy[14]; //サイズ合わせのダミー
} MMC_FILEFIND_INFO;
//---------------------------------------------------------------------------
//■■ ファイル内グローバル変数定義 ■■■■■■■■■■■■■■■■■■■■■■■■
//---------------------------------------------------------------------------
static MMC_INFO g_tMMCInfo;
static FILESYSTEM_INFO g_tFS_Info;
static unsigned long g_ulMaxFileSize;
static unsigned char g_ucInitResult; //2005/03/12 Add by Madoka 初期化時の戻り値保持変数
//2005/05/04 Added by Madoka
//ワークエリアをグローバル配列にとるのは、
//アプリ側でのみ許可します
#if (!defined(__PCEKN__)) && defined(__MMC_WORK_GLOBAL__)
static unsigned char g_ucMMCWorkArea[MMC_WORKAREA_MAX]; //MMCライブラリで利用するワークエリア
#endif //(!defined(__PCEKN__)) && defined(__MMC_WORK_GLOBAL__)
//---------------------------------------------------------------------------
//■■ ファイル内のみの関数プロトタイプ宣言 ■■■■■■■■■■■■■■■■■■■■
//---------------------------------------------------------------------------
//ミリ秒単位の指定の時間待つ(汎用)
void mmcWait(unsigned long ulWaitTime);
//各種I/Oの初期化
void mmcInitIO(void);
//固定ワークエリアの確保
//MMCとの通信に使用する固定長のワークエリアを
//ヒープ領域から確保します。
//確保に失敗した場合0を返します。
unsigned char mmcAllocFixedWorkArea(void);
//MMC初期化のコア処理
//初期化処理に失敗した場合0を返します。
unsigned char mmcInitCore(void);
//MMCのSPIモード初期化
//初期化に失敗した場合は0を返します。正常終了は1を返します。
unsigned char mmcInitSPIMode(void);
//1バイト送信
//inline void mmcByteSend(unsigned char ucData);
//↓2004/12/12 Change by N.SAWA
void mmcByteSend(int data);
//データの送信コア
void mmcSendDataCore(unsigned char *paData,int iDataLen);
//コマンド送信&レスポンス受信
//CMD13だけR2レスポンス(2bytes)
unsigned short mmcSendCommandAndRecvResponse(unsigned char ucCMD,
unsigned long ulArg);
//1バイト受信
//inline unsigned char mmcByteRecv(void);
//↓2004/12/13 Change by N.SAWA inlineはやめました。
unsigned char mmcByteRecv(void);
//データ受信
//スタートビット以降の指定のバイト数を受信します
//タイムアウトが発生した場合0を返します。正常終了は1を返します。
//unsigned char mmcRecvData(unsigned char *paRecvBuff,int iRecvLen);
//↓2004/12/13 Change by N.SAWA
int mmcRecvData(unsigned char *paRecvBuff,int iRecvLen);
//接続スチェック
//正常に接続されている場合は0を返す。
//エラーになった場合は1を返します。
unsigned char mmcCheckConnection(void);
//マスターブートレコードからブートセクタのオフセットを取得
//失敗した場合は0xFFFFFFFFを返す
unsigned long mmcGetBootSecterOffset(void);
//ブートセクタからファイルシステム情報を取得
//引数にはmmcGetBootSecterOffsetで取得したMBRからブートセクタ
//までのオフセットを入力します。
//正常に読み出せた場合は1を、失敗した場合は0を返します。
unsigned char mmcGetFileSystemInfo(unsigned long ulBootSecterOffset);
//ディレクトリエントリ検索のコア
DIR_ENTRY* mmcSearchCore(MMC_FILEFIND_INFO* pInfo);
//FATディレクトリエントリのファイル名からP/ECEのファイル名にコピー
void mmcCopyFatFileNameToPieceFileName(char *pPieceFile,char *pFatFile,char *pFatExt);
//ファイル検索
DIR_ENTRY* mmcSearchFile(const char *fname);
//FATチェインテーブルの作成
//指定のファイルの先頭クラスタとサイズを指定します。
//FATのチェインの途中で欠陥クラスタ等が見つかった場合は1を返します。
//正常終了の場合は0を返します。
int mmcCreateFATChainTable(const unsigned short usFirstCluster,
const unsigned long ulFileSize);
int mmcWaitStartBit(void); // 2004/12/13 Add by N.SAWA
int mmcWaitBusy(void); // 2004/12/13 Add by N.SAWA
int mmcSendData(const unsigned char *paSendBuff,int iSendLen);
//---------------------------------------------------------------------------
//■■ 関数インプリメント ■■■■■■■■■■■■■■■■■■■■■■■■■■
//---------------------------------------------------------------------------
unsigned char mmcInit(unsigned long ulMaxFileSize)
{
//MMCの初期化
//MMC系のAPIを使用する前に必ず1度だけ呼び出してください。
//API内で使用するワークエリアをヒープから確保します。
//MMCの初期化に失敗した場合またはワークエリアの確保に失敗した場合は0を返します。
//正常終了した場合は1を返します。
//使用するI/Oの初期化を行います
mmcInitIO();
//扱うファイルの最大サイズを設定
if(ulMaxFileSize > MMC_FILESIZE_MAX)
g_ulMaxFileSize = MMC_FILESIZE_MAX;
else
g_ulMaxFileSize = ulMaxFileSize;
//MMC側の初期化
//return mmcInitCore();
//↓2004/12/12 Change by N.SAWA
{
static void hook_mmc();
//2005/03/12 Changed by Madoka
//Old::
//int retval = mmcInitCore();
//if(retval == 1) {
// hook_mmc();
//}
//
//return retval;
g_ucInitResult = mmcInitCore();
//2005/05/04 Changed by Madoka
//pceFile系APIのフックは__PCEFILE_API_HOOK__が定義されている
//ときのみ実行
#ifdef __PCEFILE_API_HOOK__
if(g_ucInitResult == 1) {
hook_mmc();
}
#endif //__PCEFILE_API_HOOK__
return g_ucInitResult;
}
}
//---------------------------------------------------------------------------
//↓2005/03/12 Add by Madoka
unsigned char mmcGetInitResult(void)
{
return g_ucInitResult;
}
//---------------------------------------------------------------------------
unsigned char mmcInitCore(void)
{
//MMC初期化のコア処理
//初期化処理に失敗した場合0を返します
unsigned long ulOffsetSector; //MBRからブートセクタまでのオフセットセクタ数
//初期化済みフラグクリア
g_tMMCInfo.bInit = 0;
//MMCをSPIモードで初期化します
if(mmcInitSPIMode() == 0)
return 0; //初期化失敗
//CID情報の取得
if(mmcGetCIDInfo(&g_tMMCInfo.tCIDInfo) == 0)
return 0; //取得失敗
//CSD情報の取得
if(mmcGetCSDInfo(&g_tMMCInfo.tCSDInfo) == 0)
return 0; //取得失敗
//MBRからブートセクタまでのオフセットを取得
ulOffsetSector = mmcGetBootSecterOffset();
//ちゃんと取得できたか?
if(ulOffsetSector == 0xFFFFFFFF)
return 0;
//2004/11/06 Add by Madoka
//スーパーフロッピー形式に対応(情報提供:nsawaさん(http://piece.no-ip.org/))
//ありがとうございます。
//
//ブートセクタからファイルシステムの情報を取得
if((ulOffsetSector == 0xFFFFFFFF) ||
(mmcGetFileSystemInfo(ulOffsetSector) == 0))
{
//スーパーフロッピー形式と仮定してリトライ
//(スーパーフロッピー形式にはMBRが無いため、オフセット0に)
ulOffsetSector = 0;
if(mmcGetFileSystemInfo(ulOffsetSector) == 0)
return 0;
}
//固定長のワークエリアをヒープ領域から取得
if(mmcAllocFixedWorkArea() == 0)
return 0;
//2004/12/12 Add by N.SAWA
//代替バッファ未割り当ての状態で、割り込み中に初回読み込みを行った場合、
//割り込み内でpceHeapAlloc()を使ってしまうことになり危険ですので、
//代替バッファは無条件で最初に確保してしまうことにしました。
if(g_tFS_Info.pucaReadSubBuff == NULL) //2005/03/20 Add by Madoka 代替バッファのサイズは変わらないので二重確保防止
{
//2005/05/04 Changed by Madoka ワークエリアはグローバル配列で
#if (!defined(__PCEKN__)) && defined(__MMC_WORK_GLOBAL__)
g_tFS_Info.pucaReadSubBuff = (unsigned char*)(g_ucMMCWorkArea + MMC_FATCHAIN_MAX);
#else
g_tFS_Info.pucaReadSubBuff = (unsigned char*)pceHeapAlloc(PIECE_SECTOR_SIZE);
if(g_tFS_Info.pucaReadSubBuff == NULL)
return 0;
#endif //(!defined(__PCEKN__)) && defined(__MMC_WORK_GLOBAL__)
}
//初期化終了
g_tMMCInfo.bInit = 1; //初期化済みフラグON
//正常終了
return 1;
}
//---------------------------------------------------------------------------
void mmcExit(void)
{
//MMCの終了
//MMC系のAPIが不要になったら必ず呼び出してください。
//ここで初期化時に確保したワークエリアを解放します。
//2005/05/04 Changed by Madoka
//pceFile系APIのフックは__PCEFILE_API_HOOK__が定義されて
//いる時のみ実行
#ifdef __PCEFILE_API_HOOK__
//{{2004/12/12 Add by N.SAWA
{
static void unhook_mmc();
unhook_mmc();
}
//}}2004/12/12 Add by N.SAWA
#endif //__PCEFILE_API_HOOK__
//確保したヒープを解放
if(g_tFS_Info.ptaDirTable != NULL)
{
pceHeapFree(g_tFS_Info.ptaDirTable);
g_tFS_Info.ptaDirTable = NULL;
g_tFS_Info.pusaFATchain = NULL;
}
if(g_tFS_Info.pucaReadSubBuff != NULL)
{
pceHeapFree(g_tFS_Info.pucaReadSubBuff);
g_tFS_Info.pucaReadSubBuff = NULL;
}
}
//---------------------------------------------------------------------------
void mmcWait(unsigned long ulWaitTime)
{
//ミリ秒単位の指定の時間待つ(汎用)
unsigned long ulStartTime = pceTimerGetCount();
//指定の時間が経つまでループ
while((pceTimerGetCount() - ulStartTime) < ulWaitTime);
}
//---------------------------------------------------------------------------
void mmcInitIO(void)
{
//各種I/Oの初期化
//ポート機能拡張レジスタでP04,P05,P06,P14を
//汎用ポートとして使用できるようにする
//(CPUデータシートP.372 ポート機能拡張レジスタを参照)
PCFEX &= 0x8E;
//以下の詳細はCPUデータシートP.370を参照してください
//CS(Chip Select)に接続されているP14ポートの設定
P1CF &= 0xEF; //P14を使用可能に
P1IOC |= (1 << 4); //P14を出力ポートとして設定
/* 個別に設定する場合
//SCLK(Serial CLocK)に接続されているP06ポートの設定
P0CF &= 0xBF; //P06を使用可能に
P0IOC |= (1 << 6); //P06を出力ポートとして設定
//DI(Data In)に接続されているP05ポートの設定
P0CF &= 0xDF; //P05を使用可能に
P0IOC |= (1 << 5); //P05を出力ポートとして設定
//DO(Data Out)に接続されているP04ポートの設定
P0CF &= 0xEF; //P04を使用可能に
P0IOC &= ~(1 << 4); //P04を入力ポートとして設定
*/
//P04,P05,P06を一度に設定
P0CF &= 0x8F; //P04,P05,P06を使用可能に
P0IOC |= 0x60; //P05,p06は出力ポートとして設定
P0IOC &= ~(1 << 4); //P04は入力ポートとして設定
}
//---------------------------------------------------------------------------
unsigned char mmcAllocFixedWorkArea(void)
{
//固定ワークエリアの確保
//固定ワークエリアの確保
//MMCとの通信に使用する固定長のワークエリアを
//ヒープ領域から確保します。
//確保に失敗した場合0を返します。
unsigned char ucRet = 1;
unsigned short usClusterNum;
unsigned long ulHeapSize = sizeof(DIR_ENTRY) * 16; //必要なヒープサイズ
//MMCを制御するのに必要なワークエリアを一気に確保
//その後、必要な部分にポインタを分ける
//2005/05/07 Added by Madoka
//扱う最大ファイルサイズがカードの容量を超えている場合は
//最大ファイルサイズをカード容量のサイズに切り詰める
if(g_ulMaxFileSize > g_tMMCInfo.tCSDInfo.ulCardSize)
g_ulMaxFileSize = g_tMMCInfo.tCSDInfo.ulCardSize;
//扱う最大ファイルサイズから必要なクラスタ数を算出
//必要なテーブルのサイズを算出(クラスタ数)
usClusterNum = g_ulMaxFileSize / (1 << g_tFS_Info.ucClustorSizeShift) + 1;
//確保するヒープサイズを決定
ulHeapSize += (sizeof(unsigned short) * usClusterNum);
//すでに取得されていないか?
if(g_tFS_Info.ptaDirTable != NULL)
{
//とりあえず解放しておく
pceHeapFree(g_tFS_Info.ptaDirTable);
g_tFS_Info.ptaDirTable = NULL;
g_tFS_Info.pusaFATchain = NULL;
}
#if (!defined(__PCEKN__)) && defined(__MMC_WORK_GLOBAL__)
//ワークエリアを取得
g_tFS_Info.ptaDirTable = (DIR_ENTRY*)g_ucMMCWorkArea;
#else
//ヒープを確保
g_tFS_Info.ptaDirTable = (DIR_ENTRY*)pceHeapAlloc(ulHeapSize);
#endif //(!defined(__PCEKN__)) && defined(__MMC_WORK_GLOBAL__)
//取得できたか?
if(g_tFS_Info.ptaDirTable == NULL)
ucRet = 0;
//ポインタを分ける
//FATチェインテーブルのワークエリア
g_tFS_Info.pusaFATchain = (unsigned short*)((unsigned char*)g_tFS_Info.ptaDirTable
+ sizeof(DIR_ENTRY) * 16);
return ucRet;
}
//---------------------------------------------------------------------------
//void mmcByteSend(unsigned char ucData)
//↓2004/12/12 Change by N.SAWA
//void mmcByteSend(int data) →2004/12/12 Move to mmc_fram.c by N.SAWA
//---------------------------------------------------------------------------
//void mmcSendDataCore(unsigned char *paData,int iDataLen) →2005/02/09 Move to mmc_fram.c by Madoka
//---------------------------------------------------------------------------
//unsigned short mmcSendCommandAndRecvResponse(unsigned char ucCMD,unsigned long ulArg)
// →2005/02/09 Move to mmc_fram.c by Madoka
//---------------------------------------------------------------------------
//unsigned char mmcByteRecv(void) →2004/12/13 Move to mmc_fram.c by N.SAWA
//---------------------------------------------------------------------------
//unsigned char mmcRecvData(unsigned char *paRecvBuff,int iRecvLen) →2004/12/12 Move to mmc_fram.c by N.SAWA
//---------------------------------------------------------------------------
unsigned char mmcInitSPIMode(void)
{
//MMCのSPIモード初期化
//初期化に失敗した場合は0を返します。正常終了は1を返します。
unsigned char CMD0[6] = { 0x40,0x00,0x00,0x00,0x00,0x95 }; //CMD0のデータフォーマット
unsigned char CMD1[6] = { 0x41,0x00,0x00,0x00,0x00,0xFF }; //CMD1のデータフォーマット
unsigned char ucRecvBuffR1 = 0xFF; //R1レスポンス(8bit)の受信バッファ
int i;
//MMCのデータシート(P.99)記載のSPIモード初期化の
//手順にそって初期化を行います
//MMCのデータシートは以下の場所にあります
//http://www.renesas.com/avs/resource/japan/jpn/pdf/flashcard/j603002_mmc.pdf
//↑の他にも以下の場所にカード自体のデータシートが公開されています。
//参考にして下さい。
//http://www.renesas.com/avs/resource/japan/jpn/pdf/flashcard/j203658_hb28e016mm2.pdf
//
//ちなみに今回採用したSanDiskのMMCデータシートはこちら(英語)
//http://media-server.amazon.com/media/mole/MANUAL000007788.pdf
//デバッグ用
//#define INIT_MMC "MMC_INIT"
//SendUsbCom(INIT_MMC,strlen(INIT_MMC));
//mmcWait(USBCOM_WAIT);
//(1)CS = Highとして、カードをNonActiveにします。
// CSにはP14ポートを接続しているので、P14をHighにします。
CARD_DISABLE
//(2)MMCイニシャライズ用のダミークロックを74クロック以上発行します。
for(i = 0;i < 10;++i)
mmcByteSend(0xFF); //8クロック分のダミー送信
//(3)CS = LowとしてカードをActiveにし、CMD0(GO_IDLE_STATE)を送信します。
//CS = LowとしてカードをActiveにします。
//CSにはP14ポートを接続しているので、P14をLowにします。
CARD_ENABLE
//CMD0送信
mmcSendDataCore(CMD0,sizeof(CMD0));
//(4)この時点でSPIモードに切り替わります。そしてR1レスポンス(8bit)を待ちます。
// ここで受信タイムアウトや0x01以外を受信した場合はエラーとします。
if((mmcRecvData(&ucRecvBuffR1,1) == 0) ||
(ucRecvBuffR1 != 0x01))
{
#if 0
#define MMC_CMD0_ERR "MMC_CMD0_ERR"
SendUsbCom(MMC_CMD0_ERR,strlen(MMC_CMD0_ERR));
#endif
//エラーなので戻る
CARD_DISABLE
return 0;
}
//デバッグ用
//#define MMC_CMD0_OK "MMC_CMD0_OK"
//SendUsbCom(MMC_CMD0_OK,strlen(MMC_CMD0_OK));
//mmcWait(USBCOM_WAIT);
//(5)CMD1(SEND_OP_CMD)を送信し、MMCからのR1レスポンス(8bit)を待ちます。
// R1レスポンスが0x01の場合CMD1を再送信し、R1レスポンスが0x00になる
// までポーリングします。
// また、R1レスポンスが0x00 or 0x01以外の場合や受信タイムアウトになっ
// た場合はエラーとします。
//CMD1送信
mmcSendDataCore(CMD1,sizeof(CMD1));
//受信ポーリング
for(i = 0;i < MMC_POLLING_TIMEOUT;++i)
{
//受信タイムアウトになったか?
if(mmcRecvData(&ucRecvBuffR1,1) == 0)
{
//抜ける
i = MMC_POLLING_TIMEOUT;
break;
}
//受信値をチェック
if(ucRecvBuffR1 == 0x00)
{
//初期化完了で抜ける
break;
}
else if(ucRecvBuffR1 == 0x01)
{
//ビジー
//デバッグ用
//#define MMC_CMD1_BUSY "MMC_CMD1_BUSY"
//SendUsbCom(MMC_CMD1_BUSY,strlen(MMC_CMD1_BUSY));
//mmcWait(USBCOM_WAIT);
//CMD1再送
mmcSendDataCore(CMD1,sizeof(CMD1));
}
else
{
//エラーで抜ける
i = MMC_POLLING_TIMEOUT;
break;
}
}
//エラーか?
if(i == MMC_POLLING_TIMEOUT)
{
#if 0
#define MMC_CMD1_ERR "MMC_CMD1_ERR"
SendUsbCom(MMC_CMD1_ERR,strlen(MMC_CMD1_ERR));
#endif
//エラーなので戻る
CARD_DISABLE
return 0;
}
//デバッグ用
//#define MMC_CMD1_OK "MMC_CMD1_OK"
//SendUsbCom(MMC_CMD1_OK,strlen(MMC_CMD1_OK));
//mmcWait(USBCOM_WAIT);
//用が済んだので、CS = Highとして、カードをNonActiveにします。
//CSにはP14ポートを接続しているので、P14をHighにします。
CARD_DISABLE
return 1;
}
//---------------------------------------------------------------------------
unsigned char mmcGetCIDInfo(MMC_CID_INFO *pCIDInfo)
{
//CIDレジスタの内容を取得
//取得に失敗した場合は0を、成功した場合は1を返します。
//引数にはCIDレジスタ情報の格納先アドレスを指定してください。
unsigned char ucaRecvCID[MMC_CID_INFO_SIZE]; //CID情報受信用バッファ
unsigned char ucRet = 0;
//カードをActiveに
CARD_ENABLE
//CMD10送信してR1レスポンスを受信
if(mmcSendCommandAndRecvResponse(10,0) == 0x00)
{
//レスポンス後に送信されるCIDデータを受信
if(mmcRecvData(ucaRecvCID,MMC_CID_INFO_SIZE) == 1)
{
//受信したデータを分解して構造体に保存
//MID(ManufactureID)の取得
pCIDInfo->ucMID = ucaRecvCID[0];
//OID(OEM/Application ID)の取得
pCIDInfo->usOID = (unsigned short)((ucaRecvCID[1] << 8) | ucaRecvCID[2]);
//PNM(Product name)の取得
pCIDInfo->ucPNM[0] = ucaRecvCID[3];
pCIDInfo->ucPNM[1] = ucaRecvCID[4];
pCIDInfo->ucPNM[2] = ucaRecvCID[5];
pCIDInfo->ucPNM[3] = ucaRecvCID[6];
pCIDInfo->ucPNM[4] = ucaRecvCID[7];
pCIDInfo->ucPNM[5] = ucaRecvCID[8];
//PRV(Product revision)の取得
pCIDInfo->ucPRV = ucaRecvCID[9];
//PSN(Product serial number)の取得
pCIDInfo->ulPSN = (unsigned long)((ucaRecvCID[10] << 24) |
(ucaRecvCID[11] << 16) |
(ucaRecvCID[12] << 8) |
ucaRecvCID[13]);
//MDT(Manufacturing date)の取得
pCIDInfo->ucMDT = ucaRecvCID[14];
//CRC(7-bit CRC checksum)の取得
pCIDInfo->ucCRC = ucaRecvCID[15] >> 1; //LSB1bitは関係ないので削除
//デバッグ用
// SendUsbCom((unsigned char*)pCIDInfo,sizeof(MMC_CID_INFO));
// mmcWait(USBCOM_WAIT);
//受信に成功
ucRet = 1;
//CIDデータの後に付いて来る
//16bit分のCRCをダミークロックを
//送って無視する
//16クロック分のダミー送信
mmcByteSend(0xFF);
mmcByteSend(0xFF);
}
}
//カードをNonActiveに
CARD_DISABLE
return ucRet;
}
//---------------------------------------------------------------------------
unsigned char mmcGetCSDInfo(MMC_CSD_INFO *pCSDInfo)
{
//CSDレジスタの内容を取得
//取得に失敗した場合は0を、成功した場合は1を返します。
//引数にはCSDレジスタ情報の格納先アドレスを指定してください。
unsigned char ucaRecvCSD[MMC_CSD_INFO_SIZE]; //CSD情報受信用バッファ
unsigned char ucRet = 0;
//カードをActiveに
CARD_ENABLE
//CMD9送信してR1レスポンスを受信
if(mmcSendCommandAndRecvResponse(9,0) == 0x00)
{
//レスポンス後に送信されるCSDデータを受信
if(mmcRecvData(ucaRecvCSD,MMC_CSD_INFO_SIZE) == 1)
{
//受信したデータを分解して構造体に保存
//
//本当は16バイト(128bit)分全部構造体で保存しておくのが
//良いのだろうと思うけど、このCSDに関しては各種データが
//ビット単位で区切られてて、構造体にビットフィールドとか
//使って保存しようとしても、その内容を確認するためにUSB
//でVCのアプリと通信した時にP/ECEのGCCとVCでビットフィー
//ルドの仕様が違うのか、上手く値が渡せなかったりして大変
//だったので、今回は必要最小限の内容のみを保存することに
//します。
unsigned short C_SIZE;
unsigned char C_SIZE_MULT;
unsigned long MULT;
unsigned long BLOCKNR;
//読み込みブロック長を取得
//SanDiskの64MBでは512でした
pCSDInfo->usReadBlockLength = (unsigned short)(1 << (ucaRecvCSD[5] & 0x0F));
//書き込みブロック長を取得
//SanDiskの64MBでは512でした
pCSDInfo->usWriteBlockLength = (unsigned short)(1 << (((ucaRecvCSD[12] & 0x03) << 2) |
((ucaRecvCSD[13] & 0xC0) >> 6)));
//注 MMCは読み書きに対するブロック長がデフォ
// ルトで512バイトというのが標準のようなの
// で、今回製作したデータの読み書きAPIでは
// ブロック長512バイトとして処理を行ってい
// ます。
// もし、お使いのMMCのブロック長が512バイ
// ト以外の場合は、CMD16でブロック長を512
// バイトに設定するか、APIの中身を適切な
// ものに書き換えてください。
//カード容量を計算
//
//カード容量はC_SIZE,C_SIZE_MULTおよびREAD_BLK_LEN
//から以下の様に計算されます。
//
//memory_capacity = BLOCKNR * BLOCK_LEN
//
//BLOCKNR = (C_SIZE+1) * MULT
//MULT = 2^(C_SIZE_MULT+2)
//BLOCK_LEN = 2^READ_BLK_LEN
//
//(このうちBLOCK_LENはすでにusReadBlockLengthとして
// 計算済みなので、その値を利用します)
//
//CSIZEを取得
//SanDiskの64MBでは3919でした
C_SIZE = (unsigned short)(((ucaRecvCSD[6] & 0x03) << 10) |
(ucaRecvCSD[7] << 2) |
((ucaRecvCSD[8] & 0xC0) >> 6));
//C_SIZE_MULTを取得
//SanDiskの64MBでは3でした
C_SIZE_MULT = (unsigned char)(((ucaRecvCSD[ 9] & 0x03) << 1) |
((ucaRecvCSD[10] & 0x80) >> 7));
//MULTを計算
MULT = 1 << (C_SIZE_MULT+2);
//BLOCKNRの計算と保存
//SanDiskの64MBでは125440になりました
BLOCKNR = (C_SIZE+1) * MULT;
pCSDInfo->ulTatalBlocks = BLOCKNR;
//カード容量を計算
//SanDiskの64MBでは64225280になりました
pCSDInfo->ulCardSize = (unsigned long)(BLOCKNR * pCSDInfo->usReadBlockLength);
//デバッグ用
// SendUsbCom((unsigned char*)pCSDInfo,sizeof(MMC_CSD_INFO));
// mmcWait(USBCOM_WAIT);
//受信に成功
ucRet = 1;
//CSDデータの後に付いて来る
//16bit分のCRCをダミークロックを
//送って無視する
//16クロック分のダミー送信
mmcByteSend(0xFF);
mmcByteSend(0xFF);
}
}
//カードをNonActiveに
CARD_DISABLE
return ucRet;
}
//---------------------------------------------------------------------------
unsigned char mmcCheckConnection(void)
{
//接続チェック
//正常に接続されている場合は0を返す。
//エラーになった場合は1を返します。
unsigned char ucRet = 0;
unsigned short usRes;
//ステータス問い合わせ
//カードをActiveに
CARD_ENABLE
//CMD13送信してR2レスポンスを受信
usRes = mmcSendCommandAndRecvResponse(13,0);
//カードをNonActiveに
CARD_DISABLE
//レスポンスチェック
if(usRes != 0)
{
//初期化処理を試してみる
if(mmcInitSPIMode() == 0)
ucRet = 1; //エラー
}
return ucRet;
}
//---------------------------------------------------------------------------
unsigned char mmcReadSector(unsigned long ulSector,unsigned char *pucBuff)
{
//セクタリード
//MMCから1セクタ分(512バイトを想定)データを読み出します
//
//unsigned long ulSector 読み出し対象セクタ(物理セクタ番号)
//unsigned char *pBuff バッファ(必ず512バイト以上あること)
//
//正常に読み出せた場合は1を、エラーが発生した場合は0を返します
unsigned long ulAddress = ulSector * g_tMMCInfo.tCSDInfo.usReadBlockLength; //アドレス
unsigned char ucRet = 0;
//カードをActiveに
CARD_ENABLE
//CMD17送信してR1レスポンスを受信