STM32F7を使ってみる10 -いにしえのマルチメディアカードを動かす(うごかす編)-
ぇえええぇぇえええぇええ(どん引き)
↑イレギュラー化した部下に突如愛の告白されるシグマタイチョウ風に
いったいいつからIF誌はねむいさんのお株を奪うようなシモネタを炸裂させる
ようになったのでしょうか…???今回はちょっと笑えたので許しますが。
ああプロテインってそういう・・・
そんなどうでもいいことは置いといてさっさと本題に掛かります!!!!!前回は
microSD->SDの変換アダプタ作っただけで力尽きましたが今回は実際に動かします。
先ずはebayで購入した2GBのMMCPlusカードです!
MMCPlusの規格なので8bitバスで転送もできます…がソケットの互換性を考えると、
4bitバスモードで動かした方が無難でしょう。
因みに妙に汚いように見えますがUSEDでした。MMC自体最早新規生産なんかしてない
ので致し方なしです。カードとして正しく動作すればOKです。
で、その前に問題のソフトウエアの方ですが…こちらでも紛糾してるように
STM32CubeHALライブラリにMMCのサポートは全く有りません。それどころかなんと
過去のSPLには対応していたSDv1.xx系カードのサポートすらもHALライブラリでは
おもいくそぶっちされておりました!!!F**K!!
とりあえずSDv1.xx系のサポートは復活させて動作確認したのですがMMCネイティブ
モードにおけるイニシャライズはどうしたらいいのか全く分からなかったので
暫くの間ネットの海にダイブして情報を沢山漁ってきました。
幸いにもJEDECのMMCの規格は2016年現在は一般人でも公式のJEDECのサイトから
容易に入手することが出来るようにになっていてさらに中華圏のサイトでは
動作するかどうかは不明ですがSTM32向けのeMMCドライバも入手出来たので
それを参考にMMC向けのドライバをF7のHALライブラリ向けに組み込みました。
当然最初は思った通りに動かなかったのですがSTM32のSDIO/SDMMCのハード
ウエア自身にかなりクセがあることが分かり、クセを理解して全種類のカードを
イニシャライズせしめるよう克服していきました。
以下にMMCPlus/MMCv3なカードを使い認識していく過程をデバッガで実動作を
追いながら解説していきます。
STM32のSDカードドライバは基本的にSDv2->SDv1->MMCの順に認識しようとして
いきます。これは現在のSDカードの規格においても推奨される初期化手順と
されています。カードをリセットするCMD0を除くと最初に放たれるのはCMD8です。
MMCとSDv1系ではSDHC用初期化CMD8:SEND_IF_CONDはタイムアウトエラーとなります。
過去のSTM32のSPLに収録されているsdカードのサンプルではその状態から
なぜかCMD55を単品で投げてから改めてCMD55+ACMD41を投げていました。
CMD8が撥ねられた後いきなりCMD55+ACMD41を撃つとSDIOモジュールがエラーで
コケる対策にCMD55を空撃ちしていた感じです(SPLではあったけどHALライブラリ
はそれすらない!)。これはCMD55を受け付けるSDカード系は問題ないのですが
MMCv3以前だとCMD8が撥ねられた後のCMD55の空撃ちがILLEGAL_COMMANDとなり
またまた撥ねられてしまい、先に進めません(※MMCv4以降はこのCMD55が通ります)。
と言うわけでCMD55の代わりにCMD0でカードをリセット状態にしてから改めて
CMD55+ACMD41を送るようにするとうまく先に進めました!勿論SDv1系でも
CMD55の空撃ちではなくCMD0で問題有りませんでした。
MMCではCMD55+ACMD41は当たり前ですがタイムアウトエラーとなります。
先ほどと同じくCMD0を送りMMCをリセットしますが、eMMC対応を考えて引数を
0xF0F0F0F0にしたCMD0の後0x0000000な引数のCMD0を送るようにしてみました。
ここまで来てようやく本来のMMCの初期化ができます。
CMD1を送ってSDカードの「ACMD41」と同じように初期化します。
が、ブロックアドレッシング必須のSDHCと同じくCCSビット(0x40000000)を
ORして引数に渡さないとブロックアドレッシングを必要とするMMCv4.x以降の
規格では初期化が完了できませんのでしっかりとおっ立てた状態で引数として
わたしましょう。ちなみにv3以前のカードにおいてはCCSビットが立っていても
影響は受けずスルーされて初期化がそのまま通るので問題ないです。
上手く初期化が出来たらOCRレジスタの0x80FF8080が読みだされます。
MMCPlusでDualVoltage対応なので上記の値となっています。
因みにv3以前のカードでは0x80FF8000,ブロックアドレッシングな
v4系のデバイスでは0xC0FF8080が帰ってきます。
ここまで認識が通ったらだいぶ気が楽になります。
所でMMCv4.x系のカードでは新たに追加されたExtCSDレジスタから512バイト分の
追加情報を取得可能です。実はこのExtCSDは4GB以上のeMMCの総容量計算では
必須のビットが存在しています。
212〜215バイト目がそのSEC_COUNTフィールドなのですがここに総セクタ数が
記録されていて512を掛けると総バイト数が分かる仕組みになっています。
この2GBのMMCplusではSEC_COUNTフィールドからの算出方法でもCSDレジスタ
から算出する従来の容量計算方法(計算式はSDv1系と全く同じ)でも両方とも
可能です。
初期化を越えたらクロックを転送用の高速クロックに上げていきますが…
MMCv4系では最大52MHz,8bitバスモードまで動かせられます。当ぶろぐでは
4bitバスモードまでとします。MMC専用の呪文を投げる以外はSDカードの
4bit化やHighSpeedMode化と流れは同じです。そして…
無事ファイラーからディレクトリが読みだされました♥
サイズのでかい動画でもカクカクせずスムーズに動きます☆
(後でかなり早いカードなことが分かった)
お次はさらに古いMMCv3世代のカードです。容量はたったの128MB!
そしてもちろん中古品。
初期化を越えたらクロックを転送用の高速クロックに上げていきますが…
10年以上前のものですがちゃんと現在のPCカードリーダーからも認識できます。
MMCv3系のカードなので数が7ピンしかありません。MMCネイティブモードでも
当然バス数が1bitです。早速こちらも動きを追ってみましょう!
CMD1の初期化を終えるとOCRレジスタの0x80FF8000が読みだされました。
初期化を越えたらクロックを転送用の高速クロックに上げていきますが…
MMCv3系はクロック上限値が20MHzできっちり線引きされていてそれ以上はまず
動作しないので20MHz以下にクロックを落とす工夫が必要です。もちろんデータ
バス幅は1ビットのままです。
さすがに遅いですけど無事認識です♥
上記2つのカードの各レジスタをSDカードと同じようにパースしてみました。
CIDレジスタの扱いがSDカードと微妙に違うので注意です。
そんでもってMMCv4以上の細かいバージョン識別はExtCSDの"ExtCSDVER"
フィールドを読みだして解釈する必要があります。
eMMCの使用をにらんでこちらも正しく解釈できるようにしておきました。
●2GB MMCPlus
>ds 0
rc=0
Drive size: 3939328 sectors
Erase block size: 256 sectors
Default r/w block size: 1024 bytes
Card type: MMC(Byte)
CSD:
00000000 90 2F 00 2A 1F 5A 83 C1 B6 DB 9F FF 96 80 00 3F ./.*.Z.........?
CID:
00000000 37 FF FF 4D 4D 43 30 32 47 10 F3 02 67 50 2C F5 7..MMC02G...gP,.
Parsing MMC CID Register
Manufacturer ID :0x37
OEM/Application ID :
Product Name :MMC02G
Product Rev :1.0
Serial Number :0xF3026750
DateCode.Month :2
DateCode.Year :2009
Detected as MMCv4.0 Device!
OCR:
00000000 80 FF 80 80 ....
●128MB MMCv3
>ds 0
rc=0
Drive size: 250880 sectors
Erase block size: 32 sectors
Default r/w block size: 512 bytes
Card type: MMC(Byte)
CSD:
00000000 8C 26 01 2A 0F 59 81 E9 F6 DA 81 E3 9E 40 00 7D .&.*.Y.......@.}
CID:
00000000 11 00 00 30 31 32 38 4D 32 0A 05 80 FE CB 28 7D ...0128M2.....(}
Parsing MMC CID Register
Manufacturer ID :0x11
OEM/Application ID :<0><0>
Product Name :0128M2
Product Rev :0.10
Serial Number :0x0580FECB
DateCode.Month :2
DateCode.Year :2005
Detected as MMCv3.xx Device!
OCR:
00000000 80 FF 80 00 ....
>
いろいろありましたがMMCの動かし方も上手くモノにすることができるように
なりました!次はいよいよMMCから進化したeMMCの動作に挑みます!!
今回の更新はすでにおきぱに上げてあります。eMMCのSD変換アダプタを持ってるひとは
いいことあるかも・・・!?
●おまけ
前回言及したCubeF7のバグですが、「とりあえずuint64_tでキャストしときゃ
いいだろ」が祟って出てしまったカルマなのですが実際どうなるかをSTM32上で
確かめて見ました。
先ず使用する変数/定数は以下とします。
#define SECTOR_SIZE 512
uint64_t unk0;
uint32_t tnk = 8388612; /*512を掛けるとオーバーフロー*/
まずキャスト無しの場合…
unk0 = tnk * SECTOR_SIZE;
この場合は、普通にuint32_tの演算として扱われオーバーフローしたぶんは
そのまま頭が切られます。よって0x100000800ではなく0x800がunk0に代入
されました。
次に括弧でくくってuint64_tでキャストしてみます。今回フォーラムで指摘
されてたのがこのバグです。
unk0 = (uint64_t)(tnk * SECTOR_SIZE);
これもunk0に0x800が代入されてしまいました。*の演算を括弧でくくってしま
ったためにやっぱり0x800になっちゃいました。
正しいキャストの仕方がこちらです。
unk0 = (uint64_t)tnk * SECTOR_SIZE;
uint32_t変数のtnkをuint64_tにキャストしたうえでSECTOR_SIZEを掛けることで
0x100000800がunk0に正しく代入されます。
これ結構引っ掛かりやすいポイントなので私も気を付けるようにします。
フォーラムで指摘されるまで私も気づいて無くて同じミスしてましたがorz
因みにMMCv4.x系のSEC_COUNTの計算で
(代入先が64bit変数の場合)
(uint64_t)((uint64_t)(ext_csd.EXT_CSD.SEC_COUNT[3] << 24 | ¥
ext_csd.EXT_CSD.SEC_COUNT[2] << 16 | ¥
ext_csd.EXT_CSD.SEC_COUNT[1] << 8 | ¥
ext_csd.EXT_CSD.SEC_COUNT[0]));
もしくは
(uint64_t)((ext_csd.EXT_CSD.SEC_COUNT[3] << 24 | ¥
ext_csd.EXT_CSD.SEC_COUNT[2] << 16 | ¥
ext_csd.EXT_CSD.SEC_COUNT[1] << 8 | ¥
ext_csd.EXT_CSD.SEC_COUNT[0]));
もしくは
((ext_csd.EXT_CSD.SEC_COUNT[3] << 24 | ¥
ext_csd.EXT_CSD.SEC_COUNT[2] << 16 | ¥
ext_csd.EXT_CSD.SEC_COUNT[1] << 8 | ¥
ext_csd.EXT_CSD.SEC_COUNT[0]));
と誤った式にしてしまうとext_csd.EXT_CSD.SEC_COUNT[3]の最上位ビットに1が立つ
ような値がSDカード/eMMCから得られた場合、uint64だろうがint64だろうが負の値と
みなされた状態で整数拡張されて上位32bitが0xFFFFFFFFでパディングされた状態で
64bit変数にキャストされてしまい、結果として意図しない値がストアされてしまいます。
ですので、
(uint64_t)((uint32_t)(ext_csd.EXT_CSD.SEC_COUNT[3] << 24 | ?
ext_csd.EXT_CSD.SEC_COUNT[2] << 16 | ¥
ext_csd.EXT_CSD.SEC_COUNT[1] << 8 | ¥
ext_csd.EXT_CSD.SEC_COUNT[0]));
もしくは
(uint32_t)((ext_csd.EXT_CSD.SEC_COUNT[3] << 24 | ?
ext_csd.EXT_CSD.SEC_COUNT[2] << 16 | ¥
ext_csd.EXT_CSD.SEC_COUNT[1] << 8 | ¥
ext_csd.EXT_CSD.SEC_COUNT[0]));
として頭をきっちり削っておけば問題ありません。
ってわけで型の合わない変数に何も考えずキャストとか代入したらこうなります
なったorz
-
免責・連絡先は↑のリンクを
↓SNSもやってます↓
powered by まめわざ- ARM/STM32 (116)
- OpenOCD (27)
- ARM/NxP (34)
- ARM/Cypress (5)
- ARM/Others (3)
- ARM/Raspi (1)
- AVR (13)
- FPGA (4)
- GPS/GNSS (19)
- MISC (81)
- STM8 (2)
- Wirelessなアレ (16)
- おきぱ (1)
- ブラウザベンチマーク (28)
- 日本の自然歩道 (25)
- STM32U0はぢめました
⇒ ねむい (08/07) - STM32U0はぢめました
⇒ ひかわ (07/28) - STM32H5を使ってみる3 -待ち受ける初見殺しの罠たち-
⇒ ねむい (05/17) - STM32H5を使ってみる3 -待ち受ける初見殺しの罠たち-
⇒ どじょりん (05/16) - STM32H5を使ってみる3 -待ち受ける初見殺しの罠たち-
⇒ どじょりん (05/16) - いろいろ試す61(と今年の反省会)
⇒ ねむい (01/02) - いろいろ試す61(と今年の反省会)
⇒ ひかわ (01/02) - いろいろ試す61(と今年の反省会)
⇒ ひかわ (01/01) - STM32H5を使ってみる3 -待ち受ける初見殺しの罠たち-
⇒ ねむい (12/31) - STM32H5を使ってみる3 -待ち受ける初見殺しの罠たち-
⇒ ひかわ (12/31)
- October 2024 (1)
- September 2024 (1)
- August 2024 (1)
- July 2024 (1)
- June 2024 (1)
- May 2024 (1)
- April 2024 (1)
- March 2024 (1)
- February 2024 (2)
- January 2024 (1)
- December 2023 (4)
- November 2023 (2)
- October 2023 (2)
- September 2023 (1)
- August 2023 (2)
- July 2023 (1)
- June 2023 (2)
- May 2023 (3)
- April 2023 (1)
- March 2023 (1)
- February 2023 (1)
- January 2023 (1)
- December 2022 (2)
- November 2022 (1)
- October 2022 (1)
- September 2022 (1)
- August 2022 (1)
- July 2022 (1)
- June 2022 (1)
- May 2022 (1)
- April 2022 (1)
- March 2022 (1)
- February 2022 (1)
- January 2022 (1)
- December 2021 (2)
- November 2021 (2)
- October 2021 (1)
- September 2021 (1)
- August 2021 (1)
- July 2021 (1)
- June 2021 (1)
- May 2021 (1)
- April 2021 (1)
- March 2021 (1)
- February 2021 (1)
- January 2021 (1)
- December 2020 (3)
- November 2020 (1)
- October 2020 (1)
- September 2020 (1)
- August 2020 (1)
- July 2020 (1)
- June 2020 (2)
- May 2020 (1)
- April 2020 (1)
- March 2020 (1)
- February 2020 (1)
- January 2020 (1)
- December 2019 (3)
- November 2019 (1)
- October 2019 (1)
- September 2019 (2)
- August 2019 (1)
- July 2019 (1)
- June 2019 (1)
- May 2019 (1)
- April 2019 (1)
- March 2019 (1)
- February 2019 (1)
- January 2019 (1)
- December 2018 (3)
- November 2018 (2)
- October 2018 (1)
- September 2018 (1)
- August 2018 (1)
- July 2018 (1)
- June 2018 (1)
- May 2018 (1)
- April 2018 (2)
- March 2018 (1)
- February 2018 (1)
- January 2018 (1)
- December 2017 (2)
- November 2017 (2)
- October 2017 (1)
- September 2017 (1)
- August 2017 (1)
- July 2017 (1)
- June 2017 (1)
- May 2017 (1)
- April 2017 (1)
- March 2017 (2)
- February 2017 (2)
- January 2017 (2)
- December 2016 (7)
- November 2016 (2)
- October 2016 (2)
- September 2016 (1)
- August 2016 (1)
- July 2016 (1)
- June 2016 (1)
- May 2016 (2)
- April 2016 (1)
- March 2016 (2)
- February 2016 (1)
- January 2016 (1)
- December 2015 (3)
- November 2015 (1)
- October 2015 (3)
- September 2015 (2)
- August 2015 (2)
- July 2015 (3)
- June 2015 (3)
- May 2015 (4)
- April 2015 (2)
- March 2015 (4)
- February 2015 (1)
- January 2015 (3)
- December 2014 (3)
- November 2014 (2)
- October 2014 (1)
- September 2014 (2)
- August 2014 (2)
- July 2014 (3)
- June 2014 (2)
- May 2014 (1)
- April 2014 (1)
- March 2014 (4)
- February 2014 (4)
- January 2014 (3)
- December 2013 (5)
- November 2013 (4)
- October 2013 (3)
- September 2013 (2)
- August 2013 (2)
- July 2013 (2)
- June 2013 (3)
- May 2013 (2)
- April 2013 (2)
- March 2013 (2)
- February 2013 (2)
- January 2013 (3)
- December 2012 (4)
- November 2012 (2)
- October 2012 (2)
- September 2012 (4)
- August 2012 (1)
- July 2012 (3)
- June 2012 (2)
- May 2012 (3)
- April 2012 (3)
- March 2012 (2)
- February 2012 (3)
- January 2012 (3)
- December 2011 (5)
- November 2011 (3)
- October 2011 (2)
- September 2011 (2)
- August 2011 (2)
- July 2011 (2)
- June 2011 (2)
- May 2011 (2)
- April 2011 (2)
- March 2011 (2)
- February 2011 (2)
- January 2011 (3)
- December 2010 (7)
- November 2010 (1)
- October 2010 (1)
- September 2010 (1)
- August 2010 (3)
- July 2010 (4)
- May 2010 (1)
- April 2010 (2)
- March 2010 (2)
- February 2010 (2)
- January 2010 (3)
- December 2009 (3)
- November 2009 (8)
- October 2009 (7)
- September 2009 (5)
- August 2009 (4)
- July 2009 (6)
- June 2009 (6)
- May 2009 (14)
- January 1970 (1)
Copyright(C) B-Blog project All rights reserved.
Comments
Post a Comment