Moiz's journal

プログラミングやFPGAなどの技術系の趣味に関するブログです

Raspberry Piのベアメタル環境からSDCARDにアクセスする(SPIモード編)

はじめに

Raspberry Piのベアメタル環境からSD CARDをアクセスする方法について、限定的ながらある程度成功したので紹介します

周辺機器アクセスはベアメタルの鬼門

ベアメタルというのはOSなしの環境なので、当然ながらプログラミングにあたって各種OSの便利な機能を使うことができません。その中には当然、周辺機器のアクセスも含まれます。
そんな中ベアメタルで周辺機器にアクセスしようとする場合、

  1. ベアメタルで動作するライブラリを見つける
  2. 自分で何とかする
  3. 他の代替手段を探す

といった対策が必要になります。このうち1は一番簡単ではあるのですが、そもそも見つからない、見つかっても自分の目的と微妙に違う、ドキュメントが少ない、などの状況に出会うことがあり、常に万全の状態で使えるとは限りません。実際私が以前OSを移植した時は、Raspberry Piのフォーラムで見つけたSDCARDアクセスコードを許可を得て使わせてもらったのですが、その後バグの存在を指摘されたにもかかわらず動作の詳細が不明なため完全には修正することができませんでした。 また、3は逃げに近いのでなるべく避けたいところです。そうなった場合、「自分でなんとか」しようとするわけですが、次に出会う問題点がベアメタル特有のドキュメントの少なさです。場合によっては情報がまったく無く、詰んでしまう事もめずらしいことではありません。もちろんガチ勢の場合、既存のソフトのリバース・エンジニアリングや対象デバイスの解析などを駆使してどうとでもしてしまうわけですが、われわれ一般人にはかなりつらいところです。

Raspberry PiのSDCARDコントローラー(EMMC)はドキュメントが微妙

数ある周辺機器の中でもストレージは最も基本的なものです。これにアクセスできなければとたんにできる事の範囲が極端にせまくなってしまいます。
Raspberry Piの場合メインのストレージは言わずとしれたSDCARDで、Raspberry PiのCPU(BCM2835)にはEMMC(External Mass Media Controller)というIPが搭載されており、SDCARDとのアクセスをサポートしてくれます。そのEMMCの使い方は、と探してみるとBCM2835 ARM PeripheralsマニュアルにEMMCの項が見つかります(P.65 5 External Mass Media Controller)。
ここで、これは楽勝か?と思いつつ読み進めていくと、どうも勝手が違い読みにくいことに気が付きます。記述が断片的でどのように設定すればばSDCARDにアクセスできるのかわかりません。さらに読みすすめるとこのような文に出会います。

For detailed information about the EMMC internals please refer to the ArasanTM document SD3.0_Host_AHB_eMMC4.4_Usersguide_ver5.9_jan11_10.pdf but make sure to read the following chapter which lists the changes made to ArasanTM’s IP.

どうやらEMMCの使い方はArasanのドキュメントに書いてあり、BCM2835のマニュアルにはそこからの差分しか載っていないようです。記述が断片的なのはそういう理由があったわけです。 それでは、と、Arasanのドキュメントを探すと見つかりません。どこにも見つかりません。インターネット上をさんざん探しましたが、どうやら非公開のようです。やられた...。

まとめると

  • SD CARDへのアクセスが必要
  • BCM2835のEMMCの情報が必要
  • ArasanのIPの情報が必要
  • ArasanのIPのマニュアルは非公開
  • 詰んだ

困りました。

SDCARDのピンはGPIOにつながっている

このように途方にくれながらRaspberry Piのスキマティクスを見ているとSDCARDのピンはGPIOにつながっている事に気が付きました。 f:id:uzusayuu:20180520131226p:plain このあたり専用ピンにつながっているUSBとは事情が違うわけです。さて、ここでこんな考えが頭にうかびます。

「GPIOにつながっているんなら、GPIO経由でソフトでアクセスできるんじゃね?」

これは何も無茶な考えではなく、マイコンなどでは普通に行われる方法です。たとえばCQ出版の「フラッシュ・メモリ・カードの徹底研究」にはソフトウエアコントロールでMMCにアクセスする方法が、同社の「FPGAスタータ・キットで初体験!オリジナル・マイコン作り」にはNIOSからSD CARDにアクセスする方法が記載されています。 やるべきことは、

  1. EMMCを止める
  2. GPIO48から53を、ALT0(EMMC)からInputまたはOutputにつなぎ替える
  3. ソフトウェアからGPIOを制御しSDCARDをSPIモードにする
  4. 同様にソフトウェアでSDCARDの初期化を行う
  5. 同様にSDCARDからの読み出し、書き込みを行う

以上です。ソフトウェアは上記の2書籍に例があるので参考にしつつすすめる事ができます。また、SDCARD自体のコントロールについては、SDのスペック(SD Specifications Part 1 Physical Layer Simplified Specification)に十分な内容の情報があります。なんとかなりそうですね。

SDCARDにアクセスできた、が...

詳細は次回に譲るとして、試行錯誤のすえ、SDCARDの初期化と読み書きアクセスに成功しました。次の図は、SDCARDのFAT領域をベアメタル環境で読みだして、ファイルのリストを表示した結果です f:id:uzusayuu:20180520132857p:plain

今回のデモプログラムはgithubにて公開してあります。

github.com

ただ、ここで大問題があります。
どうやら、次のスペックの記述によると、SDモードからSPIモードへの変更は電源投入後の一回しかチャンスがないようです。SDのスペックの7 SPIの最初の項7.1 Introductionに次のような記述があります。

The interface is selected during the first reset command after power up (CMD0) and cannot be changed once the part is powered on.

Raspberry Piは本体のROMに記録されているブートロジックが最初のブートローダーをSDCARDから読み出すので、この時点でSDCARDはSDモードに設定されています。したがってSPIモードに変更し直すことはできないという事のようです。(痛恨)。 デモプログラムではユーザーにカードの抜き差しをしてもらうことでこの問題点を回避していますが、ちょっと実用的ではありません。やはりSDモードでのコントロールを考えないといけないようです。

あともうひとつ、ソフトウェアコントロールでシリアル通信なので読み・書き・コントロールすべて遅いです。デモではルートディレクトリのファイルを表示するのに1分くらいかかっています。*1

まとめ

以上、Raspberry Piのベアメタル環境からGPIO経由でSPIモードでSDCARDにアクセスすることにある程度成功したので報告しました。 実用性はあまりありませんが、SDCARDにコントロールIPをはさまず直接アクセスできるので、SDCARDの動作を理解するのには役に立つのではないかと思います。 次回以降、処理の詳細について説明したいと思います。

*1:これはさすがにちょっと遅すぎるので、どこか他の部分に問題があるのかもしれません。そのうちどこが本当にボトルネックになっているか調べてみたいと思います。