はじめに
不揮発性メモリ、SDカード、ファイルシステムなどのお話のバックナンバー。
SDカード仕様
https://www.sdcard.org/downloads/pls/index.html
Simplified Specifications | SD Association
FatFs 日本語サイト
http://irtos.sourceforge.net/FAT32_ChaN/doc/00index_j.html
ELM - FatFs 汎用FATファイルシステム・モジュール
組み込みシステム向けFATファイル・システム
FatFs 英語サイト
http://elm-chan.org/fsw/ff/00index_e.html
FatFs - Generic FAT Filesystem Module
Open source FAT filesystem for embedded projects
学習用の書籍とか
FileSystemやSDカード関連の書籍はかなり限られる。
基本はSDAの仕様書を読み込むしかないのだが、先に書籍で概要を把握しているだけでも読み進めやすくはなる。
SDAの仕様書は当然英語で記載されており、しかも文章のコピーができないようになっている。
仕様書の読み込み速度、理解速度を引き上げるためにも事前情報のインプットは重要となってくる。
導入編
https://www.simulationroom999.com/blog/in-vehicle-external-storage-1/
- いつもの小芝居で導入。
- SDカードは繋いだだけでは読み書きできない。
- SDカードドライバ:初期化、セクタ読み書き。
- ファイルシステム:ファイル、フォルダの概念構築。
- 組み込み系でSDカードを使うことは多いので、とりあえず社内の実績を確認。
- 組み込みFatファイルシステムはミドルウェアベンダーから購入することが多い。
- オープンソース組み込みFatファイルシステムも存在する。
- FatFs。
- 日本語サイトもあるが、最新情報が欲しい場合は英語サイトの方を見た方が良い。
不揮発性メモリ
- ストレージとして使える不揮発性メモリはおおよそ3種類
- EEPROM。
- NOR-FLASH。
- NAND-FLASH。
- EEPROMは4[Mbyte]程度なのでファイルシステムを組み込むのは不向き。
- NAND-FlashROMの凶悪な一面を垣間見た。
- 消去単位が128~256[Kbyte]。
- 同等のRAMを割り当てできないとまともに制御できない。
- SDカードの中身はNAND-FlashROM。
- しかし、NAND-FlashROMの凶悪な一面はうまく隠されている。
SDカード
- SDカードの超概要説明。
- SDカードの仕様はSDAが策定している。
- 仕様書の一部は無償で入手可能。
- すべての仕様を入手するにはSDAへの加盟が必要。
- SDカードは4種類。
- 容量が違う。
- 利用できるインターフェース仕様と適用すべきファイルシステム異なる。
- SDカードのインターフェース仕様は2種類。
- SPIモード。
- SDモード。
- SPIはSCK、MISO、MOSI、SSの4種の信号線を使う。
- SSはLowアクティブ。
- LowアクティブはTTL時代のオープンコレクタのHigh、HZの区別が付きにくい時代の名残。
- SSはLowアクティブ。
- 調歩同期は装置間通信、同期シリアルは装置内通信で使われる。
- 同期シリアルの方が圧倒的通信速度が速い。
- SPI通信についての説明をした。
- SCLKの立ち上がりでサンプリング。
- よって、同期シリアルと呼ばれる。
- SlaveがわはSSの立下りで処理の準備をしている場合があるので、Lowのままにせず一旦Highにしておいた方が安全。
- SDのSPIモードとSDモードではコマンド仕様はほぼ一緒。
- SDカードのピン配置説明。
- SPIモード時のピンアサイン説明。
- SDモード時のピンアサイン説明。
- 1番ピンのモード変更及びCardDetecctフローを説明。
- LowにしたりHZにしたり、コマンド投げて内部プルアップ解除と大忙し。
- SDカードの通信の種類は大きく3種類。
- No data Operationはcommandとresponseだけで成り立つもの。
- responseパターンはR1,R1b,R2,R3,R7の5種類。
- R1bがbusy付きresponse。
- busyはresponseの直後に0値出力が続いている間。
- SDカードの(Multiple) Block Read Operation(SPIモード)について説明。
- response後にdata blockが従属する。
- エラー時はresponse後にdata error tokenが従属する。
- data error tokenは読み出しならではのエラーパターンが記載されている。
- SDカードの(Multiple) Block Read Operation(SPIモード)の説明。
- Start Block token、Stop Tran tokenというものがある。
- Single Block、Multi Blockで各tokenが異なる。
- CMD25(WRITE_MULTIPLE_BLOCK)の方が効率的だが、書き込みBlock数が少ない場合はcommand発行回数の都合でCMD24(WRITE_BLOCK)の方が効率的になることがある。
- SDモード通信について確認。
- SPIと同じく同期シリアル通信に該当する。
- ただし、command/responseはCMDライン、read/writeはDATライン
- DATラインは最大4bitのラインとなる。
- SDモードはデフォルトでDAQ0だけを使う1bitモードなので、commandで4bitモードに切り替える必要がある。
- SDモード通信のNo data Operationを説明。
- ノーレスポンスのパターンが割と重要。
- ACMD41でSD、MMC判定。
- CMD8でSDSC、SDHC以降判定。
- SDの仕様が増えるたびに今後増えていくかも。
- ノーレスポンス判定タイムアウトは1秒。
- SDモード通信の(Multiple) Block Read Operationの説明。
- CMDラインとDATラインがあるため、responseが終わる前にdata blockが送出されることを想定する必要あり。
- CMD12(STOP_TRANSMISSION)で強制停止できる。
- SPIモードと使い方は一緒。
- SDモード通信の(Multiple) Block Write Operationについて説明。
- data block送信毎にbusyが入る。
- busyの待ち時間はACMD13(SD_STATUS)で取得できるAU_SIZEに依存。
- AU_SIZEは組み込みに於いては重要なパラメータ。
- AU_SIZEが小さい高速なSDカードを選択したり、AU_SIZEに合わせて書き込み単位を変えたり。
- SDカードのSDモード通信に於いてのレスポンスについて説明。
- SPIモードに無かったR6が追加。
- R6はRCA(Relative Card Address)を取得するもの。
- RCAはCMD7の引数に使われるもので、これが無いと読み書きモードへ移行できない。
- 上記使用はSPIモードには無いもの。
- SDカードのSDモード通信に於いてのレスポンス(R1とR1b)について説明。
- R1の中にcard statusという32bitのエラー&状態情報がある。
- 状態が想定と異なる場合は再初期化等で期待する状態に再遷移させる設計/実装をする必要がある。
- R1bはSPIモードと同じく、R1にbusyが付いたもの。
- busyはDATが0を維持している状態。
SD初期化(SPIモード)
- SDカードはいきなり読み書きはできない。
- 初期化シーケンスを通してSDカード状態を読み書き可能状態へ遷移させる。
- 初期化シーケンスはSDv1、SDv2のルートに分かれる。
- SDv1とSDv2 SDSCはモノとしては一緒。
- SDSCかSDHC/SDXCはSDv2の最後のCCSの判定で分かる。
- SDカードのSPIモード通信の初期化シーケンス詳細を開始。
- 以下の順番で説明予定。
- 初期状態に戻す。
- SDv2以降判定。
- 駆動電圧判定。
- 読み書き可能状態へ。
- SDv2の容量判定。
- 以下の順番で説明予定。
- 初期状態に戻すのはCMD0(GO_IDLE)。
- SDv2を判定するのはCMD8(SEND_IF_COND)でエラーになるかどうか。
- SDカードのSPIモード通信の初期化シーケンスの中の駆動電圧判定について説明。
- CMD58(READ_OCR)を送ると、R3フォーマットのレスポンスが返る。
- R3フォーマットはR1にOCRが付加されたもの。
- OCRのbit15~bit23が駆動可能電圧を示している。
- 自装置の駆動電圧が範囲外の場合は制御不可。
- SDカードのSPIモード通信の初期化シーケンス読み書き可能状態遷移を説明。
- ACMD41(SEND_OP_COND)を投げてR1レスポンスのin idle stateを監視するだけ。
- ACMD41(SEND_OP_COND)のパラメータにHCS(High Capacity Support)の付加してSDHC以降のモードに切り替えられる。
- SDHC以降モードはBlock lengthが512byte固定となる。
- SDカードのSPIモード通信の初期化シーケンスの中のSDv2の容量判定について説明。
- CMD58(READ OCR)を投げてCCS(Card Capacity Status)ビットを確認する。
- CCSが0ならSDSC、1ならSDHC/SDXC。
- 結果的にCMD58(READ OCR)を2回発行するが、仕様書上はmust要件となってる。
SD初期化(SDモード)
- SDカードのSDモード通信の初期化シーケンスを大雑把に説明。
- 次回から以下の流れで説明予定。
- CMD8(SEND_IF_COND)によるSDv2判定及びサポート電圧判定。
- ACMD41(SD_SEND_OP_COND)によるHigh Capacity設定とVoltage Switch可否判定。
- CMD11(VOLTAGE_SWITCH)によるVoltage Switch。
- CMD2(ALL_SEND_CID)によるCIDの取得。
- CMD3(SEND_RELATIVE_ADDR)によるPublished RCAの取得。
- CMD7(SELECT/DESELECT_CARD)によるTransfer State(tran)遷移。
- CMD8(SEND_IF_COND)によるSDv2判定及びサポート電圧判定の説明。
- 以下のパラメータが存在。
- PCI express 4.0 Support有無。
- Voltage Supplied。
- Check pattern。
- セットした値がそのままレスポンスに乗ってくる。
- CMD8(SEND_IF_COND)によるSDv2判定及びサポート電圧判定のレスポンス側の説明。
- レスポンスはリクエストと同等の構成。
- リクエストが受けつけられたかどうかを返しているだけ。
- レスポンスはリクエストと同等の構成。
- 現状は選択肢が少ないので、ほぼレスポンスパターンは限られるが今後のSD仕様の追加次第ではどうなるか分からない。
- ACMD41(SD_SEND_OP_COND)のリクエストについて簡単にに説明。
- 処理の流れとしてはSPIモードのACMD41(SD_SEND_OP_COND)に似ている。
- ACMD41(SD_SEND_OP_COND)のリクエスト、レスポンスのパラメータを確認。
- 新出パラメータ多数。
- ACMD41(SD_SEND_OP_COND)のリクエスト電文、レスポンス電文に出てくるパラメータ説明。
- HCSとCSSはSPIモードでも出来てたパラメータ
- XPCはSDXC Power Control。
- 最大電流値を切り替えられる。
- UHS-IIはその名のとおりUHS-II対応かの確認用。
- ACMD41(SD_SEND_OP_COND)のリクエストとレスポンスのパラメータについての続きを説明。
- S18RとS18AはSwitching to 1.8V Request/Accpeptedで駆動電圧を変更するのに使う。
- UHS-IIの場合は変更不可。
- OCRはSPIモードの時と同じ。
- S18RとS18AはSwitching to 1.8V Request/Accpeptedで駆動電圧を変更するのに使う。
- ACMD41(SD_SEND_OP_COND)のパラメータによる挙動に違いについて説明。
- inquiry ACMD41。
- OCR取得用ACMD41。
- OCRパラメータを0にすることでこれになる。
- first ACMD41。
- 初期化用ACMD41。
- OCRパラメータを非0にすることでこれになる。
- inquiry ACMD41。
- CMD11(VOLTAGE_SWITCH)によるVoltage Switchの説明。
- ACMD41で1.8V切替サポートが確認できたSDカードは1.8V駆動に切替できる。
- Voltage Switchの手順はまぁまぁ複雑。
- タイミングチャートで確認。
- 大雑把に手順確認。
- VOLTAGE_SWITCHはCMD11(VOLTAGE_SWITCH)の発行が起点となる。
- CMD11にはパラメータはない。
- SDカードはR1レスポンスを返した直後にCMDとDATのラインをLowにする。
- ホスト側は入力モードになっているので出力が衝突することは無い。
- カードがVOLTAGE SWITCHの開始受付としてCMDとDATラインをLowにする。
- ホスト側はCMDとDATラインをLowをカード側がVOLTAGE SWITCHの開始を受領したと見なす。
- ホスト側はSDCLKを5ms以上止める。(6ms待ちが安パイ)。
- 上記の5ms後にホストから1.8VのSDCLK送出開始。
- ホストからのSDCLK送出から1ms以内にカードはCMDを1.8VでHighにする。
- ホストはそれを検知。
- さらにカードはDATのラインを1.8VでHighする。
- これもホストが検知。
- 上記をもって、SDCLK、CMD、DATのラインが1.8V駆動で通信可能な状態が相互で確認できたことになる。
- 「CMD2(ALL_SEND_CID)によるCIDの取得」の説明。
- CIDはCard IDentificationの略。
- CMD2(ALL_SEND_CID)のレスポンスはR2レスポンスフォーマット。
- CIDは128bitの6種類の情報を持つ。
- CID(Card IDentification)の内訳説明。
- ManufacturerIDは8bitの数値。(情報未開示)
- OEM/ApplicationIDは2文字のASCIIコード。(情報未開示)
- ManufacturerIDとOEM/ApplicationIDの取得はSD-3C,LLCにライセンスを付与してもらう必要がある。
- CID(Card IDentification)の詳細の話の続き。
- Product nameは最大8文字のASCIIコード。
- “SD01G”のような文字列。
- Product revisionはn.mを示す形でそれぞれ二進化十進数(BCD)で表記。
- 二進化十進数(BCD)は二進法の4桁で0から9を表現。
- CID(Card IDentification)の詳細の話の続き。
- Product serial numberは32bit長のシリアルナンバー
- Manufacturing dateは12bit長のフィールド。
- 8bitで年、4bitで月を表現。
- 「CMD3(SEND_RELATIVE_ADDR)によるPublished RCAの取得」について説明。
- CMD3(SEND_RELATIVE_ADDR)はパラメータ無しのコマンド。
- レスポンスはR6フォーマット。
- RCA(Relative Card Address)とcard status bitsを内包。
- CMD3(SEND_RELATIVE_ADDR)によるPublished RCAの取得の説明続き。
- card status bitsはcard statusの一部を切り出したもの。
- CMD3(SEND_RELATIVE_ADDR)として、card status内の無関係なエラーパターンを削除したものがcard status bitsになっている。
- 「CMD7(SELECT/DESELECT_CARD)によるTransfer State(tran)遷移」について説明。
- CMD7にはSELECT_CARDとDESELECT_CARDがある。
- Stand-by State(stby)とTransfer State(tran)の遷移に使う。
- stbyの方が省電力の可能性あり。
SD読み書き(SPIモード)
- SDカードのSPIモード通信の読み書きの手順について説明。
- 詳細は以下の流れで説明予定。
- Single Block Write処理。
- Multi Block Write処理。
- Single Block Read処理。
- Multi Block Read処理。
- CMD24(WRITE_BLOCK)による書き込みについて説明。
- CMD24(WRITE_BLOCK)のリクエストパラメータは32bitのdata addressが付く。
- 1block512byteとすると2TBが上限。
- CMD24(WRITE_BLOCK)のレスポンスはR1フォーマット。
- ACMD23(SET_WR_BLK_ERASE_COUNT)による消去ブロック数指定について説明。
- ACMD23のリクエストパラメータはNumber of blocks。
- 指定しない場合のdefault値は”1″となる。
- 仕様書上は書き込み高速化が見込めるとあるが、実際はSDカード側の設計次第。
- 「CMD25(WRITE_MULTIPLE_BLOCK)による書き込み」について説明。
- CMD25のパラメータは32bit長の”data address”
- CMD24(WRITE_BLOCK)と一緒。
- CMD25のレスポンスはR1フォーマット。
- R1レスポンスの後にData Block転送。
- Start Block/data Response/STOP_TRAN tokenの発行について説明。
- Start Block tokenは’FCh’。
- data Response tokenにはstatusパラメータが乗る。
- ‘010’であれば正常。
- STOP_TRAN tokenは’FDh’。
- CMD17(READ_SINGLE_BLOCK)による読み出しについて説明。
- CMD17のリクエストは32bit長の”data address”のみ。
- CMD17のレスポンスはR1フォーマット。
- R1レスポンスに追従する形でdata blockがカード側から送られてくる。
- CMD12(STOP_TRANSMISSION)の発行不要。
- CMD18(READ_MULTIPLE_BLOCK)による読み出しの説明。
- CMD18のリクエストパラメータも32bit長の”data address”。
- CMD18のレスポンスもR1フォーマット。
- R1レスポンスに追従する形でdata blockがカード側から送出。
- CMD12(STOP_TRANSMISSION)で止めるまで送出。
- CMD12(STOP_TRANSMISSION)による停止について説明。
- CMD12のリクエストパラメータはなし。
- CMD12のレスポンスはR1bフォーマット。
- busy付きなのはだたdata block転送モードを解除するのに時間が必要になることを想定しているためと思われる。
SD読み書き(SDモード)
- SDモードの読み書きはSPIモードの手順とほぼ一緒。
- 差分はtokenが無い点。
- STOP_TRAN tokenの代わりにCMD12(STOP_TRANSMISSION)を発行する。
- SDモードの読み書きの場合、Transfer State(tran)が重要なのでCMD13(SEND_STATUS/SEND_TASK_STATUS)で状態確認を行う。
- CMD13(SEND_STATUS/SEND_TASK_STATUS)はSTAUSとTASK_STATUSのどちらかを取得できる。
- STAUSはCard StatusのことでR1フォーマットに埋まっているもの。
- Card StatusのCURRENT_STATEが”4:tran”になっていることを確認するのが読み書きする上での目的となる。
- CMD13(SEND_STATUS/SEND_TASK_STATUS)の話の続きを説明。
- CMD13はSend Task Status RegisterでSEND_STATUS/SEND_TASK_STATUSを切替できる。
- Task StatusはCommand Queueの状態監視用。
- Command Queueについては次回以降説明。
SD応答向上仕様
- SDカードには応答向上仕様というものがある。
- すべてのSDカードに搭載されてる保証はないため、利用シーンは限られる。
- 使用SDカードが決定しており読み書きスループットを最大化させたい場合。
- 応答向上はCQ(Command Queue)Modeがキモ。
- Voluntary CQ modeとSequential CQ Modeの2種類がある。
- CQ(Command Queue) Modeを簡単に説明。
- Performance Enhancement Function Register offset 262byte bit1で切替ができる。
- 1:Voluntary CQ mode。
- 0:Sequential CQ Mode
- Sequential CQ ModeはTask ID順に処理される。
- ACMD13(SD_STATUS)で取得できるSD_STATUSの明細。
- 全てを説明するとボリュームが大きいので以下3点に絞って説明予定。
- PERFORMANCE_MOVE。
- VIDEO_SPEED_CLASS。
- APP_PERF_CLASS。
- SDカードのSD_STATUS詳細。
- 今回はPERFORMANCE_MOVEについて。
- SDカード内のNAND-FlashRomは消去単位大きすぎて、普通に使おうとするとRAM不足問題になる。
- SDカード内部に大容量のRAMを持つとコストが上がる。
- よって、RAM使用量削減の手法を用いる必要がある。
- NAND-FlashRomの共通の性質を説明。
- page(読み書き)、block(消去)の概念が共通。
- NAND-FlashRomの省メモリ書き込み手法説明。
- 書き戻さずに、page単位でコピー。
- コピーの最中に書き換えたいpageだけ更新。
- NAND-FlashRomの省メモリ制御についての続きを説明。
- NAND-FlashRomは確率的にどこかのBlockが不良Blockになってる。
- 初期不良Block。
- 後発不良Block。
- よって、リニアアドレス的なアクセスに向いていない。
- 物理Block、論理Blockに分けて変換テーブルを挟んで管理することが多い。
- SDカードのPERFORMANCE_MOVEの話。
- PERFORMANCE_MOVEの明細説明。
- コピー速度を明記しない場合もある。
- Infinity。
- シーケンシャルアクセスを前提とした場合、高速書き込みを保証している場合もある。
- Sequential Write。
- コピー速度を明記しない場合もある。
- VIDEO_SPEED_CLASSについて説明。
- スピードクラス各種。
- スピードクラス。
- UHSスピードクラス。
- ビデオスピードクラス。
- SD_STATUSのVIDEO_SPEED_CLASSのパラメータを参照することでビデオスピードクラスが分かる。
- VIDEO_SPEED_CLASSの話の中のVSC_AU_SIZEについて説明。
- NAND-FlashRomの性質上、書き込み単位は大きい方がスループット上有利。
- よって、書き込み性能が高いSDカードほどVSC_AU_SIZEが大き目な傾向にある。
- AUサイズは8MB~512MB。
- 一回の転送でAUサイズ分を送っているわけでは無く、SUサイズ単位で送っている。
- SUサイズは大体8MB近辺。
- APP_PERF_CLASSについて説明。
- Application Performance ClassはA1、A2がある。
- スマホからの高速アクセスを想定してコマンドキュー、キャッシュを駆使している。
- 上位クラスは下位クラスの仕様を内包する。
- 3hの場合、A2、A1を内包したA3ということになる。
- SDカードのAPP_PERF_CLASSの詳細の話。
- A1,A2共通要件として「連続した1GBの範囲を4MBチャンク」の話がある。
- IOPSは1秒当たりのアクセス回数。
- SDカードの場合1アクセス4kbyte想定。
- A2はA1の4倍の性能。
- コマンド・キューとキャッシュを無効条件でA1サポート義務あり。
- SDカードのPERFORMANCE_ENHANCEの説明。
- PERFORMANCE_ENHANCEの内訳。
- Command Queue。
- キャッシュ。
- ホスト主導メンテナンス起動。
- カード主導メンテナンス起動。
- メンテナンスはSDカード内のデフラグ。
- セルフメンテナンスは2種類。
- ホスト主導で明示的実行。
- カード主導で暗黙的実行。
- セルフメンテナンスを有効化するにはPerformance Enhancement Registerを制御する必要がある。
- CMD48(READ_EXTR_SINGLE)、CMD49(WRITE_EXTR_SINGLE)を使用する。
- セルフメンテナンス有効化に使うコマンドは以下。
- CMD48(READ_EXTR_SINGLE)。
- CMD49(WRITE_EXTR_SINGLE)。
- 基本的にはMemory or I/O、Function Noを指定しての読み書き。
- 書き込み側はbit単位のマスクができる。
- Host-initiated maintenanceについて説明。
- Performance Enhancement Registerで制御。
- Start Host-Initiated Maintenanceで開始。
- Card maintenance Urgencyで緊急度設定。
- Card-initiated maintenanceについて説明。
- Card Initiated maintenance Enableを1にすれば起動。
- SDカードバスがIdleの時に勝手にセルフメンテナンスを実施してくれる。
- R1フォーマットのcard statusにあるFX_EVENTで完了判定。
- 再度、PERFORMANCE_ENHANCEの話。
- Command Queue Supportの内訳確認。
- Queueの深さが分かるパラメータ。
- CQ Modeを選択したり有効化するのはPerformance Enhancement Registerを操作する。
- Enable CQ。
- CQ Mode。
- CQ Modeのステートマシンを見せた。
- 基本フローも書き出し。
- CQ Modeは読み書き処理の予約ができ、その予約はTask IDで識別される。
- Task IDをもって、実際の読み書き結果を取得する。
- 「CMD49(WRITE_EXTR_SINGLE)でEnable CQ=1にする」は前回出た話。
- CMD44(Q_TASK_INFO_A)のリクエストパラメータ説明。
- リクエストパラメータのDirectionは「読む」か「書く」かの指定。
- リクエストパラメータのExtended AddressはSDUCのように2TByteを超える場合に使用。
- SDUCの仕様上の最大容量は128Tbyte。
- CMD44(Q_TASK_INFO_A)のリクエストパラメータPriorityは1だったら優先。
- Voluntary CQ modeの時のみ有効なパラメータ。
- Task IDはCQの数に依存。
- CQの数はPerformance Enhancement Registerから取得できる。
- CMD44(Q_TASK_INFO_A)のリクエストパラメータのNumber of Blocksについて説明。
- CMD44(Q_TASK_INFO_A)のエラーハンドリングについて説明。
- SD側のリソース都合のエラーもIllegal Commandとして返ってくる点に注意が必要。
- CMD45(Q_TASK_INFO_B)で開始Blockアドレスを指定について説明。
- リクエストパラメータは32bit長のStart block address。
- CMD44(Q_TASK_INFO_A)とCMD45(Q_TASK_INFO_B)は2つで1つの意味になる。
- これらのコマンド利用には制約がある。
- CMD44(Q_TASK_INFO_A)とCMD45(Q_TASK_INFO_B)の制約について説明。
- 2つのコマンドは必ず連続している必要がある。
- CMD44の後にCMD45以外だとエラー。
- CMD44の後にCMD45で初めてタスク登録完了。
- 複数のCMD44が来た場合は、最後のCMD44が有効。
- 「CMD13(SEND_STATUS/SEND_TASK_STATUS)でCQの状態を確認」について説明。
- CMD13は以前やったものなので、復習。
- task statusを参照して、ReadyになってるTaskは次のCMD46(Q_RD_TASK)かCMD47(Q_WR_TASK)を投げて良い。
- 「CMD46(Q_RD_TASK)で読み出し」と「CMD47(Q_WR_TASK)で書き込み」について説明。
- 共にリクエストパラメータはTask IDのみ。
- 事前にTask IDに紐づけて情報を渡しているため、Task ID以外の情報は不要。
- 共にリクエストパラメータはTask IDのみ。
- Task IDの概念がややこしいので整理が必要。
- Task ID関連について情報整理した。
- 端的に言うとTask ID = Command Queue番号 = (STATUS_TASK_XXのXXの部分)。
- まだ語っていないコマンド群あり。
- チューニング(CMD19)。
- ERASE(CMD32、CMD33、CMD38)。
- アボート(CMD43)
- CMD19(SEND_TUNING_BLOCK)の説明。
- リクエストとレスポンスは普通。
- CMD19は固定データがData Blockとして送られてくる。
- Fh、Eh、Dh、Bh、7hが多い。
- DAT[3:0]の回線上を見ると何かしら見えてくるかも?
- CMD19(SEND_TUNING_BLOCK)はSDカードバスのチューニング
- 1.8[V]駆動モードの時に利用できる。
- 1.8[V]駆動モードじゃない場合はillegal command扱い。
- カードから送られてくるデータが固定なのはSDカード毎に検査が変わらないようにするため。
- CMD19(SEND_TUNING_BLOCK)の電気回路的な話。
- CMD19を使用して以下を確認するのが目的。
- 最大オーバーシュート、アンダーシュートの確認。
- 最大の伝播遅延の確認。
- 最小の伝播遅延の確認。
- 電気回路の難しいところはハード屋さんがやってくれるはずなのでサポートを万全にすることを意識する。
- 消去系コマンドの説明。
- CMD32(ERASE_WR_BLK_START)。
- CMD33(ERASE_WR_BLK_END)。
- CMD38(ERASE)。
- 消去系コマンドはCQモード時のみ使用可能。
- CommandQueueと連携することで効果が得られるためと思われる。
- CMD32(ERASE_WR_BLK_START)、CMD33(ERASE_WR_BLK_END)について説明。
- リクエストパラメータ、レスポンスフォーマットは一緒。
- 32bit長アドレス。
- R1フォーマット。
- SDUC時はCMD22(ADDRESS_EXTENSION)で5bitの拡張アドレスを指定する。
- CMD38(ERASE)について説明。
- CMD38のリクエストパラメータは32bit長Erase Function。
- Eraseが通常の消去、Discardは管理破棄、FULEは全領域Erase。
- busy待ちはAU_SIZE、ERASE_SIZE、ERASE_TIMEOUT、ERASE_OFFSETから算出する。
- CMD38(ERASE)のFULEについて説明。
- 完全フォーマットとかで使われる仕様。
- CMD38(ERASE)のFULEのサポート有無はSD_STATUSで確認できる。
- 通常のERASEと違い、全領域ERASEであっても1秒以内に完了する仕様となっている。
- 間違って使わないように消去範囲を明示する必要はある。
- CMD38(ERASE)のDiscardについて説明。
- DiscardはSSD由来の用語。
- Discard指定したBlockがどのような状態になるかは仕様上の規定はない。
- Discardしておくと、ストレージ側(SD/SSD)で効果的なウェアレベリングを実施してくれる可能性が上がり、結果として寿命が延びやすくなる。
- CMD43(Q_MANAGEMENT)について説明。
- CommandQueueに登録されてるTaskを全部かTask ID別に停止できる。
- Sequential CQ mode時にTask ID単位の停止は禁止されている。
- 停止した際の挙動は未規定の未保証。
- SDカード関連の話はこれで完了。
FatFs
- FAT解説ページの紹介。
- FatFsの作者であるChaNさんの解説ページ。
- 今後の方針。
- FatFsをPC上で動作させる。
- 現状でもメモリ空間にFATを構築することはできるサンプルが存在。
- SDカードのディスクイメージを吸い上げて、それに対して読み書きとかできたらいいな。(希望)
- FatFsをPC上で動作させる。
- FatFsをDownloadしてきた。
- 日本語サイトではなく、英語サイトから。
- FatFs sample projects for various platformsの方を落とす。
- FatFs sampleの中身確認。
- 様々なマイコン向けのサンプルあり。(avr,stm32,lpc23xx)
- win32がWindows向けのサンプル。
- 様々なマイコン向けのサンプルあり。(avr,stm32,lpc23xx)
FatFs メモリ上シミュレーション
- FatFsのビルド環境準備。
- Visual Studio 2017 expresを使用。
- プロジェクトに設定されているWindows SDKが入っていない場合があるので構成プロパティで設定変更が必要。
- FatFs起動。
- WindowsXP以前だとPCのHDDに直接アクセスできたらしい。
- FatFsと対話するためのコマンド群がある。
- 「?」でhelpが確認できる。
- パラメータ指定に物理ドライブと論理ドライブの指定があるので注意。
- ファイルアクセスの前にフォーマットやマウントなどの処理が必要。
- 上記が済めば、一般的なファイルアクセスAPIが使用できる。
- FatFsでファイルアクセス前の準備の部分を実施。
- 物理ドライブへのアクセス初期化。
- FATにフォーマット。
- 論理ドライブマウント。
- volume status参照。
- FATことFile Allocation Tableはクラスタの繋がりを表現している。
- これによりファイルサイズの伸縮を実現している。
- flコマンドでルートディレクトリ参照。
- 引数はpathなので「0:」のような表現になる。
- ファイルオープン時にmode指定。
- modeはビットアサインになってる。
- ファイルへの書き込みコマンド「fw」はお試しようのため、自由に書き込みが出来るコマンドにはなっていない。
- 対話モードは複数ファイルは開けない。
- ファイル読み取りのコマンド呼び出しの流れは書き込み時と一緒。
- オープン時のmode指定を読み取りmodeにする。
- ddコマンドでディスクイメージをdumpできる。
- 512byte単位なので若干使い勝手は悪い。
- 次回からメモリ上でなく、ファイル上にディスクイメージを構築できるようチャレンジ。
FatFs ファイル上シミュレーション
- FatFs Win32のソースコード群確認。
- 「diskio.c」を改造すればディスクイメージをファイルにできそう。
- diskio.cはWindowsXP時代のHDDアクセス用にAPIが残っている。
- このAPIをうまく流用すると楽かもしれない。
- 認識する物理ドライブを元からあるRAM Diskと別に加えて10個にする方針。
- FatFs Win32のdiskio.cを改造。
- 修正差分確認。
- 改造の概要説明。
- 物理ドライブ走査数をMAX_DRIVE分に修正して認識できる物理ドライブの数を増加。
- 物理ドライブ1以上を指定されたらディスクイメージファイルをオープン。
- FatFs Win32 ファイル上シミュレーション起動。
- マウント、フォーマットをして、ファイルを2つ作成。
- fjコマンドでカレントディレクトリ指定。
- flコマンドでファイルが作られていることを確認。
- ファイルの中身も確認。
- 次回からディスクイメージの中を見ていく。
- FatFs Win32 ファイル上シミュレーションのディスクイメージを確認。
- PhysicalDrive1で生成されている。
- MBR(Master Boot Record)を確認
- FAT32であることを確認。
- BPB(BIOS Parameter Block)が63セクタ目にあることを確認。
- BPB(BIOS Parameter Block)について簡単に説明。
- 重要なパラメータだけ抽出。
- FatFsでの具体的な数値を抽出。
- セクタ、クラスタ、予約領域、FAT領域の数が分かる。
- FAT領域は破損を想定しており、冗長性を持たせ多重化されている場合がある。
- SDカードの場合は1個なことが多い。
- BPB(BIOS Parameter Block)のFAT32におけるオフセット36以降のフィールドの説明。
- FAT12/16とFAT32で構成が違うが、ここではFAT32で説明。
- 重要パラメータはBPB_FATSz32、BPB_RootClus。
- 上記が分かるとルートディレクトリエントリの位置が分かる。
- ルートディレクトリエントリを直接特定できるパラメータはない。
- 以下パラメータが必要。
- PT_System、BPB_RsvdSecCnt、BPB_FATSz32、BPB_NumFATs。
- MBR、BPB、予約領域、FAT領域を積み上げていくとルートディレクトリエントリの位置が分かる。
- ルートディレクトリエントリを確認。
- ディレクトリエントリが並んでおり、作成したtest.txt、test2.txtが存在。
- ファイルの中身の情報はDIR_FstClusHIとDIR_FstClusLOで指定されたクラスタから特定。
- BPB_RootClusでルートディレクトリエントリのクラスタ番号から特定する。
- test.txtの内容のクラスタ位置を確認。
- ファイルの中身を確認。
- 指定した7000[byte]のデータが並んでいたのを確認。
- しかし、7000[byte]が並んでいるのたまたま。クラスタの空き方によっては並ぶ保証は無い。
- FAT領域のクラスタチェーンでクラスタの関係性を表現している。
- FAT領域の位置確認。
- FAT領域参照。
- FAT32の場合、32bit長データを1要素としてクラスタチェーンを表現している。
- FAT16の場合は16bit長データを1要素としている。
- 基本的には該当クラスタがどのクラスタ番号に繋がるかの数値が埋まっている。
- 0x0fffffffがチェーン終端となる。
- FATは基本「8.3形式」というファイル命名規則になっている。
- ファイル名8文字、拡張子3文字。
- VFAT仕様によりその制限を突破している。
- VFAT未対応FileSystemからは「long_file_name.txt」が「long_f~1.txt」のような形で見える用にして互換性を確保している。
- FatFsのVFAT仕様確認方法。
- とりえあず、ロングファイルネームなフォルダとファイルを作成してディスクイメージの中身を確認する方針。
- FatFs対話モードでフォルダとファイルを作成。
- 「long_file_name_folder」作って、その中に「long_file_name_file.txt」を作成。
- ロングファイルネームなフォルダやファイルのディスクイメージ上で確認を試みる。
- まずはルートディレクトリエントリから。
- 存在するファイルとフォルダが3つのはずだが、ディレクトリエントリとしては5つ存在。
- 5つのうち3つがロングファイルネーム仕様を満たす仕掛け。
- ファイル名もasciiからUnicodeになってる。
- ロングファイルネームなフォルダやファイルのディレクトリエントリの関係性を確認。
- LFNが先に現れ、最後にSFN。
- VFAT未対応FileSystemはLFNをスキップしてSFNだけを参照している。
- SFNにフォルダ内のディレクトリエントリの先頭クラスタが埋まっている。
- LFNが先に現れ、最後にSFN。
- ディレクトリエントリが指し示すフォルダの中のデータはフォルダ内のディレクトリエントリ。
- つまり入れ子になっている。
- ルートディレクトリ以外のディレクトリは「.」と「..」の名称のディレクトリが存在。
- 「.」がカレントディレクトリ。
- 「..」が親ディレクトリ。
- 相対PATH用の仕様。
- フォルダの中のディレクトリエントリの構成を図解。
- カレントディレクトリ、親ディレクトリ、LFN→SFNの構成。
- ファイルの実体が配置されてるクラスタ確認。
- ここの考え方は通常の「8.3形式」のファイルと同一。
- 該当クラスタのFAT領域に於けるクラスタチェーンを確認。
- 扱ったのはFAT32。
- 他にFAT12、FAT16があるが、違いはFAT領域のクラスタサイズとディレクトエントリ構造体。
- 基本的な追い方は一緒。
- 組み込み機器ではPCで出来て当たり前がとても困難。
- 「車輪の再発明」という揶揄が適切ではない状況の方が多い。
- 日ごろから「出来て当たり前」の仕組みを考えると吉。
SDカードディスクイメージ
- SDイメージシミュレーションの手順説明。
- その手順及び構成を図解。
- ポイントはLinuxのddコマンドでSDカードのディスクイメージの吸い上げと書き戻し。
- VMware Workstation PlayerとUbuntuが必要。
- 今回はWinodws PC前提だが他のLinux環境でも問題無い。
- WindowsでSDカードをFATでフォーマット。
- FAT12/FAT16/FAT32が選択できないのでFATを指定するのみ。
- 領域サイズで自動選択。
- テキストファイルをSDカード内に作成。
- LinuxでSDカードのディスクイメージ作成。
- dfコマンドでデバイス確認。
- ddコマンドでディスクイメージ作成。
- ディスクイメージをWindows側に持ってきてFatFsシミュレータのプロジェクトフォルダへコピー。
- PhysicalDrive2というファイル名はFatFsシミュレータがDisk2と認識するルールに則った名称。
- FatFsシミュレータでディスクイメージ認識はOK。
- fsコマンドで確認できた。
- Windowsで作成したテキストファイルの有無をFatFsで確認。
- 「long_file_name_file.txt」があることが確認。
サイズもあってる。
- 「long_file_name_file.txt」があることが確認。
- Windowsで作成したテキストファイルの中身をFatFsで確認。
- 「0123456789」の繰り替しのテキストファイルなことを確認。
- FatFsで適当なテキストファイルを作成。
- なんとなくやばそうだが、問題ない。たぶん。
- 事前にリスト確認。
- 「long_file_name_file_by_fatfs.txt」を作成。
- リストでファイルが生成されていることを確認。
- ファイルを読み出して書き込まれているデータが正しいことを確認。
- LinuxでディスクイメージをSDカードへ書き込み。
- ddコマンドで書き込み。
- Windowsで確認前にLinuxでSDカード確認してみた。
- ファイルが作成されていることを確認。
- サイズが正しいことを確認。
- ファイルの中身が正しいことを確認。
- viで「:%!xxd」を実行するとバイナリモード。
- Windows上でSDカードに作成されたテキストファイルを確認。
- ファイルの存在を確認OK。
- ファイルの内容を確認OK。
- ディスク関連はブラックボックスのまま使用してしまうことが多いが、概念だけでも知っておくといろいろな確認手段が得られる。
- 今後の方針としてWindows上からSD直接制御。
SDカード直接制御
- Windows上からSDカード直接制御に意味があるのか?
- 特にない。面白そうだからやる。
- 方針を提示。
- まずは改造。
- その後、FatFs-Windows間で相互運用できるかを確認。
- 一応OS側で保護されているが、HDDにアクセスしないように気を付ける。
- リムーバブルディスクにしかアクセスできないはず。
- FatFs改造方針。
- DeviceIoControl関数を使用する。
- 余談として、ファイルアクセス以外にデバイスアクセスにもReadFile、WriteFileを使用する。
- DeviceIoControlの制御コードにFileSystem関連のものがあるので、これでリムーバブルディスクの直接制御はできそう。
- FatFs改造のソースコード差分提示。
- 次回から以下に注力する形で開設予定。
- dismount_volume関数。
- DeviceIoControlがポイントとなる。
- main.cのVolToPart配列。
- 論理ドライブと物理ドライブ関連。
- dismount_volume関数。
- OSから見たマウント解除方法説明。
- CreateFileに「\\.\d」を指定すると論理ドライブのハンドルを取得できる。
- DeviceIoControlに以下の制御コードを渡すことでOSの論理ドライブアクセスを禁止できる。
- FSCTL_LOCK_VOLUME。
- FSCTL_DISMOUNT_VOLUME。
- FatFs内のVolToPart配列について説明。
- マルチボリューム、マルチパーティション想定したパラメータ。
- PARTITION構造体について説明。
- 物理ドライバ番号とパーティション番号が格納される。
- これにより、論理ドライブ番号、物理ドライブ番号、パーティション番号が紐づけられる。
- 「FatFsでSDカードのFAT認識」を実施。
- マウント「fi 1」及びvolume status「fs 1:」は読み出せた。
- VolToPart配列の定義が反映され論理ドライブ1にSDカードが配置。
あとは実際に読み書きをしてみる。(理屈上は動くはず)
- VolToPart配列の定義が反映され論理ドライブ1にSDカードが配置。
- FatFsでSDカード内のファイルリスト表示。
- 「fl 1:」
- FatFsでSDカード内のファイル内容表示。
- 「fo 1 long_file_name_file_by_fatfs.txt」
- 「fd」
- 「fc」
- 共に問題無く処理できた。
- 「FatFsでファイル生成して書き込み、リスト表示、内容表示」してみた。
- 問題無く動作。
- ファイル名OK。
- ファイルサイズOK。
- 書き込まれた内容OK。
- 問題無く動作。
- あとは、同じようにWindowsからもこのファイルが見えるかを確認する必要がある。
- 前回FatFsで作成したファイルの確認。
- ファイル名:long_file_name_file_by_fatfs_to_sdcard.txt
- ファイルサイズ:20000byte
- 内容:’d’を連続で20000文字
- Windows上でファイルの確認。
- 問題無くファイルを確認できた。
- SDカードをFatFsでフォーマットしてみる。
- 物理的に壊れることはない。はず。
- RAMディスクに対してフォーマットしたことはある。
- FatFs対話モードのコマンドは「fm」。
- fm <ld#> [<fs type> [<au size> [<align> [<N fats> [<N root>]]]]]
- FatFsでFAT32フォーマットを実施。
- フォーマットOK。
- WindowsでFAT32が認識されることを確認。
- 問題なく認識。
- パーティション分けも試したくなった。
- ダメもとで実施予定。
- FatFsパーティション分け用のコード修正。
- VolToPart配列を変更するだけ。
- VolToPart配列で物理ドライブ1に4つのパーティションを認識できるように設定。
- パーティション1~4。
- パーティション0は自動検知でパーティション1相当になる。
- パーティション分けの時のみ使用。
- FatFs対話モード時のパーティション分けコマンド確認
- 「fp」コマンドを使用。
- コマンドパラメータを確認。
- ドライブ指定は論理ドライブ番号ではなく、物理ドライブ番号で指定。
- FatFsのパーティション分けは百分率が使える。
- パーティションについて簡単に説明。
- FatFsは拡張パーティションは未対応。
- パーティション分けを実施する前の事前準備を実施。
- Windowsのディスクの管理でパーティションの削除。
- FatFsでパーティション分けを実施。
- それぞれ25%の4つのパーティションを作成。
- 問題無くパーティションが分かれていることをWindows側から確認。
- 次回はフォーマットをしてみる。
- パーティションのフォーマットはFAT32とexFAT混在で。
- FAT32、au=4096。
- exFAT、au=4096。
- exFAT、au=8192。
- FAT32、au=8192。
- フォーマット実施。
- 問題なくフォーマットできた。
- Windowsのディスク管理上からも確認。
振り返り、まとめ
- 今回が本シリーズの最終回。
- SDカード、FileSystemのそれぞれだけでも結構なボリュームだった。
- SDカード直接制御のフォーマットはWindows上からのフォーマットの自由さを得るのに有効な場合がある。
- FileSystemはWindows等の他のシステムとの相互運用性確保に便利。
コメント