鳥なき里のマイコン屋(90) Longan nano、microSD

JosephHalfmoon
JosephHalfmoon

RISC-V搭載、お手頃価格でカラーLCDまで背負った小型マイコンボードLongan nano、比較的順調にLCD/LED/DAC/UART(USART)/I2Cと動かしてまいりましたが、今回はmicroSD(TFCARD)であります。ボード下面にスロットがあります。Readはね、何の問題もなかったんですが、Writeに問題あり。

Longan nanoは小さなボードに「これでもか」と部品を押し込んだ感があり、上面の小さなカラーLCD(それでも160×80あるので、16ドットフォントの文字なら10文字x5行の表示可能)など、フレキで基板に接続されていますが、その固定たるやマイコンチップの上面との間の両面テープです。そんな中、ボード裏面に鎮座しているのが、microSD(TFCARD)のスロットであります。

スロットがあるのだから、RW簡単に出来るよね

などと甘く見ておりました。実際、Longan nano用のExampleとしてダウンロードしてあった、gd32v_lcdというフォルダ内には、lcd用のフォルダと並列に

fatfs

のホルダもあり、TFCARDからバイナリデータを読み込んでLCDに表示するようになっています。実際、microSDからの読み込みはその通り真似っ子すればまったく問題ありませんでした。microSDに

put_into_tf_card

というフォルダ内にあるlogo.binをコピーしておきます。目出度いSipeed社のロゴが格納されている25KBほどのファイルです。それをボード裏面のスロットに挿入。ブレッドボードにLongan nanoを刺したままでもmicroSDの抜き差しは出来ないことはないのですが、狭い隙間でかなり辛い。要ピンセット。

差し込んだ後は、例によって前回のソースのチョイ直しであります。

まずは、fatfsのヘッダファイル類の入ったfatfsフォルダを所定のincludeパスにコピー、fatfsのソースファイル類の入ったfatfsフォルダの方は、ソースフォルダにコピー、そして1行インクルード追加。

#include "fatfs/tf_card.h"

オリジナルのfatfsそのものは、実装依存部分が入っていないのだと思いますが、Longan用に改造されたものには「含まれている」(問題あるのだが)ので、これをインクルードすれば、ずるずるとFATFS内のファイルにアクセスする関数群が使えるようになります、一応。

そして、大域変数を定義。ここで、imageという変数は画面にバイナリデータを表示するために使われる変数です。名前は image という名にしないとなりません。バイナリを画面に書き込む関数は、書き込みの座標こそ引数にとるものの、データは image という大域変数から読み込むようになっているためです。なお、この変数は画面半分の大きさしかありません。16ビットカラーの160×40ドット分。ですからファイルから2回に分けて読みだしてLCDに書き込むという手数になります。手元のLongan nanoは幸い32KB RAM品なので全画面分のバッファを確保することができなくもないのですが、20KB RAM品などを考えると半面にしておかないとRAMが足らなくなるからか?

unsigned char image[12800];
FATFS fs;

続いて、簡単なmount関数を作っておきます。真が返ったらファイルシステムをマウントできているので、後の操作をやるように。

int mountTF() {
    FRESULT fr;
    fr = f_mount(&fs, "", 1);
    if (fr == FR_OK) {
        return 1;
    }
    return 0;
}

そして、とりあえずサンプルプログラムを、ほぼベタにコピペしたバイナリファイルをリードして、LCD画面に描く関数。

void readFile() {
    FRESULT fr;
    FIL fil;
    UINT br = 0;
    fr = f_open(&fil, "logo.bin", FA_READ);
    if (fr != FR_OK) {
        LCD_ShowString( 0, 31, "OPEN ERROR!", WHITE);
    }
    f_lseek(&fil, 0);
    fr = f_read(&fil, image, sizeof(image), &br);
    LCD_ShowPicture(0, 0,159,39);
    f_lseek(&fil, 12800);
    fr = f_read(&fil, image, sizeof(image), &br);
    LCD_ShowPicture(0,40,159,79);
    f_close(&fil);
}

これをコンパイルして、走らせると、アイキャッチ画像のように、Sipeed社のロゴが画面に表示されます。その上の文字は、前回までのコードのテキスト書き込み部分。

さて、FATFSをマウントし、ファイルをオープンし、シークして、リードして、クローズできました。次は、

f_write()

じゃね。これと書き込みモードでOPENできれば、ファイルに何かデータを書き込んでいくことができる筈。まず、そのままビルドしてみると、エラーとなりました。これは、何故かと言えば、FATFSの設定を決めている以下のヘッダファイル内で、READONLY指定されているためでした。

ffconf.h
#define FF_FS_READONLY  1
上記の定数が1だとREADONLY、0にすれば f_write()関数が使えるようになり、ビルドが先に進みます。なお、手元の上記ヘッダファイル内でデフォルトのコードページは、簡体字中国語 に設定されていました。文字列を取り扱う際には注意かも。
さてf_write()関数がコンパイルされるようになったものの、こんどはリンカがエラーを吐きます。原因を調べているとき ここで使われているFATFSの実装には、日本語のドキュメントページが存在することに気付きました。ありがとうございます。大変助かります。

手元のソースには、タイムスタンプ関数 get_fattime()の実装が含まれていないように思われました。上記のドキュメントによるとREADONLYモードでは、タイムスタンプ関数は不要(逆に言えばREADONLYでなければ必要)だそうです。そして、とりあえず0返しておいてもタイムスタンプは無だけれど動作はするみたい。そこで、偽物関数追加。

DWORD get_fattime() {
    return 0;
}

やってみると、ビルドも通った感じ。が、しかし、走らせると返ってこない。調べてみると、SPIを経由して1ブロックのデータを書き込むロウレベルの関数が不在に見える。読み込む関数は実装されておるのですが。。。なぜ、片手落ち。ううむ、どこかに見付からない関数を含むソースでも落ちていないか? 今回は、READONLY!

鳥なき里のマイコン屋(89) Longan nano、I2CでAQM1602 へ戻る