2010年10月31日

USBBOOTプログラム用ライブラリ

Linux は Linux でやるとして、USBBOOT で動かすプログラム用の開発環境が欲しくなってきた。

いままで LCD 自体を動かすとか、そういう目的に使ってきたが、テスト目的でも割り込みを使ったり段々高度な使い方になって行きそうだ。デバッグにしてもメッセージを画面に残したいし。ライブラリ化していかないと、収集が付かなくなりそう。

  • 理想は、avr-libc のようなもの。デバイスを生で扱えるレイヤー と 少し使い易くして デバイスの違いを吸収してくれるレイヤー。それと printf みたいな共通ルーチン。

  • ある程度の規模の組み込みシステムだと newlib が良く使われているのだが、ソースだけで 16MB とか規模がすごく大きくなっている。テストやちょっとしたものを作りたいだけなので、規模が大きいのはどうかという気がする。それにデバイスを制御する部分はないので、そこは自分でつくらないといけない。

  • PIC24F や PIC32 だと MPLAB という開発環境がある。豊富な周辺装置を扱っているのでこういうのも参考にできたらと思うのだが、残念ながら PIC は良く知らないのだ。かといってこれから調べるのも大変そうだし ... ライセンス的な不安もある。

とりあえず。次の方針でライブラリーを整備していこうかと思う。

  • avr-libc を参考にして、avr-libc 風味で作る。

  • とは言え、Ingenic が用意した define や マクロがあり、これらは linux や USBBOOT でも使われている。この定義は、整理して使う。

  • 共通関数は、avr-libc でサポートしているものを avr-libc 自体や 他のライブラリから取ってくる。

さて、avr-libc 風味とはなにか?


  • どの CPU かが分かる define 。

    avr-gcc だと -mmcu=atmega88 とか CPU を指定すると __AVR_ATmega88__ が define されるようになっている。汎用の mipsel を使うのでそこまでは出来ないが、CPU の定義で 内部で使うヘッダーを切り替えるようなことはしたい。

    とりあえず __JZ4725B__ とかにしておこうと思う。メーカ名までいれると長くなりすぎ。

  • SIGNAL で定義する割り込み関数。

    avr-gcc だと SINGAL(SIG_ADC) とかで定義した関数は、レジスタをセーブリストアするプロローグ・エピローグに 変更され 割り込みベクタに直接登録される。

    mips では、割り込みベクタは共通になっているので、そういうわけにはいかないのだが、
    そこから先に 擬似ベクタテーブルを置いて、そこから割り込み要因毎に call しようかと思う。

    で、weak シンボルを使って、SIGNAL で定義した関数があれば、デフォルトと入れ替える。
    関数は、特別な関数ではなく普通の C 関数。

    実は割り込みでなにをどうセーブして... といったあたりが良く分かっていない。
    まずは、効率より動かすことが先。-- なんとかして セーブして C 関数を call するところから始めようと思う。
    で、その先で 擬似ベクタテーブルに call してもどってきたら リストアして eret 。

  • avr-libc と同じレベルの共通関数。

    なにからなにまで入れると大きくなるし作るのが面倒なので、avr-libc と同じレベルにしておく。

    いろいろ検討したのだが、newlib だと ライブラリが別のライブラリ関数を call して ... 芋づる式に 大きくなっていくようだ。どうも avr-libc の stdio を移植したほうが良さそう。

    • avr-libc では、最終的に getc/putc のレベルになるようだ。

    • 一方 string とか アセンブラになってしまっている。どうしたものかと思ったのだが、ここだけ newlib 使っても良いのかも知れない。


こんな感じでどうだろう? それに加えて CPU やマシンで使うのに便利な関数群を加える。

  • キャッシュフラッシュ関数 や c0 レジスタのアクセスマクロ

    デバイスを扱うとき メモリに書き込むのを保証しないとダメで キャッシュフラッシュ関数 が必要になる。

    大雑把な 全キャッシュフラッシュと 範囲指定のキャッシュフラッシュぐらいは用意しないと 面倒。

    c0 レジスタのアクセスマクロ としては 割り込み禁止/許可ぐらいにしようかと思うのだが、
    内部の割り込み処理を作るのに必要なものもあるので、それらもついでに 定義しておく。

  • LCD を使う putc のような共通関数。

    Ingenic の ツールとかは、シリアルつかってメッセージを出力する共通関数がある。だが PMP を使う場合 シリアルを引き出すのが難しい。

    逆に LCD は接続されているので、機種ごとに LCD の 出力モジュールを用意したらどうかと思う。

    今、出来ているのは、ILI9325 ILI9326 だけだが、いくつか GPIO の定義が必要なものの、だいたい 共通化できそうな感じ。

    一方 Neo Slim 3000 は、HSYNC/VSYNC を使ったインターフェイスになっていて、ちゃんとフレームバッファを定義した上で、LCD モジュールを 使わないと 表示できない。さらに DMA やら 定期的に転送するための 割り込み処理も必要。

    これもなんとか作って、必要なものが揃っているか確認するとともに、有用に使えるようにしておきたい -- とは思っているのだが、なかなか厳しそう。

  • USBBOOT 対応

    USBBOOT にも対応ではなく、改造版 USBBOOT に対応。

    0x80600000 から ロードして C 関数と同じく a0,a1,a2 にパラメータをセットして call する。a0,a1 は、argc , argv 。

    実行モード は、カーネルモード (Normal)/割り込み禁止でスタート。

    NAND FLASH や microSD/SD からロードすることは別途考える。(= 当面考えない)


作業は進んでいる。判ったことを少し。

  • avr-libc は、かなりアセンブラ化されている。string 系は使えない。printf の中核の vsprintf も だいぶカスタマイズされていて、float 関係の下位関数がアセンブラで使えない。

  • 使えないものは、newlib ではなくて NetBSD から取ってくることにした。vsprintf が似ているのが理由。下位関数を含めて入れ替えて、file 構造体のアクセスを avr-libc に合わせる。

  • ライセンス上あまりあちこちから取ってきたくないので、NetBSD に統一する。string も移植するし、libm も必要なら、NetBSD から持ってくる。

  • NetBSD のバージョンは、2.1 にした。古いほうが シンプルだろうというのが理由。.. ただアセンブラの記法が 合わない。量はすくないし、勉強がてら自力で変換するつもり。

ここまでが MIPS32 共通部分の話。jz47xx 固有の部分や CPU の設定は、全部作る。とはいえ jz47xx のヘッダーは Ingenic が出しているものを ベースにして整理する。

全体の規模は、共通部分 1万行 / jz のヘッダ 1 万行 ぐらい。これに 自作のコードが付くことになる。

... なかなか大変になってきたが、一度作っておくと後が楽になるはず。

ここらで一旦 スナップショット。

当面は、usbboot に同梱。ヘッダーファイルの整理中の状態も入れてあるが、入れるのはこれだけ。次は消す。

ベースにした NetBSD の一部も 置いておく。適当に移植したので分からなくなったときの参照用。

現状:

  • 共通部分はビルドできるようになった。(ただし未テスト) ディレクトリは、

     - include/, stdio/, stdlib/ -- avr-libc-1.7.0 ベース
    - string/, others/ -- NetBSD-2.1 ベース (setjmp.S だけ newlib)

  • jz47xx 固有 + MIPS32 (4Kc ?) は、ヘッダが大分できた。

    - include/jz/ -- jz_xx.h は Ingenic の カーネルヘッダベース (jz_core.h を除く)
       jz_core.h は、主に MIPS32 関係で自作
     - jz/ -- cache.c は、usbboot から取ってきて API を NetBSD 風にした。
       vector.S は、割り込みベクタテーブル avr-libc を参考に weak シンボル。
       delay_us.c delay_ms.c は、ビジーループでの遅延。CPU クロックは CPM の 設定から計算。
       出来ているのはここまで。割り込みを作りたいが全然。
     - drivers/ -- 作ったものを追加していく予定だが、全然。
       一応 ili9325/ili9326 の コードは置いてある。

  • おまけ。

      - done/ jz47xx のヘッダを モジュール毎に切り出したもので、作業用。後で消す。
      - notyet/ まだ反映済みでないもの。CIM と DBLK だけ残っている。

  • Todo
    やるべきことは山ほどあるが、やりたいことから手を付ける。

    (1) hello world 。

    まずは、リンクできてプログラムが動くことを確認する。

    最初に確認したいのは、getopt 。次に puts / fwrite / printf (浮動小数点なし)

    そのためには、puts をつくらないといけない。作るにあたって serial / usbboot / LCD を 選択できるようなことも 考えたい。

    (2) マシン情報の表示

    c0_prid や OTP の情報。CPU クロック と メモリ 量の表示。

    マシン非依存でないと困る。

    (3) 割り込み

    まずは、OS タイマー割り込みを カウントするものでも良いから。割り込み処理ができるようにする。

なんだかんだ変更したので次の版。

変更点:

  • テストプログラムをビルドできるようにした。

    tests/01_hello : ただの hello world 。

    .rel.dyn というセクションがないと怒られたので、target.ld に追加。

    あと、-msoft-float でビルドするようにした。libgcc.a をリンクすると 今度は、.eh_frame がないと怒られそれも追加。

    さらに、malloc 用の __heap_start / __heap_end も追加。一応 16MB でも動くような値にしている。
    メモリマップは、

    0x80600000 text
    data
    6MB bss
    heap
    0x80c00000 stack

    xburst_stage2 がメモリの後ろ 4MB に配置されるので、16MB のことを考えると 0x80c00000 までにしておかなければならない。
    先頭が、0x80600000 なのは、Linux の zImage と同じにしておくため。
    プログラムエリアは 6MB しかないが、前の 6MB も 基本自由に使える。

    malloc と realloc には、 __heap_end との比較のために STACK_POINTER() というマクロを使っているのだが、auto 変数 のアドレス使って適当にやっている。

  • printf を使えるように した。

    FILE *fdopen_serial(FILE *fp);
    FILE *fdopen_ubcomm(FILE *fp, void *p);
    FILE *fdopen_ili9325(FILE *fp, int reset, int cs, int backlight);
    FILE *fdopen_ili9326(FILE *fp, int reset, int cs, int backlight);

    こんな関数群を作った。fp に stdout を指定することで、printf が使えるようになるはず。
    ... だが、これだけでは stderr が出力されないし、複数のデバイスに出力することも出来ない。

    void jzcon_append(FILE *fp);
    void jzcon_setup();

    だいぶいんちきなんだが、一回 fdopen した状態で jzcon_append() するというのを 出力したいデバイス分やって jzcon_append() することで、stdout , stderr に表示できるようにした。

    この関数群を drivers に入れて jz/console.h に定義をまとめた。

    ちなみに、argc/argv は USBBOOT経由で 渡ってくるのだが、コマンドラインが そのまま argv[1] に入っている。普通に使うには、parse_args でバラさないといけない。

    いろいろ初期化が面倒だが、そうしておかないと 低レベル処理のテストがかえって面倒になるので、やむを得ないところ。

これで ようやく Todo(1) hello world の準備ができた。あとはデバッグあるのみ。

とか書きながら、テスト前にさらに変更。

変更点:

  • Todo(2) マシン情報の表示 。

    一応、マシン情報の表示と CPU クロック, メモリ量の表示を作った。

  • Todo(3)に着手。-- OS タイマー周りを Linux のコード見ながらいれてみた。

    OS タイマーは、32bit カウンタで、クロックソースを 外部クロック(12MHz), RTCクロック(32.768 kHz), ペリフェラルクロック PCLK (CPU クロックの 数分の1 (設定による)) から選べて、それを 1/N にするプリスケーラ もある。(N = 1,4,16,64,256,1024)

    自由度が高いのだが、高解像度(PCLK = 100MHz オーダー) と 低解像度 (外部クロック/4 = 3MHz) の 2 つの使い方を 標準ということにした。

    32bit しかないのでいずれオーバーフローするわけだが、100MHz で 43 秒持つ。3Mhz なら 23.8 分も持つ。

    これだけ持てば 割り込み処理がうごかなくとも ちょっとしたベンチマークをするのに使える。それは有用だが、割り込み自体のテストするのにはちょっと具合が悪い。

    割り込み自体のテスト用に 他のタイマーも調べてみたのだが、クロックソース と プリスケーラの機能はみな同じだった。WDT(ウオッチドックタイマー)も同じで 使い方が判ったので jz/wdt.h を作って avr-libc 流に使えるようにしておいた。

    さて、割り込み周り。とりあえず jz/interrupt.h を作って SIGNAL(IRQ_TCU0) とかで割り込み関数を定義するところは作った。

    あと、OS タイマーの割り込み処理も作った。実をいうと細いところはまだ理解していない。... のだが、作った割り込み処理が動くような仕様にしたいと思っている。

    ちょっと細かくなるのだが、

    SIGNAL(IRQ_TCU0)
    {
    REG_TCU_TFCR = TCU_TFCR_OSTFCL; /* ACK timer */
    current_cycle_high++;
    __intc_ack_irq(IRQ_TCU0);
    }

    これが動く仕様にする。
    __intc_mask_irq(), __intc_unmask_irq() は、関数を呼ぶ側で面倒を見るが、__intc_ack_irq() は自分でやる。

    追記: デバイス側の 割り込み要因をクリアしないと INTC の割り込み要因はクリアされないようだ。
    __intc_ack_irq() はダミーで意味をなさない。

  • Todo(3)-- タイマー周りを いれてみた。

    沢山ある 16bit タイマーのうち 1 つを (秒間 100回とか)定期的に割り込みを起こすようにする。基本は OS タイマーと同じだが、違う所もありまだ仕掛り中。

    ちょっとタイマーの機能についてメモ。

    各タイマーは、16bit で 2つの比較レジスタを持つ。ひとつは HALF MATCH。タイマーがこれ以上になると HALF MATCH 割り込みを起こす(もちろんマスクできる) 。もうひとつは FULL MATCH 。こちらは、FULL MACH 割り込みを起こすと共にタイマーを 0 にリセットする。

    で、PWM は、HALF MATCH と FULL MATCH を使って実装するわけだ。定期的に 割り込みを起こすだけなら、HALF MATCH は使わない。

    よく見たら OS Timer も 比較レジスタがあって 0xffffffff に設定されていた。こちらは時刻用だから、フリーランニングにするのが普通。

    WDT も同じく 比較レジスタは 1つ。

    ちなみに、WDT は 16bit もあるし クロックソースやプリスケーラがあって自由度が高いのだが、avr-libc スタイルの wdt.h では、RTC をソースにして、15ms 〜 128 秒の間で 使えるようにしている。

    最大128 秒と大きくしたのは、立ち上げ時とかシャットダウンのときに使えるかなと思ったため。


割り込みの勉強

まず MIPS のレジスタについて。

汎用レジスタは 32 あるが、それぞれ次のように別名が付いていて、特定の役割を持っている。

  • r0 (zero) -- 常に 0
  • r1 (at) -- アセンブラ用 (32bit値 や アドレスのロードなど)
  • r2-r3 (v0-v1) 戻り値 32bitまで : v0
  • r4-r7 (a0-a3) 関数の引数
  • r8-r15 (t0-t7) 関数内で自由に使える 
  • r15-r23 (s0-s7) 関数内で使う場合セーブしてから使う
  • r24 (t8)
  • r25 (t9) 関数の call 先 アドレスにも使用
  • r26-r27 (k0-k1) 割り込み処理でのみ使用するレジスタ。
  • r28 (gp) グローバルポインタ PIC で使用
  • r29 (sp) スタックポインタ
  • r30 (fp) フレームポインタ
  • r31 (ra) リターンアドレス
    ※ PIC はポジションインディペンドコードのこと
    ※ at をプログラムで使いたいときは、set .noat とする。

さて、TX19A のマニュアルを見ると こいつはシャドウレジスタというのを持っているが、 r0/r26/r27/r28 は 対象外。r29 も バンク 1-7 で共通だそうだ。一方 M4K(PIC32MX で採用) とか M14Kc もシャドウレジスタを持っていてこちらは 32 個全部が対象。

MIPS32 と 言っても いろいろあるようなのだが、どうも Jz47xx は、普通の MIPS32 で シャドウレジスタ は持っていないらしい。

次にどういう風に処理するか検討

  • ユーザーモードはサポートしない。OS を作りたいわけではなく、マイクロコントローラのように使いたいだけなのだから。
  • そうすると、正常系の例外・割り込みは 装置からの割り込み (と MIPS のソフトウェア割り込み) のみ。.. ということになるはず。
  • 普通にスタックにレジスタをセーブして、割り込み処理の C 関数を call すれば良さそう。なにをセーブすべきかというと zero, s0-s7, k0-k1 以外 と c0_status , c0_epc(割り込み発生アドレス)。
  • 戻ってきたら レジスタ と c0_status (の IE)をリストアして (セーブした)c0_epc に jump 。
    あとは全部 C 関数に任せる。

    (メモ)
  • ERET は、ユーザモードに戻る命令らしく使わない。
  • セーブ・リストアの処理をするのに k0,k1 が使える。

    割り込みの許可と stack ポインタの復帰を atomic にやりたいのだが、どうするのだろう?
    割り込みを許可したら その時点で 割り込みが入る可能性がある。stack を元に戻していないと stack がどんどん大きくなる可能性がある。

    stack を開放してから k0 に入れておいた c0_status の値を mtc0 。で、k1 に入れておいた 戻りアドレスに jump ?
    -- そうなると mfc0 で割り込み可にした瞬間に 割り込みが入る可能性がある。で、k1 が壊されてしまう。k1 をセーブしても同じで最後に k1 を使わざるを得ない。困った。
    -- ひょっとして アドレスの範囲を見て return しようとしていたら、epc ではなく、k1 に jump ?

割り込み処理の C 関数では、(とりあえず)簡単にするため 割り込み禁止のまま 実行することにする。

とりあえずこの方針で。

実をいうと全然動いていない。どうもコンパイル環境も関係あるようなので、自分でビルドした gcc(4.2.4) で動かす方針で、検討する。 (MinGW環境でmipsel-gccをビルド の記事参照)

    にある dingux_toolchain_20091022.tar.bz2 を linux や xburst_stage1/2 をビルドするのに使っているのだが、このライブラリは MinGW+MSYS 環境 でも使えるようにしたいと思っている。で、自分でビルドしているわけだが、gcc-4.3.4 を使いたいところ 古い MinGW の環境のため make の関係で gcc-4.2.4 までしかダメ。別に gcc が、古くても大丈夫だろうとタカを括っていたのだが、なにか変。-fno-pic を指定しても、一部 PIC 特有の gp を使ったコードになっている。
    とにかく、OpenWRT は動いているのだから そのパッチを使ったら良いだろうということで、試してみている。

全然関係なかった。


    void msg_init(void *p)
    {
    comm_area = p;
    }

    というコードに注目しているのだが、
  • 自分でビルドした gcc の場合
    -fno-pic などを付けようがなにをしようが、

    msg_init:
    j $31
    sw $4,%gp_rel(comm_area)($28)

    というコードになってしまう。gp($28) に正しい値が設定されていないと誤動作する。

  • dingux_toolchain の動作

    -fno-pic では、
    msg_init:
    lui $28,%hi(__gnu_local_gp)
    addiu $28,$28,%lo(__gnu_local_gp)
    lw $2,%got(comm_area)($28)
    j $31
    sw $4,0($2)
    -fno-pic -mno-abicalls では、
    msg_init:
    lui $2,%hi(comm_area)
    j $31
    sw $4,%lo(comm_area)($2)
    -fpic では、
    lw $2,%got(comm_area)($28)
    j $31
    sw $4,0($2)

    という風にオプションに対してコードが変わる。-fno-pic では、gp($28) に値が設定されていることを期待していない。

  • 対策
    外部から呼び出される場合(startup を含む)、gp の設定をちゃんとする。外部を呼び出す場合 gp をセーブして call し戻ってきたら gp をリストアする。

    こんな感じか。

やはりよく判らない。ちょっと実験。


    head.S:
    .text
    .extern c_main
    .globl _start
    .ent _start
    .type _start, @function
    .set noreorder
    _start:
    la $gp, __gnu_local_gp
    j c_main
    nop
    .set reorder
    .end _start
    main.c:

    extern void msg_init();
    extern void msg_proc();

    void c_main(int argc, char *argv[]) {
    int i;

    msg_init((void *)argv);

    for (;;) {
    msg_proc();
    }
    }

    msg.c:

    struct comm_struct {
    void (*proc)();
    };

    struct comm_struct *comm_area;

    static inline unsigned long read_gp() {
    unsigned int c = 0;
    __asm__ __volatile__(" \
    .set noreorder; \
    move %0,$gp; \
    .set reorder" : "=r" (c): );
    return c;
    }

    static inline void write_gp(unsigned long c) {
    __asm__ __volatile__("\
    .set noreorder; \
    move $gp,%0; \
    .set reorder" :: "r" (c));
    }

    void msg_init(void *p)
    {
    comm_area = p;
    }

    void msg_proc () {
    unsigned int saved_gp;
    saved_gp = read_gp();
    if (comm_area && comm_area->proc)
    (comm_area->proc)();
    write_gp(saved_gp);
    }

    上記の head.S main.c msg.c から成るプログラムを 自分ビルドの mipsel-gcc (ver 4.2.4) で作成。共通オプションは、

    -O2 -fno-zero-initialized-in-bss -mips32

    リンクは、binutils-2.19.1 で

       mipsel-ld -nostdlib -EL -T target.ld head.o main.o msg.o -o hello.elf


    で 共通オプションのみ, -fpic を追加, -fpie を追加で比べてみたが同じものが出来た。

    80600000 _start:
    80600000: 3c1c8060 lui gp,0x8060
    80600004: 279c00a0 addiu gp,gp,160
    80600008: 08180004 j 80600010 c_main
    8060000c: 00000000 nop

    80600010 c_main:
    80600010: 27bdffe8 addiu sp,sp,-24
    80600014: afbf0010 sw ra,16(sp)
    80600018: 0c18000e jal 80600038 msg_init
    8060001c: 00a02021 move a0,a1
    80600020: 0c180010 jal 80600040 msg_proc
    80600024: 00000000 nop
    80600028: 0c180010 jal 80600040 msg_proc
    8060002c: 00000000 nop
    80600030: 08180008 j 80600020 c_main+0x10
    80600034: 00000000 nop

    80600038 msg_init:
    80600038: 03e00008 jr ra
    8060003c: af84ffe4 sw a0,-28(gp)

    80600040 msg_proc:
    80600040: 27bdffe8 addiu sp,sp,-24
    80600044: afbf0014 sw ra,20(sp)
    80600048: afb00010 sw s0,16(sp)
    8060004c: 03808021 move s0,gp
    80600050: 8f82ffe4 lw v0,-28(gp)
    80600054: 10400006 beqz v0,80600070 msg_proc+0x30
    80600058: 00000000 nop
    8060005c: 8c420000 lw v0,0(v0)
    80600060: 10400003 beqz v0,80600070 msg_proc+0x30
    80600064: 00000000 nop
    80600068: 0040f809 jalr v0
    8060006c: 00000000 nop
    80600070: 0200e021 move gp,s0
    80600074: 8fbf0014 lw ra,20(sp)
    80600078: 8fb00010 lw s0,16(sp)
    8060007c: 03e00008 jr ra
    80600080: 27bd0018 addiu sp,sp,24

    どうしても いきなり gp を使うと説明したものの具体例。

    -G 0 を 付けてみたら、-fpic とか -fpie に関係なく次のコードになった。

    80600000 _start:
    80600000: 3c1c8060 lui gp,0x8060
    80600004: 279c00a8 addiu gp,gp,168
    80600008: 08180004 j 80600010 c_main
    8060000c: 00000000 nop

    80600010 c_main:
    80600010: 27bdffe8 addiu sp,sp,-24
    80600014: afbf0010 sw ra,16(sp)
    80600018: 0c18000e jal 80600038 msg_init
    8060001c: 00a02021 move a0,a1
    80600020: 0c180011 jal 80600044 msg_proc
    80600024: 00000000 nop
    80600028: 0c180011 jal 80600044 msg_proc
    8060002c: 00000000 nop
    80600030: 08180008 j 80600020 c_main+0x10
    80600034: 00000000 nop

    80600038 msg_init:
    80600038: 3c028060 lui v0,0x8060
    8060003c: 03e00008 jr ra
    80600040: ac44008c sw a0,140(v0)

    80600044 msg_proc:
    80600044: 27bdffe8 addiu sp,sp,-24
    80600048: afbf0014 sw ra,20(sp)
    8060004c: afb00010 sw s0,16(sp)
    80600050: 03808021 move s0,gp
    80600054: 3c028060 lui v0,0x8060
    80600058: 8c42008c lw v0,140(v0)
    8060005c: 10400006 beqz v0,80600078 msg_proc+0x34
    80600060: 00000000 nop
    80600064: 8c420000 lw v0,0(v0)
    80600068: 10400003 beqz v0,80600078 msg_proc+0x34
    8060006c: 00000000 nop
    80600070: 0040f809 jalr v0
    80600074: 00000000 nop
    80600078: 0200e021 move gp,s0
    8060007c: 8fbf0014 lw ra,20(sp)
    80600080: 8fb00010 lw s0,16(sp)
    80600084: 03e00008 jr ra
    80600088: 27bd0018 addiu sp,sp,24


    どうも -G 0 は、いわゆる static に 近いようだ。で、-G 0 を付けないと gp が正しいことを常に期待するコードになっている。

    ... となると xburst_stage1 は -G 0 付きが良さそう。xburst_stage2 は、リロケータブルだから、-G 0 なしにしなくてはならない。で、ロードして実行するプログラムは、基本どちらでも良いが、libgcc が -G 0 なしだと思うので -G 0 なしに統一しておいたほうが良さそう。

    ちなみに xburst_stage2 は、アドレステーブルを自分で変換している。仕様をあわせないとたぶん動かない。

    ところで、-fno-zero-initialized-in-bss は、まともな start-up を持っていないので初期化をさぼるために入れている。いずれ外さないといけないと思っている。

問題がひとつ判った。jalr v0 となっている所。xburst_stage2 のコードは、飛び先アドレスを t9 に入れておかないといけない。理由は、t9 相対で gp を設定しているため。 逆に gp は壊してしまうので、-G 0 を付けない場合は、call 前後でセーブ・リストアが必要。

ここを直したら、プログラムが動くようになった。ようやくデバッグが出来る。

デバッグが少し進んで printf が使えるようになった。一旦スナップショット。


変更点:

  • printf , getopt が動くのを確認。

    いろいろバグはあった。修正した中で重大かも知れない仕様変更をした。

    変更したのは、stdin/stdout/stderr 。ポインタではなく、実体のアドレスに変更。
    - 要するに代入できない。まだ malloc を動かしたくないのが理由。

    usbboot のプログラムのほうにもバグがあったので修正。

    たぶん malloc や memcpy/memset は未確認。memcpy/memset はアセンブラで結構複雑。
    - 条件によって動くコードが変わるのだ。

  • Todo(2) マシン情報の表示 。

    一応、マシン情報の表示と CPU クロック, メモリ量の表示が出来た。

    Jz4725: c0_prid 0x0ad0024f
    Jz4725B: c0_prid 0x1ed0024f
    (Jz4750 : c0_prid 0x1ed0024f )
    Jz4755: c0_prid 0x2ed0024f


    CPU クロック, メモリ量 は、Jz4725/Jz4725B で正しく取得できている。
    ただ OTP は全然。Jz4750/Jz4755 系でないとダメなのかも。

    c0_prid は、何だろう? 8bit づつに分けて 4 つのフィールドになっているらしい。
    - ベンダー 0xd0 core 0x02 rev 0x4f で、最上位の 1 バイトはベンダー定義。

    Jz4725B は Jz4755 と違って core の拡張はないようだから これで合っているようだ。ベンダー定義の部分は、 00001010 と 00011110 の違いか。

  • xburst_stage1 が 動くのを確認。

    自分ビルド gcc-4.2.4 を使ってのビルドで動作が確認できた。
    オプションは、-G 0 。

    xburst_stage2 はまだ動かせていない。

    Todo
    (3) 割り込み (つづき)

    いま作ってある ostimer と timer を動かす。

    (4) timer の 実用化。

    callback を登録できるようにする。-- なにやら OS っぽくなってきたが、次のステップで必要なのだ。

    (5) ベンチマーク

    時間が分かるようになったならベンチマークをしてみたい。MXU あり/なしの jpeg-6b とか をやってみたい。

    (6) generic-LCD での表示。

    要するに Neo Slim 3000 で LCD を使えるようにしたいのだ。ここまで出来れば終了の予定。

バージョンアップした。

変更点:

  • Jz4755 (T555) での動作確認と修正

    jzlib 自体は 変更なし。マシン情報の表示はできたが、予想に反して OTP は見えない。

posted by すz at 14:12| Comment(0) | TrackBack(0) | Jz47xx(USBBOOT)

2010年10月21日

Linux(r237)のテスト

ベースバージョンをr237に変更したが、そろそろテストを開始しようと思う。

まずは、ブートするまでの流れを おさらい。

  • メモリマップ:

    0x80000000
    割り込みベクタとか
    0x80002000
    (8KB) (1)xburst_stage1
    (stack)
    0x80004000
    0x80010000
    0x80100000 (offset 1MB) :
    (u-boot ) : (4)kernel(vmlinux.bin)
    : + initrd
    0x80600000 (offset 6MB) 0x80600000(max)
    (3)kernel (zImage)

    0x81c00000
    (4MB) (2)xburst_stage2
    (stack)
    0x82000000 (32MB の場合)

  • usbboot で boot コマンドを入力すると、xburst_stage1/2 をロードして 実行する。stage1 はメモリとかクロックとかハードウェアの初期化で、stage2 は、コマンド処理。stage1 は実行後不要になる。
  • kernel (zImage) は、0x80600000 にロードして同じアドレスから実行する。改造した usbboot では コマンドラインも渡せるようにしている。
  • kernel (zImage) は、0x80010000 から 内蔵したイメージを展開していく。イメージは、vmlinux.bin + initrd 。
    パラメータ(コマンドラインのアドレスとか) はセーブしていて、vmlinux.bin を実行するときに渡す。
  • vmlinux.bin の開始アドレスは、kernel_entry (arch/mips/kernel/head.S)
  • kernel_entry は start_kernel(init/main.c) を呼び出す。
  • start_kernel では、かなりの初期化を実行した後(printk すら 使えるようになった後)、setup_arch(arch/mips/kernel/setup.c) を呼び出す。ここから プログラムのメモリ(BSS) 以外のメモリの初期化とかが始まる。

次に、前回 (r108) でどこまで実行できたか

  • zImage をロードして制御を渡す 。OK
  • start_kernel 実行開始 OK 。
     - LCD のバックライトを点灯させることで確認
  • setup_arch 実行開始 NG 。
     - setup_arch まで行かない。


今回は、r237 ベースに変更してしきり直す。

今回からは、バックライトに加えて、赤黄の LED が使える。また、ある程度処理が進めば、
LCD へのメッセージ出力 も可能になる予定。

さて、前回と同じところまで行くものなのか確認 -- したら全然動かない。

困った。全く動かない。

過程を書くとちょっと込み入った話になるので、パスして結果だけ。

  • zImage が カーネル(kernel_entry)に処理を渡すのは確認できた。
  • だが、kernel_entry から startup_kernel に処理がわたらない。
  • 細かく調べると 冒頭の mtc0 が動かないことが判った。

      kernel_entry:
      800144f0: 40086000 mfc0 t0,c0_status
      800144f4: 3c011000 lui at,0x1000
      800144f8: 3421001f ori at,at,0x1f
      800144fc: 01014025 or t0,t0,at
      80014500: 3908001f xori t0,t0,0x1f
      80014504: 40886000 mtc0 t0,c0_status

    • c0_status というのは、カーネルモードとか割り込み禁止とかの CPU の動作モードや 割り込み原因などのステータスが格納されているレジスタ。
      このコードは、それのビットを立てたり落としたりしている。

      c0_status の意味:(一部)
    • bit4 UM
    • bit2 ERL (RESET/NMI 発生時に 1)
    • bit1 EXL (通常例外/割り込み発生時に 1)
        - UM=1 かつ ERL = 0 かつ EXL = 0 のときユーザモード。
    • bit0 IE (1: 割り込み許可 / 0: 割り込み禁止)

  • c0_status になにを設定すると動かないのか細かく調べたところ

    もとのデータは、0x1240CE16 が多いが このうち
    0x4 -- ERL ビットを 0 にすると 止まるか暴走する
    ことが判明。
    ちなみに、暴走した後放置しておくと、フラッシュから立ち上がった。

  • 調べると Reset や NMI で実行開始した場合 ERL bit が 1 になる。
    ERL を 0 にするには、

    (1) ERET で復帰
    (2) プログラムで 0 を書き込む

    の 2 通りがあるらしい。(2) では暴走するのだから (1) の方法を使うのか?
  • 頼りになるものは、u-boot のソースコードぐらいだが ... JzRISC では

    /* CU0=UM=EXL=IE=0, BEV=ERL=1, IP2^7 = 1 */
    li t0,0x0040FC04
    mtc0 t0,CP0_STATUS

    としていた。

ERL=1 だと割り込み許可ができない(or 無効) 。困ってしまったが、最初の割り込み許可までは、動作確認できるはず。
とりあえず
  • 先頭の CP0_STATUS の設定 (arch/mips/kernel/head.S)
  • raw_local_irq_disable (arch/mips/include/asm/irqflags.h)
  • raw_local_save_flags (arch/mips/include/asm/irqflags.h)
  • raw_local_irq_restore (arch/mips/include/asm/irqflags.h)
の 0x1f を 0x1b にすることで 先に進むことにした。

  • 大雑把にいうと動作モードには、ユーザモード/カーネルモードがあるが、カーネルモードにも種類があって、ERL=1 は NMI/Reset での実行状態/EXL=1 は 例外(システムコールとか)・割り込みが起きたときの実行状態/UM=ERL=RXL=0, は通常の実行状態。
    上記の対処は、ERL を変更しないようにしたということ。

こうすることで、setup_arch の直前まで来た。

さて、setup_arch の直前には printk が入っている。これをどう表示させるのだろう?

ちゃんと調べてみると arch/mips/kernel/early_printk.c というのがあってここで定義している。で、call する関数は prom_putchar() 。
そして、prom_putchar() は、(現config では) シリアルを使う版が arch/mips/jz4750l/board-a41.c に記述されていた。

ならば、prom_putchar() を LCD を使うように書き換えてみたところ .... 出た。



最後のメッセージは、NR_IRQS:256 で ここから先は、やはり ERL を 0 にしないと無理そうだ。

それはともかく、いくつか気になるところがある。

  • F4750L とあるが、もう分離しているのだから、A-41 / A-33 に変更しなくては。
  • メモリが 64MB 認識されてしまっている。

    usbboot -f /etc/xbufst-tools/a41-boot64M.cfg

    として起動しているので、64MB の RAM は実際にあるし使える状態。だが、

    usbboot> exec arch/mips/boot/compressed/zImage mem=28M

    として起動しているのだ。( exec は、新規で作成した コマンド )
    mem= を認識させないと stage2 が壊れてしまう。
    ... それにしてもなぜ 64MB と分かるのだろう? トータルのメモリサイズは渡していないのに。

      64MB は、JZ4750L では、ハードコーディングされていた。

      zImage だと 0x80600000 にロードして、先頭から実行すれば良いのだが、別の起動方法もある。
      objcopy で vmlinux を 変換し、0x80010000 にロード。
      実行は先頭ではなく、kernel_entry のアドレスを nm で調べて(いつも同じアドレスだが) そこに go する。具体的には、

      # mipsel-linux-objcopy -O binary vmlinux vmlinux.bin

      usbboot> load 0x80010000 vmlinux.bin 0
      usbboot> go 0x800144f0 0 mem=28M

      ... この方法だとテストプログラムで パラメーターを渡す実績もあるのだが.. linux で認識してくれなかった。... バグっているらしい。

テストその2(続き)


これで、どこまで行くか調べたところ、init_IRQ() (init/main.c) から call される arch_init_irq() (arch/mips/jz4750l/irq.c) までだった。

clear_c0_status(0xff04) /* clear ERL */

というのがあって、ここではじめて ERL を clear しているつもりらしい。意味がないので、0xff00 にしておいた。


    これで次に止まるのは、次のところと分かっている。
  • raw_local_irq_enable (arch/mips/include/asm/irqflags.h)
    -- 0x1f を 0x1b に 0x1e を 0x1a にしておく。


最後に止まるのは、calibrate_delay() -- 実際にタイマ割り込みが来ないと 先に進めないようだ。

  • ちなみに、calibrate_delay() が完了すれば、おなじみの BogoMips が表示される。


さてどうしたものか ...Linux カーネル Tree にマージ申請したときの紹介には、

  • The JZ4740 has a mostly MIPS32 4K compatible core (no on cpu timers)

と書いてあるのだが ...

とりあえず、MIPS 4K ファミリーの Software User's Manual というのを見てみる。CP0 のレジスターは、 $0-$31 まで定義されていて、

    $12 STATUS (上記の c0_status のこと)
    $14 EPC (通常の例外・割り込みからの復帰アドレス)
    $30 ErrorEPC (NMI/Reset からの復帰アドレス)

と書いてある。実際に値を読みだしてみると...

    $14 EPC 0xADD273F3 とか 0x8DDA73F3
    $30 ErrorEPC 0x94D5BFFF

なにか初期値がそのまま入っている感じで電源投入の毎に微妙に値が変わるのだが、起動後は、何回読みだしても同じ値。

これらに 適当な値を入れて ERET すると ... ユーザモードになって ... 結局アドレスエラーで 例外が起きそう。では、BEV を 0 にした上で、0x80000180 とか 0x80000200 の一般例外ベクタから 望むアドレスへの ジャンプ命令を書いておけば良いのだろうか?

で、それをどこでやるのが適切なのだろう? やはりブートローダからのカーネル実行?

  • ERET は、カーネルモード(通常 NMI や例外・割り込みで切り替わる)からの復帰命令。


    これをテストプログラムでやってみた。

    0x80000180からの例外ハンドラは、

    3c028000 lui v0,0x8000
    24420170 addiu v0,v0,0x170
    8c480000 lw t0,0(v0)
    8c440004 lw a0,4(v0)
    8c450008 lw a1,8(v0)
    8c46000c lw a2,12(v0)
    01000008 jr t0
    00000000 nop

    こんな命令列にする。その 16バイト前から ジャンプアドレスと パラメータを入れておく。なにか例外が起きれば、ここが実行されるわけだ。例外は故意に起こすが一旦ユーザモードに入らないといけないので、ERET を使う。( ErrorEPC にアドレスエラーを起こす値を設定しておく。)

    プログラムに実行が渡ったときの c0_status は、

    0x1200EE13 -- UM = 1 , EXL = 1, IE = 1

    状態としておかしくない。で、
  • IE を 0 / 1 にするのは OK 。
  • UM を 0 にするのは OK 。
  • EXL を 0 にすると ... 例外。
    という動作になった。... どうも ERL/EXL を変更するのはダメのようだ。

    それはともかくこれで割り込み禁止/許可ができる。

  • ブートローダ(usbboot) で 例外を起こして Linux 実行。
  • Linux では ERL/EXL を変更しない。
      0x1b を 0x19 に / 0x1a を 0x18 に

    という方針でやってみる。...

    ところでなぜこんな変なのか? 推測するしかないが、例えば UM/ERL/EXL の状態に応じたシャドーレジスタがあるとか
    ... 他のものがちゃんと動いているはずだし ... なにか設定があるのだろうが今のところ分からない。

で、やってみた。割り込みが許可できるようになったが、calibrate_delay() で止まる。

ちょっと見たところ jz4750l と jz4750 で time.c が全然違う。 jz4750 や jz4740 の time.c をコピーしてもビルドはできるが、やはり動かない。

    ちょっと CPU の違いをメモ

    OS Timer (32 bit) 16bit PWM
    Jz4740 x 8 8(?)
    Jz4750 o 6 6(0-5)
    Jz4725B o 5 5(0-3,5)
    Jz4755 o 6 4(1-3,5)

  • jz4750 では、タイマー割り込みには、timer5 を使用している。
  • OS Timer は、get_cycles 用に使用。

    jz4750 と互換性はありそうだが、PWM の都合上 timer0-2 にしないと困りそう。
    割り込みには、TCU0-2 の 3 つがあり timer5 は TCU1 ?
    jz4740 では、timer0 / timer1 / timer2-7 で 3 種類の割り込み。

    (linux の分類の) jz4750 と jz4750l では、レジスタの定義が一部違う。

    jz4750:
    #define IRQ_MSC1 13
    #define IRQ_MSC0 14
    jz4750l:
    #define IRQ_MSC1 24
    #define IRQ_MSC0 25

    jz4725B はいったいどっちなのか? それともまた別なのか?
    ちなみに DMA チャネルのの数

     jz4750 12
    jz4755 8
    jz4725B 6

    jz4750:
    #define MAX_DMA_NUM 12 /* max 12 channels */
    jz4750l:
    #define MAX_DMA_NUM 8 /* max 8 channels */


    jz4755/jz4725B は、jz4750l に近そうだし、CONFIG_FPGA で切り分けできるし、jz4750l を間借りして良かったとは思うのだが ... 情報がないし骨が折れそうだ。

    でも usbboot で テストプログラムを動かせるし、実際に割り込みが起きたらどのビットが立つのか調べることはできるから、あまり心配はしていない。

    もうすこし調べてみると、(INTC)割り込みコントローラと(CPM)クロックジェネレータがだいぶ違う。-- この違いは、付いているデバイスの種類と最大数の違いから来るものでやむを得ないようだ。
    あと (CIM)カメラインターフェイス と (IPU)イメージプロセッシングユニットが違う。-- これは、jz4750l が 設計中のもので変なのだろう。

    追記: なんと Jz4755_pm が入手できた。これを見ると 割り込み原因のビット割り当ては jz4750l に合致する。
    Jz4725B は、4755 を shrink したものだろうから たぶん jz4750l で良いはず。
    タイマーの割り込み割り当ては、timer0,3,4,5 が TCU1/timer 1,2 が TCU2 。
    クロック供給の設定も jz4750l に合致。

    ただし、
    #define INTC_ISSR (INTC_BASE + 0x18)
    #define INTC_ISCR (INTC_BASE + 0x1c)
    は存在せず、INTC_ICSSR が変なアドレス(0xB3016000)にある。

まぁ、ここらあたりで一旦整理しようと思う。
usbboot の 起動方法が変わったので いままでの テストプログラムの動作に問題が出るし。

    asis 版
  • linux-jz4725b-r237-wk.tar.bz2
  • usbboot-wk14.tar.gz

    usbboot は、1 回実行すると そこで終わりになった。割り込みをいじったりする場合は仕方ないとしても今までのプログラムも最後に暴走することになる。

    内部で状態を変更してからの実行にしたい。そのためには、少々面倒なことをしないと。
    引数が 使えるから、レジスタをセーブして、引数にセーブエリアをわたして、例外つかって jump 。... みたいな。

    追記:いろいろやってみたのだが、結局

    ERL = 1, EXL = 1 → ERL = 0, EXL = 1

    ならなんの問題もないことが判った。

テストその3(続き)


現在は、calibrate_delay() で止まっている。

タイマー割り込みの処理が実行されて jiffies がカウントUP されば、BogoMips が表示されて先に進むはずだが 割り込みの処理が実行されない。

で、local_irq_enable() call した後 (init/main.c) で、いろいろレジスタを表示させてみた。

    c0_status 10000403 (EXL = 1, IE = 1, only Hard Int 0 is enabled )
    c0_cause 30c00700 (Hard Int 0 is caused, Excepton code = Interrupt)
    CPM_CLKGR 00000000 (All Clock Gate are opened)
    INTC_ISR 00200040 (TCU2 , RTC are pending)
    INTC_IMR ff5fffff (TCU0, TCU2 are not masked)
    INTC_IPR 00200000 (TCU2 is active ?)
    TCU_TSTR 00000000
    TCU_TSR 00000000
    TCU_TER 00008004 (OS Timer , timer 2 are enabled)
    TCU_TFR 00000004 (timer 2 is FULL comparison matched)
    TCU_TMR 003f003b (Os Timer, timer 2 are not masked FULL comparison match intr)
    TCU_TCNT2 00000a42
    TCU_TCNT2 0000099f

なんだか正常そうなのだ。timer 2 を使って 周期的に割り込みを起こし、TCU2 の割り込みが発生する設定なのだが、timer 2は進んでいるし、TCU2 の割り込みも発生していて pending になっている。

割り込みも許可できているつもりだが ... 違った。ERL と EXL ともに 0 でないと割り込みは来ない。結局最初の問題に戻る。

いろいろやってみたら... write_c0_cause(0) をしてから EXL = 0 にすると ... 先に進んだ。

... で mtd が組み込まれてしまい。

bad eraseblock 210 at 697f000
Bad eraseblock 2598 at 5137f000
Bad eraseblock 2600 at 5147f000

こんなメッセージが ... まだオリジナルのファームウェアを壊すつもりはないので焦ったが、一応立ち上がった。

とりあえずメッセージが流れてしまったので、途中で止めて BogoMips をみてみた。

226.91 BogoMips 

だそうだ。CPUクロックを 228MHz にしているので、CPUクロックにほぼ一致する値になるらしい。

結局、arch_init_irq() (arch/mips/jz4750l/irq.c) の

clear_c0_status(0xff04) /* clear ERL */

write_c0_cause(0);
clear_c0_status(0xff1f) /* clear ERL */

に変更するだけで良かった。(ここまで ERL=1 / EXL=1 で来るので、割り込み禁止とかの変更はイキ)

次は、console とか パラメータとかをキチンとしよう。

    asis 版
  • linux-jz4725b-r237-wk2.tar.bz2
  • usbboot-wk15.tar.gz

    たいして変わっているわけではないのだが、ここまでの分のバックアップ。
    usbboot-wk15 は、wk13 ベースに戻した上で wk14 のテストコード追加。


追記: 結局 write_c0_cause(0)は、usbboot でもすることにした。これで、c0_status 周りを元に戻しても問題なくなった。.. のだが別に悪影響があるわけではないので当面すのままにしておく。

さて、今は usbboot での環境を整備しようかと思い、jz47xx の reg.h と ops.h を見ている。jz4740 や jz4750 といったチップ毎に reg.h ops.h があるのだが、どこまで同じで、なにが違うか分かるようにするため、チップ毎のファイルを コントローラ毎に してみている。

  • ひとつ重大なことを発見。.. jz4740 と jz4750l の rtc のコードにバグがあった。jz4750 だけ直してあった。

  • コントローラ毎に してみると ほぼ同じものもあるが、全然違うものもある。SLCD (Smart LCD) はあまり変わらないのだが、LCD (Generic LCD) は、機能が大幅に拡張されていて レジスタの数が 2倍ぐらいになっている。全然違うのは、他には CIM (カメラ) , ICDC (internal CODEC) 。あと SSI や MSC(SDカード), DMAC(DMA コントローラ)は、コントローラーが複数になっていて マクロが変更になっている。
  • INTC (割り込みコントローラ) , CPM(クロック) などは、周辺デバイスの構成が変わっているので チップ毎に違う部分がある。

  • ICDC (internal CODEC) は、Jz4740系 と Jz4750系ではまったく違う。Jz4740系 は、レジスタが普通にメモリにマッピングされているが、Jz4750系は、まるで別デバイスのようだ。
  • IPU のヘッダファイルは変。他のと違う。アプリケーションからとってきて突っ込んだ感じ。Jz4750 と Jz4755 も違うので困惑したが、デバイスそのものは同じだった。編集して 他のに合わせることにした。
    ついでに jz4740 の pm を見て比べたところ、互換性はだいぶあるが、随分拡張されている。
  • OTP(One Time Programmable Module というのがあって、そこにチップの情報が格納されている。
    プロダクトID やら ユニークな ID を作れる情報もある。

まぁこんな感じ。この作業を通じて だいぶ分かってきたような気がする。

Linux については、ちょっとお休み。パラメータはちゃんと渡っていることは確認できた。... が xburst_stage2 に callback すると panic することが分かった。ちゃんと panic まで来ているのだが、なぜなのかまでは分かっていない。これをどうにかしないと... 先に進めない。

ついでに書いておくが、手持ちのなかで Neo Slim 3000 だけが採用している HSYN/VSYNC インターフェイスの LCD は、なかなか使うのが難しいことが判った。DMA も必要だし 周期的に表示するため タイマも動いていないといけない。-- 要するに最初のデバッグに利用するのは困難。

posted by すz at 19:02| Comment(0) | TrackBack(0) | Jz47xx(Linux)

2010年10月19日

Jz4755(T552とか)

いままで、JZ4725B の話題ばかりだったので、ここで JZ4755 の話題をまとめておこうと思う。

CPU について




0.4mm ピッチ LQFP176 pin パッケージで、内部のブロック図はこんな風になっている。

JZ4725B とこが違うのかというと...

  • SIMD2 :

    SIMD 命令は JZ4725B にもある(60命令)が、命令が追加されているらしい。(SIMD2: 114命令)

  • SDRAM :

    JZ4725B は 16bit 幅だが、16bit/32bit 幅を選択できる。

  • MSC1(SD/MMC インターフェイス):

    JZ4725B は、1bit データ幅 で SD/MMC の性能を使い切れない。JZ4755 は 4bit データ幅。
    ちなみに、SDHC の最高周波数は 50MHz だが 80MHz まで使える (SDHC UHS-I対応?) 。
    MSC0 というのもある。(JZ4725B も同等機能 , 4bit 最大80MHz) ... のだが NAND FLASH と排他で使うもので boot 用。

  • SPI/SSI インターフェイス(最大 50MHz):

    JZ4725B にはない。MSC1 とピンが共用なので実質使えないかも。

  • タッチパネルインターフェイス:

    JZ4725B にはないが、その他の Jz47xx チップはたいがい持っている。

  • UART :

    JZ4725B と同等の 1ch だが、JZ4725B は GPIO に使われてしまうケースが結構ある。JZ4755 は実質使える。

  • サウンド出力 (カップリングコンデンサレス) :

    よくわからないが、BTL 出力ができるらしい。JZ4725B には BTL はない。

  • CS2/CS3 :

    NAND FLASH/SRAM の チップセレクト 要するに NAND FLASH/SRAM を合計 4 つまで付けられる。JZ4725B は 2 つまで。

  • AC97/I2C 出力: JZ4725B にはない。
  • カメラ入力: JZ4725B にはない。
  • TV 出力: JZ4725B にはない。
  • TS インターフェイス: JZ4725B にはない。


Jz4755 のチップは taobao で買える。たとえば ここなら 1 個あたり 25 元 (1元=15.5円として 390円)。パッケージは、0.4mm ピッチとはいえ LQFP176 で 個人の電子工作で扱える範囲には入る。
 あと こことか。

    DINGOO A320 などで使われている JZ4740 は BGA で、電子工作でどうにもできないので、あまり興味がなかったりする。

    JZ4760 には興味があるが、LQFP176 あたりの PMP向けチップが出た上で買えるようにならないと。

さて、このチップは、Dual-Core だが、1 つは VPU で DSP 的に使う。キャッシュのかわりに SRAM が 32KB 。-- どうやって そのもうひとつを使うのか分からないのだが、どうも qi-hardware のメーリングリストに入って ある人にリクエストすれば NDA なしでもらえるらしい。

    qi-hardware が入手しているドキュメントには、

    • XBurst Microprocessor Core, Rev 1.0, Apr 2007, 62 pages
    • Jz4725B Data Sheet, Rel July 7, 2009, 37 pages
    • Jz4725B Programming Manual, Julz 14, 2009, 529 pages
    • Jz4720 Data Sheet, Rev 1, Jun 2008, 37 pages
    • Jz4740 Data Sheet, Jun 2007, 35 pages
    • Jz4740 Programming Manual, July 22, 2009, 539 pages
    • Jz4750 Data Sheet, Apr 2009, 40 pages
    • Jz4750L Data Sheet, July 17, 2009, 37 pages
    • Jz4750L Programming Manual, July 14, 2009, 570 pages
    • Jz4755 Data Sheet, July 7, 2009, 33 pages
    • Jz4755 Programming Manual, Jul 22, 2009, 732 pages

    というのがあるそうだ。この情報は、google のキャッシュに残っていたもの。Jz4750L 単独で Data Sheet やら Programming Manual があるのが興味深いが、それはさておき Programming Manual がないと VPU は扱えなさそう。

    そもそも、Jz4725B の Programming Manual ですら入手できていない。Linux のソースコードがあるので、たいがいの機能は使えるわけだが、VPU は どういう使い方をするのか 分からない.. と思う。

      追記: なんと jz4755_pm が入手できた。VPU が出来ることは、IDCT, Motion Compensation,Motion Estimation,De-Block の 4つだけで レジスタに値を書き込むことで制御する。

    ところで、Jx4755 とかの Xburst core は、MIPS32 4K core あたりとだいたい互換らしいのだが、4K core (5段パイプライン)だと 180nm プロセスで 167MHz ぐらい。Xburst(8段) は同じ 180nm プロセスで 360MHz まで行っている。なにげに結構すごいのかも。

Jz4755 が載った PMP -- Mahdi T552


今は Jz4725B の PMP ばかり集めていて Jz4755 が載った PMP は持っていない。Jz4725B が自由に扱えるまで手を出さないつもりだが、一応調べてみた。

このなかで、Mahdiが結構 Jz4755 の製品を出している

そのなかでも気に入ったのは、T552



こんなやつ。4.0 inch (480x274) 。

気に入ったのは、ここのレビューに分解写真があるのも理由。





  • メモリは、W9812G6GH-6(16MB) x 2 。
  • 例によって FM ラジオのパターンもある。
  • LCD は 0.5mm ピッチ 50pin ? -- RGB インターフェイスか?
  • 裏面に部品がほぼないのは、嬉しかったり。

面白いことに KO Digital HD-300 というのも同じ筐体のようだ。



これは一体なんなのだろう? ProjectXA の文字が見えるところから、ChipRise というところが設計・製造しているのだろう。.. ということは、両方 OEM ?

    KO Digital (可欧) というところも 大きなメーカーっぽい。http://www.kocode.com (FLASH / サウンド付き注意)
    HD-300 はだいぶ古い製品のようで現行は、HD900A とか。ここ見ると 明らかに Jz4755 。画面が例のもの + 720p対応。
    ... どうもよくわからないが、HD系は Jz4755 が多そう。(ただし HD800系は RK かも)


それはさておき、これはどこで買えるのだろう?

ひとつは、ownta.com で、$79.80 -- 84円換算で 6700円。
Free shipping だが、 Registered Airmail $15.74 というのを見ると不安になる。送料を払うなら Express Shipping (3-5 days) - $16.74 が良さそう。

もうひとつは、taobao で、例えば ここここだと 送料込まずで 265元 -- 15.5 円換算で 4100 円。
随分と安いように見えるが、代行業者を通さないと買うのは無理そう。

    例えば taobao 代行業者の グッズエイト を通すと ...
     ( 265元 + 中国国内送料 約20元 + EMS送料 60元 ) x 15.5(元→円)
       + 手数料 500円 = 約 5800円。( これ以外に +振込料金x2回 )。

    代行業者にもいろいろあって、上記は一例。利用したこともないし別にお薦めというわけではない。
    だいたい 元→円のレートは、12円ちょっと。明示されている手数料は 5% だが、レートが 30% 増しに近い。そしてそれは、手数料や送料にもかかる。それでも高くなければ良いのだが、なにか釈然としない。


まぁこんな感じなのだが、 T552 だと Camera インターフェイスもタッチパネルも使っておらず .. 線も引き出せない。(自分でビルドした Linux を動かす前提で VPU が使えないとすると) Jz4725B の PMP と比べて メモリと SD/microSD が速いだけで 機能的にはあまり変わらないことになる。

これではちょっと面白くないのだ。... というわけでパス。

追加: T555




T552 が高いのは、液晶のせいで Jz4755 が高いせいではない。たとえば ここの T555 は、3.0 inch 400x240 , 4GB で A-32 の Jz4755 版という感じだが、170元(本体のみなら 150元)しかしない。... ただ 小さいのはメモリも 16bit かも知れないし、やはり T552 のほうが良さそう。
 あと ここ は、180元。

追記:
パスと書いたが、Jz4755 の Programmers Manual 手に入ったし、買ってしまうことにした。

なにを買うかだが、T552 は、まず欲しい。理由は Jz4755 で 本当にちゃんと H.264 が見れるのかどうかを チェックするため。ちゃんと見れるのならば、画面も大きめだし 実用としても使えそうだ。

ただ、プログラムを動かしたりするのならば、LCD がネック。Smart LCD ではないと思うので制御がたいへん。電子工作で LCD を 外すとかするなら 0.5mm ピッチ 50 pin なのは 嬉しい。フレキとかコネクタの入手性は、54pin の Neo Slim 3000 より良い。

T555 も良いように思えてきた。たぶん Smart LCD で デバッグとかするのに都合が良いし、電子工作で使うにしても LCD を外して線を引き出すのは 楽なはず。ただし、メモリが 32bit でない可能性が高く その点ではイマイチかも知れない。 jz4755 でないということはないはず。720p 対応を謳っているし、TV-out がある。Jz4725B に TV-out の機能を付けると却って高くなりそうだし。

届いたらレポートする予定。

    追記:2010/11/16 なかなか来ない。T555 は、生産中止・希望色 在庫切れだそうで.. 色変更するだけで 2 週間かかってしまった。今製造しているのは T556/T557 らしい。




ところでこれは何だろう? Mahdi が出している M18 Touch という製品らしいのだが、タッチパネルの上に(有線だが)コントローラが付いている。これが、Jz4755 だと面白いのだが ... Jz4755 とは限らない。

Jz4755 が載った E-Book -- EB70




aliexpress.com で 唯一 jz4755 でヒットするのは この 電子ブック EB70

値段は、$89.47 x 1 + $16.96(@EMS) = $106.43 。

液晶は普通の 7inch TFT LCD 800x480 だがタッチスクリーン 。メモリは 32MB , FLASH は不明(8GB まで)。バッテリー容量も不明(3300mAH まで)。 Wi-Fi: 802.11b/g が付いている。他の外部インターフェイスは microSD , イヤホン , スピーカー (マイクも? ) 。leather case が付属。

.. なんというか Android 端末を Jz4755 までダウングレードした感じ。

開発・テスト用ならこういうのも良いかも知れないのだが... 実用として使うならどうなのだろう?
CPU のクラスとしては、RK27xx よりは速いと思うが、RK28xx には負ける。そして、VPU や SIMD を使いこなしてはじめて本来の性能になるから、ファームウェアの出来が重要。
だが、肝心のファームウェアの出来が分からない。

Jz4760


ついでに Jz4760 について書いておこう



前に JZ4760 が出るらしいと書いたが、データシートから転載したらしいブロック図を発見。(url)

日付は、2010-08-20 で随分前の情報だ。ingenic のコードにも随分前から Jz4760 の対応が入っている。出るのは確実なのだろうが、いつになったら出るのだろう? 来年?

それはともかく、ありがたいことに英文の説明も付いている。たぶんこれもデーターシートからの抜粋。


  • XBurst Jz4760 is a mobile application processo targeting for multimedia rich and mobile devices like Smart phone, PMP, mobile digital TV, and GPS. This SOC introduces an innovative dual-core architecture to fulfill both high performance mobile computing and high quality video decoding requirements addressed by mobile multimedia devices.

  • The CPU (Central Processing Unit) core, equipped with 16K instruction cache and 16K data cache operating at 600MHz, and full feature MMU function performs OS related tasks. At the heart of the CPU core is XBurst processor engine. XBurst is an industry leading microprocessor core which delivers superior high performance and best-in-class low power consumption.

  • A hardware floating-point unit which compatible with IEEE754 is also included.

  • The VPU (Video Processing Unit) core is powered with another XBurst processor engine. The SIMD
    instruction set implemented by XBurst engine, in together with the on chip video accelerating engine and post processing unit, delivers doubled video performance comparing with the single core implementation.

  • The memory interface supports a variety of memory types that allow flexible design requirements, including glueless connection to SLC NAND flash memory or 4-bit/8-bit/12-bit/16-bit/24-bit ECC MLC/TLC NAND flash memory for cost sensitive applications.

  • On-chip modules such as audio CODEC, multi-channel SAR-ADC, AC97/I2S controller and camera interface offer designers a rich suite of peripherals for multimedia application.
  • TV encoder unit 10-bits DAC provide composite TV signal output in PAL or NTSC format.
  • The LCD controller support up to 1280x720 output, as well as external HDMI transmitter.
  • WLAN, Bluetooth and expansion options are supported through high-speed SPI and MMC/SD/SDIO host controllers.
    The TS(Transport stream) interface provides enough bandwidth to connect to an external mobile digital TV demodulator.

  • Other peripherals such as USB OTG and USB 1.1 host, UART and SPI as well as general system resources provide enough computing and connectivity capability for many applications.

    ざっとみて、Jz4750 から変わったのは、

    • CPU の周波数 360MHz(400MHz?) → 600MHz
    • FPU (浮動小数点演算ユニット)
    • DDR/DDR2 のサポート (SDRAM は未サポートになった?)
    • USB Device (HI-Speed) の OTG 対応。
    • 2D グラフィックスエンジンの追加。
    • MMC/SD/SDIO の数 2 → 3 等高速シリアル系の強化

    といったところか。機能的には Jz4750 のちょっとした強化版 のように見える。プロセスルールが 180nm → 130nm になるようだ。

    まぁ、最近の Android 向け 高性能 ARM チップには太刀打ちできない。だいたい RK2808 クラス。.. だが MIPS で カーネルソースや情報を公開しているということに意味がある。
    それに(おそらく)値段も安く、あまり高価でないPMPに採用されるはずで、開発して遊ぶには嬉しいポイント。

上にも書いたが これの PMP向け LQFP版 がでると嬉しい。.. だが、これを使いこなすには VPU の使い方がわからないと...

    追記:VPU の使い方は判った。Jz4755 で判らないのは、SIMD(60命令) → SIMD2(114命令) の差分ぐらい。

    2D グラフィックも判った。(Jz4760 データシート入手! ただし pm はない。)

    ― Up to 100M pix/s
    ― Up to 1080P
    ― Line/Rectangle
    ― ROP4/Alpha blending/Filter
    ― Rotation (90/180/270 degree)/Mirror
    ― 1 Rectangle Clip

    だそうだ。ようやく Rotation が出来るようになったわけだが ... キャッシュラインサイズ(32 byte) x 画面縦分の SRAM を持って 変換してから メモリに書き戻すとかしないと メモリ負荷がとんでもないことになりそう。いったいどうやっているのだろう?


追記: VPU の使い方が判ったと書いたが、Linux のソースには、説明がないものの定義が含まれている。VPU が出来ることは、IDCT, Motion Compensation(MC),Motion Estimation(ME),De-Block の 4つだが、MC/ME は定義がある。

よくよく見ると Programmers Manual にすらない OTP (One Time Programmable Module) の定義まである。
OTP には、(どのCPUかが分かる)プロダクトID や (ユニークなIDを作れる)ウェハのIDと位置が入っている。
.. これは嬉しいかも。

追記 20101122: New console in prototype stage
という記事が出てきた。

  • Ingenic 4755 (Dual Core Clocked at 400 MHz but can be overclocked to 550Mhz The second core is a VPU similar to a GPU)
  • 4.0 TFT LCD (Brand: King Display KD43G16-40NC-A3 Resolution: 480x272 Active area: 95.04mm x 53.86mm 262K color, 24bit parallel RGB interface)
  • 64MB SD Ram (Winbond W9825G6EH-6 (2 pieces) 4M words x 4 banks x 16 bits = 32 MB 166MHz/CL3 or 133MHz/CL2)
  • 2GB NAND (Samsung K9GAG08U0E 16 Gb = 2GB MLC, large block 8-bit interface)
  • MicroSD Memory Slot
  • D-Pad and Analog Nub on left
  • Standard A,B,Y,X on the right and L1 R1 Shoulder buttons on top
  • 4MP Video Camera/Camera
  • OS will be Dingux with hopefully a new menu system the fall back will be Gmenu2X



    プロトタイプ基板の画像も出ている。

    外観は、ありきたりな PSP タイプになってしまうようだ。
    (写真は他の人が予想したものだが、基板の形をみれば判る)

    基板だけ見ると Neo Slim 3000 とよく似ている。Hold スイッチがなかったり、カップリングコンデンサの容量が少なかったり デザイナーが同じじゃないかと思えるほど。それに加えて P5-5 のようなマイクロコントーローラも付いている。

    値段は、Estimated price $80 to $85 USD 。ファームウェアの開発にお金をかけていれば 妥当な気がするが... そうでなければ、ちょっと高めのイメージ。

    売れるかどうかは、オリジナルのファームウェア次第か。それが Dingux なら結構期待できるかも知れない。ただ Jz4755 用にカーネルを移植するのは 骨が折れそうなんだが、大丈夫なんだろうか?

    -- 勘違いしていたが、dingoo-digital から出ている情報らしい。本物の次機種?
    なら ファームウェア は期待できそうだ。だが、550Mhz までオーバクロックするのは本当なのだろうか? Jz4740 と同じ 180um なのに?

    -- dingoo-digital も dingoo-tech も関係ないと書いてきた。... ならファームウェアの問題は厳しそう。

    11/24 ウォッチしているんだが、Jz4760 モデルの話も出てきた。今から 9ヶ月後 .. そうかその頃か。



    まさか ... Get-Arcade Pocket Console (RMB320) のことだったりするのだろうか?

    4.3 inch で カメラ付いているし、2GB しかないし。写真さがすと microSD だし TV-OUT あるし。
    A320のチームが作れば Jz4755を選びそうなものだが ... 同じ形状の ものは 無数にある。

    やっぱり違うかも。
posted by すz at 21:04| Comment(0) | TrackBack(0) | Jz47xx

2010年10月01日

USBBOOT で LCD制御

A-41 の LCD は、コントローラで制御する Smart LCD 接続になっていることが判った。おそらく 兄弟機である A-33 も同じだろう。

  • Smart LCD 接続では、フレームバッファを用意して、定期的に 出力するような制御は不要になり、PORT を叩くだけで制御できる。

  • そのかわり、どのようなコントローラが載っていてどのようにコマンドを発行するのかという情報が必要になる。

  • Smart LCD なら、Linux でデバッグする前に、単純なプログラムで試してみることが出来るし、そうするほうが開発効率が良い。

... というわけで USBBOOT で動かせるプログラムとして LCDを制御するようなものを作ってみようと思う。

ピンのアサインについて

    LCD が どのように GPIO に割り付けられるのか? .. これを知らないといけないわけだが、SLCD コントローラを使う前提になるから、だいたいは決まってしまうのだ。

    LCD_DAT0-LCD_DAT17 (LCD の DB0-DB15(+ DB16,DB17) に接続)
    LCD_VSYNC( = SLCD_CS) LCD の WR
    LCD_HSYNC( = SLCD_RS) LCD の RS

    LCD の CS/RD を使う場合は別途 GPIOを(PORTD から)割り当てる。
     - A-41 では RD は 固定 (read しない/できない)

    Linux のコードだと PIN_CS_N / PIN_RESET_N が GPIO として定義されることになっている。RESET も GPIO かも知れない。

    追記:
    A-41 は、
     LCD RESET = 102 PD23 LCD_SPL(LCD)
     LCD CS = 103 PD22 LCD_CLS(LCD)
    だということが分かった。


コントローラについて

    そもそもこれがなにか分からない。だから試行錯誤しなければならないのだ。

  • A-41 では、ILI9325 が有力だが、違うかも知れない。

    FPC-TLN240T36A1 というのが載っているのだが、
    "FPC-TLN240T36A5 9325"でググるとなにやら沢山ヒットする。

  • A-33 は 400x240 なので、320x240 用の LCD コントローラは使っていない。ILI9326 か?

    ちなみに、ILI9325/ILI3926 では アプリケーションノートの PDF もあり、初期化例が載っている。

解析方法について

  • CSとRESET のピンアサインだけは、探す必要がある。CS(RESET) を プルダウンしてみて、GPIO を読めばたぶん分かる。
  • まずは、解析などせず ILI9325 だと思ってプログラムを作成し動かしてみる。全然だめなら解析する。

  • 解析は、ロジアナを使うつもりだが、16ch なので、16bit + RS/WR を一度には取れない。まずは、RS/WR + 下位8bit 分。
    これで、インデックス レジスタの設定を見て どういうレジスタを使っているかを知る。

  • それであたりが付けられなかったら RS/WR + 上位 8bit も取る。同じシーケンスのはず(RD がないから状態によってシーケンスが変わらない)だから、全部が分かるはず。

  • でも、まずは 解析の練習を フォトフレーム KDPDK24 でやるつもり。
     - オリジナルのファームウェアを消す段階になったら、8bit タイプの LCD に交換するのも良いかも知れない。なぜなら 8bit 分GPIO が空く。多分 GPIO の空きは 0 だから貴重。

  • 問題は、テストピン。外れたりすると面倒だから 配線をハンダ付けしてしまうかも。配線材は、ピンヘッダ用接続ケーブル[CB-PH10P-250] を切って使うつもり。

     - PDPDK24 の 20pin の空きパターン(1.0mm ピッチ)でハンダ付けしているのだが、線が太すぎてなかなか難しい。
     - ちょっと反則だが、
      
     これを切ってテストピン代わりに付けるか。
    - 強度が足りなかった。プローブ付けたらもげてしまった。
    - やはり ハンダ付けか。

追記:

    PDPDK24の分析練習は終了。ST7785 か そのあたりのコントローラのようだ。2Ah(CASET), 2Bh(RASET), 2Ch(RAMWR) の繰り返しで画面を更新している。

    picfun: 2.4/2.8インチ QVGA液晶表示器の制御 に、ILI9325 のライブラリがある。LCD が使えるかどうかのテストならこれを参考にしたほうが分かりやすい。

バスについて



  • ILI9325 で 16bit アクセスをする場合、DB17-10 が上位 8bit / DB8-1 が下位 8 bit 。ちなみに、8bit アクセスする場合 DB17-10 に接続し、上位→下位の順で 2 回 Write する。(8bit 用のコードを参考にするのに必要な情報)

    16bit アクセスすると 決め打ちしているが、IPU が使える条件は、32bit (R8G8B8) か 16bit(R5G6B5) しかない。IPU を使わないと 動画性能が落ちるのでかならず使っているはず。


追記:実際のコードを組んでみる。

RESET と CS は判ったので、コードを組みはじめることはできそうだ。(確認したのは、A-33 だが、A-41 も同じだと思う。)

で、A-41 は ILI9325 だと思うので、これ用のコードを検討する。

まずは、ILI9325AN -- アプリケーションノートにあるコードを見てみると ... いくつかのパネルに対してのコードが別々になっていた。

コードを比較してみると ..

  • 初期化の電圧設定 と ガンマ曲線の設定のみが違う。
     - 違うパネルのデータを使っても 表示だけはできそう。
  • ついでに ILI9326AN を見てみると、ILI9325 と手順はほぼ同じものの、レジスタのアドレスと値が違う。各パネルの違いは、ILI9325 と同じような感じ。

とりあえず、アプリケーションノートにあるコードを元にして picfun のコードを参考に プログラムを作成しようと思う。


ちょっといくつか ILI93xx の コマンドリファレンスを 切りだして 画像にしてみた。描画エリアと 描画方向を指定して データを連続で送る ... ということは出来ると思うのだが .. コマンド体系は同じように見えるが、それぞれコマンド自体は違うようだ。


    picfun のコード(ILI9325)だと、
    ST7785 での、2Ah(CASET), 2Bh(RASET), 2Ch(RAMWR)がそれぞれ
  • 0x20 : Horizontal GRAM Address Set
  • 0x21 : Vertical GRAM Address Set
  • 0x22 : Write DATA to GRAM
    に相当している。
    ILI9326/ILI9328 も同じだが、ILI9327 は、2A/2B/2C で ST7785 と同じ。

これだけで描画するというのもひとつの手だ。ただのテストなのだから 凝ったことをする必要はない。

GPIO のアクセス方法

    bit 単位の set/clear 関数はマクロにあるのだが、まとめてアクセスする関数は定義されていない。どのようにアクセスするものなのかまずはチェック

    • GPIO 関係の レジスタは、3 つ 1組みになっている。Read-only の xxx というレジスタに対して、Write-only の xxxS/xxxC というレジスタがある。機能は、該当ビットを 1 にする (xxxS) / 0 にする (xxxC)。-- 以下 xxxS/xxxC については省略して説明。
       - 複数bit の 値を 1 オペレーションで設定することはできない。
    • xxx は PAyy,PByy,PCyy .. とネーミングされているが、マクロは PXyy となっていて統一的に扱う。以下の説明でも PXyy を使う。
    • PXIN -- 入力に設定されたとき ピンの値が読める。
    • PXDAT -- 出力に設定されたときの GPIO の値。
    • PXFUN / PXSEL -- この 2 つで GPIO として使う設定になる。0/0 が GPIO 。
    • PXDIR -- GPIO の方向。1 で 出力。
    • PXPE -- pull-up または pull-down (PIN によって決まっている) の設定。0 で pull-up/pull-down。

      まとめ
    • 出力設定 PXFUN = 0 , PXSEL = 0 , PXDIR = 1
    • 入力設定 PXFUN = 0 , PXSEL = 0 , PXDIR = 0
    • 出力 H: PXDAT = 1 / L PXDAT = 0


delay について

    コードには、delayms など ms 単位での待ちをいれている。これをちゃんと実装しないと、まずそうだ。
    また、GPIO のアクセスで WR のパルス幅をコントロールしないといけない。適当に作ると 早すぎて コントローラの条件を満たさないかも知れない。

      USBBOOT では 228 MHz が デフォルトになっている。1 clock 4ns ぐらい。

    Linux のコードを参考にして、__delay(loops) と mdelay(ms) を作ろうと思う。具体的には、

      #define CPUCLOCK 228000000

      static inline void __delay(unsigned int loops)
      {
      __asm__ __volatile__ (
      " .set noreorder \n"
      " .align 3 \n"
      "1: bnez %0, 1b \n"
      " subu %0, 1 \n"
      " .set reorder \n"
      : "=r" (loops)
      : "0" (loops));
      }

      static inline void mdelay(unsigned int ms)
      {
      int i;
      for (i=0; i<ms; i++) {
      __delay(CPUCLOCK / 2000);
      }
      }

    これ。__delay の 1 loop は 2clock のようだ。




A-41 の LCD に表示できた。

  • WK11: usbboot-wk11.tar.gz

  • 16bit の ILI9325 用のコードで画面クリアが出来た。
     - 青、緑、赤で 全面の塗りつぶしも OK で、予想通り R5G6B5。

  • ただし、最初は安定しなかった。時々画面が白のままになる。
     - delay を増やすことで、正しくクリアできるようにはなった。

      タイミングのチェック:
    • CS/RS/データの確定後 10ns 待って WR を ↓。
    • 50ns 以上(500ns 以下)待って WR を ↑
    • 40ns 以上待って 次のステップ。

     - 追記: ILI_93XX_Reset() が適当だったので安定しないことがわかった。
      普通に clear/set するようにしたら 安定した。

  • フォントの描画コードも入れている。
     - 表示はできているが、現状は色がおかしい。
      → バグがわかった。
     - デバッグに利用できるのももうすぐ。
      → スクロール機能が必須。
  • ILI9326 用のコードも作ったので、A-33 でもやってみたいが、予備が届くまでおあづけかな。
     - バッテリー充電機能が不明なので、いちいちバッテリーを外している。これが面倒。
     - だが使えることを確認して安心したい。

A-33 も動いた。

  • WK12: usbboot-wk12.tar.gz

    結局、制御できるかどうか安心したくて、やってみることにした。

  • ILI9326 16bit インターフェイス用のコードが動くことが確認できた。初期化のコードは、アプリケーションノートから取ってきたものだが、他は、ILI9325 用のコードをベースに レジスタ番号を ILI9326 に合わせただけ。あっさり動作した。

  • 画面サイズは、横 240 x 縦 432 だった。(A-41 は 横 240 x 縦 320)

    これで一安心。

    Linux 移植でのデバッグでも 情報を画面に 残せるようなる。これをベースにして jz_ubcomm ドライバ に組み込む予定。(正規の SLCD ドライバは別途考える)

      A-41 から I2Cを引き出して LED を点灯できるようになったのだが、ほとんど使わないうちに いらなくなりそうだ。

      Neo Slim 3000 の方は、Smart LCD 接続でなく RGB インターフェイス。こうなると、A-41/A-33 で進めたほうが 良さそうだ。

      ところで、予備を everbuying で 2 つ 買っているのだが、売り切れで 1 つしか入手できないという連絡があった。結局差額を支払って A-32 にチェンジ。A-33 とだいたい同じ兄弟機のはずだし、中を見たいし、A-33 ほど安っぽくはないし .. まぁいいか。

    これで LCD制御はひとまず完了。

    • Linux で主に使うのは、フレームバッファの転送だけなので 凝った機能を使わない。SleepMode に入る/出る という機能もあるが、アプリケーションノートそのままだし。

    • いずれ P5-5 にも 手を付けると思うが、先のはなし。

    おまけ: ILI9325 メモ

    • R03h : Entry Mode
       (9326 では、R03h = R003h)

      D15/D14 : TRI/DFM = 00 → 65K mode
      D12 : BGR = 1 → swap R and R (??)
      D5/D4 : I/D = 11 → incliment/decliment:
                      V inc , H inc
      D3 : AM = 0 → update direction = Horizontal

      例:
      ILI93XX_CtrlWrite(0x03, 0x1030);


      TRI/DFM の設定で、16bit モードでも 256K Color の書き込みができる。ただし、2 回の書き込みが必要。(8bit モードでは、3回)

      BGR=1 と下記の REV=1 で、RGB データを逆順にできる。何故か逆順が 普通に R5G6B5 としてアクセスできる設定。

      重要なのが、I/D と AM 。データを書き込む方向を指定するもので、これを使えば画面を回転させられる。

    • R61h : Gate Scan Control
       (9326 では、R61h = R401h,R6Ah = R404h)

      D2 : NDL = 0 → Non-Display Area = black ?
      D1 : VLE = 0 → virtial scrolling = disabled
      D0 : REV = 1 → change endian

      例:
      ILI93XX_CtrlWrite(0x61, 0x0003);
      ILI93XX_CtrlWrite(0x6A, vscroll_base);


      NDL は、表示外エリアが白か黒かを指定するもの。
      REV は、それぞれ R,G,B の MSB の指定。

      VLE は、縦スクロールの許可。これを使えば長辺方向にスクロールできる。Linux の本来のドライバは、フレームバッファから転送するので必要ないが、デバッグでコンソールもどきにするとき欲しい機能。

      とりあえず Pixel 描画以外に、これだけ知っているだけで十分使える。

      あとガンマ曲線の設定を理解できれば、好みの色調に出来て嬉しいかも。

      それ以外で気になるのは...

    • R2BHh : Frame Rate
       (9326 では、R20Bh だが値の意味が違う)

      デフォルト 96 Hz だが、40 Hz まで落とせる。(9326 では、デフォルト 80 Hz / 最小 30 Hz)

      ひょっとして、フレームレートを下げると液晶本体の消費電力もかなり減ったりしないのだろうか? 一度調査してみたい。

    ちょっと修正。

    • WK13: usbboot-wk13.tar.gz

      上記の RESET の操作を修正。
      あと、exec コマンドを追加。0x80600000 にロードして go する簡易コマンド。

      まだ動いていないが、MinGW で動くように気がついたらコードを修正している。
posted by すz at 23:53| Comment(0) | TrackBack(0) | Jz47xx(USBBOOT)