SDカードブートローダー用API
2014年6月22日
ケンケンさんのSDカードブートローダーは、PIC32MX150F128Bを搭載した、SDカードのアクセスとカラーのビデオ出力(NTSC)が可能な、ゲーム用のシングルボードコンピューターである。hexファイルをSDカードに書き込むことで、様々なアプリケーションを読み込んで実行することが可能な仕様だ。これ用のアプリケーションを色々と考えるのは、PIC使い(最近はPIC32ばかり)の私にとっては凄く楽しい。
このブートローダーは24KBの大きさがあり、SDカードへのアクセスとカラーのキャラクターディスプレイの機能がすべて含まれている。アプリケーションを作成する場合、これらの機能が使えるようになれば、色々と応用が利くし、バイナリーのサイズも小さく抑えることが出来る。
そこで、アプリケーション側から、ブートローダーのSDカードアクセスと、カラー・キャラクターディスプレイのコードを呼び出して、これらの機能を簡便に使うことが出来るようにしてみた。
Microchip社のCコンパイラーでは、PIC32でアプリケーションを作成する場合の関数呼び出しのための規約があるようで、同じCPU(MIPS 32)を使用する限り、同じようにコードを呼び出して使うことが出来る。従って、基本的には、ブートローダー用のコードが記述されているフラッシュメモリーの物理アドレスに、ジャンプすればよい。やらなければならないことは、次の2つである。
1)ブートローダー側で呼び出したい関数が、どの物理アドレスから実行できるかを調べる。
2)アプリケーション側では、その物理アドレスにジャンプするようなコードを記述する。
1)に付いては、必要な関数のポインターを配列で用意しておき、それを固定の物理アドレスに配置することにした。2)に付いては、関数ポインターを利用する一般的なCのコードを利用することにした。
ブートローダーの改変
関数ポインターの配列は、初め、次のような方法で確保しようとした。コード用のフラッシュメモリーの一番最後のアドレスに埋め込む方式である。
これはこれでうまく働いたが、コード中では参照されていないこの配列をリンカーが無視しないように、工夫しないといけない。そういった改変を加えると、ブートローダーのサイズがぎりぎりになってしまい、今後コードの改善が必要になった場合にそれを受け付け無くなってしまう可能性があった。他方で、割り込みベクター領域に使われていないフラッシュ領域がたくさんあることに気が付いたので、そこを使うことにした。最終的に、ブートローダー側の変更は、次のアセンブリを"*.s"ファイルとして追加するだけになった。
アプリケーション側のコード
アプリケーション側では、なるべく簡易で分かりやすいコードにしたいと思ったので、ヘッダーファイルをインクルードして、定義されている関数を呼び出すだけで使えるようにした。ヘッダーでは次のように記述している。
関数の実装は、例えば次のように。
ブートローダー側のキャラクターディスプレイでは、幾つかの割込みも使用されている。これらも実装しておかなければ、文字は表示されない。ここは簡単で、割り込みベクターテーブルに、ブートローダーの割り込みベクターテーブルにジャンプするコードを記述するだけで良く、次のようなアセンブリを一つ用意するだけで済んだ。
このプロジェクトを進める上で、上記の部分までは比較的すんなりいったのだが、最後に難関が一つだけ在った。初め、用意したAPIのうち、キャラクターディスプレイに関する部分は機能したが、SDカードへアクセスする部分が機能せず、これを使うと例外でCPUが停止する不具合に見舞われた。色々調べて、ようやく分かったことは、アプリケーション側とブートローダー側で異なるグローバルポインター(gpレジスター)が使われていて、それにより、予想外のメモリーアクセスが在って、それが例外の引き金になっていたことである。最終的には、リンカースクリプトで同じグローバルポインターの値を利用するように指定することで、回避した。アプリケーション用のリンカースクリプトは、ケンケンさんのサイトで指定されている物を変更して使っているが、主な変更点は、以下の通り。
ようするに、ブートローダーで使われているRAM領域、8 kbを使わないように保護することと、その指定によりグローバルポインターが変わってしまうのを元に戻す、というのがポイントである。
最終的に出来上がったAPIを呼び出すための仕組みは、次の4つのファイルをプロジェクトに取り込むことで実装できる。
・api.c
・api.h
・apiint.s
・app_32MX150F128B.ld
これを使えば、今までPIC32を使ったことが無かった人でも、Cの知識さえあれば、容易にSDカードが扱えて、カラーテキストを表示するアプリケーションを作成できるようになるのではないだろうか。
SDカードブートローダ用API ver 0.4.3は、ここからダウンロードできます。
簡単なテストアプリケーションが含まれています。ライセンスは、LGPLです。
このブートローダーは24KBの大きさがあり、SDカードへのアクセスとカラーのキャラクターディスプレイの機能がすべて含まれている。アプリケーションを作成する場合、これらの機能が使えるようになれば、色々と応用が利くし、バイナリーのサイズも小さく抑えることが出来る。
そこで、アプリケーション側から、ブートローダーのSDカードアクセスと、カラー・キャラクターディスプレイのコードを呼び出して、これらの機能を簡便に使うことが出来るようにしてみた。
Microchip社のCコンパイラーでは、PIC32でアプリケーションを作成する場合の関数呼び出しのための規約があるようで、同じCPU(MIPS 32)を使用する限り、同じようにコードを呼び出して使うことが出来る。従って、基本的には、ブートローダー用のコードが記述されているフラッシュメモリーの物理アドレスに、ジャンプすればよい。やらなければならないことは、次の2つである。
1)ブートローダー側で呼び出したい関数が、どの物理アドレスから実行できるかを調べる。
2)アプリケーション側では、その物理アドレスにジャンプするようなコードを記述する。
1)に付いては、必要な関数のポインターを配列で用意しておき、それを固定の物理アドレスに配置することにした。2)に付いては、関数ポインターを利用する一般的なCのコードを利用することにした。
ブートローダーの改変
関数ポインターの配列は、初め、次のような方法で確保しようとした。コード用のフラッシュメモリーの一番最後のアドレスに埋め込む方式である。
__attribute__((address(0x9D005FD0))) static const int g_addresses[]={ (int)setcursorcolor, (int)printstr, (int)setcursor, (int)clearscreen, (int)init_composite, (int)FindNext, (int)FindFirst, (int)FSfclose, (int)FSfread, (int)FSfopen, (int)FSInit, (int)MDD_MediaDetect };
これはこれでうまく働いたが、コード中では参照されていないこの配列をリンカーが無視しないように、工夫しないといけない。そういった改変を加えると、ブートローダーのサイズがぎりぎりになってしまい、今後コードの改善が必要になった場合にそれを受け付け無くなってしまう可能性があった。他方で、割り込みベクター領域に使われていないフラッシュ領域がたくさんあることに気が付いたので、そこを使うことにした。最終的に、ブートローダー側の変更は、次のアセンブリを"*.s"ファイルとして追加するだけになった。
/* 9D00_0220 */ .section .vector_1,code .long MDD_SDSPI_MediaDetect .long FSInit .long FSfopen .long FSfread .long FSfclose .long FindFirst .long FindNext /* 9D00_0240 */ .section .vector_2,code .long drawcount .long TVRAM .long init_composite .long clearscreen .long setcursor .long printchar .long setcursorcolor
アプリケーション側のコード
アプリケーション側では、なるべく簡易で分かりやすいコードにしたいと思ったので、ヘッダーファイルをインクルードして、定義されている関数を呼び出すだけで使えるようにした。ヘッダーでは次のように記述している。
#define fsdpointer ((int**)0x9D000220) #define fvpointer ((int**)0x9D000240)
関数の実装は、例えば次のように。
void printchar(unsigned char n){ void (*f)(unsigned char n); f=(void (*)(unsigned char n))fvpointer[5]; f(n); }
ブートローダー側のキャラクターディスプレイでは、幾つかの割込みも使用されている。これらも実装しておかなければ、文字は表示されない。ここは簡単で、割り込みベクターテーブルに、ブートローダーの割り込みベクターテーブルにジャンプするコードを記述するだけで良く、次のようなアセンブリを一つ用意するだけで済んだ。
.section .vector_6,code nop; j 0x9d0002c0; .section .vector_8,code nop; j 0x9d000300; .section .vector_10,code nop; j 0x9d000340; .section .vector_14,code nop; j 0x9d0003c0;
このプロジェクトを進める上で、上記の部分までは比較的すんなりいったのだが、最後に難関が一つだけ在った。初め、用意したAPIのうち、キャラクターディスプレイに関する部分は機能したが、SDカードへアクセスする部分が機能せず、これを使うと例外でCPUが停止する不具合に見舞われた。色々調べて、ようやく分かったことは、アプリケーション側とブートローダー側で異なるグローバルポインター(gpレジスター)が使われていて、それにより、予想外のメモリーアクセスが在って、それが例外の引き金になっていたことである。最終的には、リンカースクリプトで同じグローバルポインターの値を利用するように指定することで、回避した。アプリケーション用のリンカースクリプトは、ケンケンさんのサイトで指定されている物を変更して使っているが、主な変更点は、以下の通り。
kseg1_data_mem (w!x) : ORIGIN = 0xA0002000, LENGTH = 0x6000 _gp = ALIGN(16) + 0x7ff0 - 0x2000;
ようするに、ブートローダーで使われているRAM領域、8 kbを使わないように保護することと、その指定によりグローバルポインターが変わってしまうのを元に戻す、というのがポイントである。
最終的に出来上がったAPIを呼び出すための仕組みは、次の4つのファイルをプロジェクトに取り込むことで実装できる。
・api.c
・api.h
・apiint.s
・app_32MX150F128B.ld
これを使えば、今までPIC32を使ったことが無かった人でも、Cの知識さえあれば、容易にSDカードが扱えて、カラーテキストを表示するアプリケーションを作成できるようになるのではないだろうか。
SDカードブートローダ用API ver 0.4.3は、ここからダウンロードできます。
簡単なテストアプリケーションが含まれています。ライセンスは、LGPLです。
コメント
ケンケン (2014年6月23日 07:40:42)
ブートローダ側の割り込みベクタの空き領域に関数の配列を格納するとは、
アイデアですね。これだとリンカースクリプトで場所が固定されていますからね。
で、実際に私もブートローダのプロジェクトににapi.sを追加してビルドしてみました。
AP側のテストプログラムもビルドして、SDカードに入れて、期待通りに動作している
ことを確認しました。
出来てしまえば、とてもシンプルで、簡単に見えますね。実際はいろいろと大変
だったとは思いますが。
AP側のリンカースクリプトの修正も意外と単純なんですね。私も正直なところ
リンカースクリプトは詳しくなくて、公開されているものを手探りで修正しました。
もっと詳しくなれば、いろいろ応用できそうです。
アイデアですね。これだとリンカースクリプトで場所が固定されていますからね。
で、実際に私もブートローダのプロジェクトににapi.sを追加してビルドしてみました。
AP側のテストプログラムもビルドして、SDカードに入れて、期待通りに動作している
ことを確認しました。
出来てしまえば、とてもシンプルで、簡単に見えますね。実際はいろいろと大変
だったとは思いますが。
AP側のリンカースクリプトの修正も意外と単純なんですね。私も正直なところ
リンカースクリプトは詳しくなくて、公開されているものを手探りで修正しました。
もっと詳しくなれば、いろいろ応用できそうです。
Katsumi (2014年6月23日 12:38:04)
ケンケンさんの環境でも無事に動作したとのこと。ほっとしました。どうも有り難うございます。
リンカースクリプトは、PIC18ではよく使っていましたが、PIC32では今回が初めてです。ケンケンさんのソースコードが参考になっています。どうも有り難うございます。
リンカースクリプトは、PIC18ではよく使っていましたが、PIC32では今回が初めてです。ケンケンさんのソースコードが参考になっています。どうも有り難うございます。