SNSへはこちら

FT90マイコンを使ってみよう(5) - 動くようにバイナリを加工

前回まででいい感じに環境を整えてきましたが、まだ Mac から書き込んでも上手く動きません。一方で Windows で公式書き込みツールを使うと動きます。Windows であっても、dfu-util を手動で使っても動きません

動作確認用プログラム

Lチカによってマイコンが動いているかどうかを見ます。前々回と全く同一のものです。Lチカは簡単だし動作確認にもなるし良いよね。

#include <ft900.h>
#include <ft900_startup_dfu.h>

#define LED_GPIO_NUM 13
int main(void) {
    gpio_dir(LED_GPIO_NUM, pad_dir_output);
    gpio_write(LED_GPIO_NUM, 1);
    delayms(1000 * 10);
    gpio_write(LED_GPIO_NUM, 0);
    GO_DFU();
}

そう言えば、ビルドって他のマイコンに比べてすっごく簡単なんですね。リンカスクリプトとかを自分で書かなくても、コンパイラデフォルトの crt0.o とかでなんとかなってしまいます。
FT32 アーキテクチャは FT90 マイコンでしか使われないので、実際に動く構成をそのままコンパイラ任せで扱えるのはありがたいですねえ。

WinとMacでのバイナリの違い

ではなぜ動かないのかをお見せします。これ、実質バイナリ解析みたいで、謎解き感覚で楽しかったんですよね。取り敢えず動かすための答えが欲しい方は次のセクションへ GO!

Windows では FT90x Programming Utility を使って書き込みすると動きますので、このツールを使って生成されたバイナリファイルを見ます。一方で Mac では手動で 0xFF をバイナリ末尾にパディング & dfu-suffix でサフィックス付加をしただけです(サフィックス付加自体は dfu-util に便宜を図るためだけのものなので、マイコン動作には一切関係がない)。なのでこれらで比較します。

いずれも xxd コマンドの出力で見ました。その後 diff をしたところ、末尾のみが異なったと言う感じです。まずは Win と Mac のものを御覧ください。

# Win
0001efe0: ffff ffff ffff ffff ffff ffff ffff ffff  ................
0001eff0: ffff ffff ffff ffff ffff ffff 0304 3e6e  ................
0001f000: ffff ffff ffff 0001 5546 4410 32d4 79d6  ........UFD.2.y.
# Mac
0001efe0: ffff ffff ffff ffff ffff ffff ffff ffff  ................
0001eff0: ffff ffff ffff ffff ffff ffff ffff ffff  ................
0001f000: ffff ffff ffff 0001 5546 4410 5dde 8cd6  ........UFD.]...

参考までに、Windows のバイナリはプログラマ側で加工後、%USERPROFILE%\AppData\Roaming\Bridgetek\なんとか\dfuSuffix.dat に吐き出されます。

ということで、0x1effc から 4bytes 分だけ、謎の値が含まれている事がわかりました。
ちなみに、0x1f000 からのデータは DFU 用のサフィックスなので不要です。

動くバイナリ作成法

以上を踏まえて、以下の操作をすれば動くバイナリが作れるということが分かりました(動作確認済)

  • コンパイラの吐いたバイナリを 126KiB 分だけ 0xFF でパディング
  • 末尾 4Bytes を マジックナンバー 0304 3e6e に書き換え

これで皆さんの作ったバイナリが動くようになります!Mac で書き込んでも、何事もなかったかのように動き出しますよ〜。長い道のりだった...

このマジックナンバー、どうやら場合によって 0304 16d9 になったり色々と変わるのですが、0304 3e6e を書くとどのプログラムでもいい感じに動きます。よく分からんというのが腑に落ちないけどまあいいっか。

動くバイナリ作成用プログラムの公開

バイナリ操作がありますので面倒くさいですよね。ということで、そのために僕が作成した FT930 シリーズ向けのパディング & マジックナンバー付加プログラムを公開いたします。前の記事で書いたものがありますが、その強化版です。

#include <stdio.h>

int parse_arg(int argc, char **argv) {
    (void)argv;
    if( argc < 2 ) {
        fprintf(stderr, "Argument Error\n");
        return 1;
    }
    return 0;
}

int main(int argc, char **argv) {
    if( parse_arg(argc, argv) != 0 ) {
        return 1;
    }

    // open & get filesize
    FILE *fp = fopen(argv[1], "ab+"); // for adding binary data
    if( fp == NULL ) {
        fprintf(stderr, "Invalid Path or File State\n");
        return 1;
    }
    long int filesize = ftell(fp);
    if( filesize >= 124 * 1024 ) {
        fprintf(stderr, "Designated binary size is too large (or already padded).\n");
        fprintf(stderr, "Or is it for FT900?\n");
        return 1;
    }

    // write 0xFF to pad
    for(int i = 0; i < 124 * 1024 - filesize - 4; i++) {
        char buf = 0xFF;
        fwrite(&buf, 1, 1, fp);
    }

    // write signature at the tail
    char buf[] = {0x03, 0x04, 0x3e, 0x6e};
    fwrite(buf, sizeof(buf[0]), sizeof(buf), fp);

    fclose(fp);
    return 0;
}

使い方は簡単。普通に gcc でコンパイルしたら、第1引数にコンパイラの吐いたバイナリを指定するだけです。

$ gcc -Os -Wall -o ft930pad ft930pad.c
$ ./ft930pad output.bin

是非、お役立てください。

(蛇足)DFUの仕様の違いについて

確か前に「ブートローダー謹製の DFU 機能と、ライブラリに付属する DFU は違う?」とか言った記憶があります。
確かに細かな違いがあるようですが、実は大して変わらないようです。今回の記事にように謎解きをして、動くバイナリをしっかりと書き込めるようになって以来、特に違いを意識するような感じにはなってません。