2012年06月17日

MCPU -- A Minimal 8 Bit CPU

MCPU -- A Minimal 8 Bit CPU in a 32 Macrocell CPLD

    というのを思い出した。これは、CPLD で実装できる 極端にシンプルな 8bit CPU 。

    実際に CPLD に実装しても メモリを別に用意しなくてはならない 。FPGA だとメモリがあるのが普通なので、全部を実装可能だ。でも、どうせならもっと規模が大きい CPU を実装したい ... ということで今までは興味がなかった。

    128スライスしかない MachXO2-256 ならどうだろう? メモリを載せて実装できるのだろうか? 試してみたくなった。

    まずは、資料の入手から。"MCPU - A Minimal 8 Bit CPU in a 32 Macrocell CPLD" でググると PDF ファイルがヒットする。まずは、これを入手。

  • http://opencores.org/project,mcpu

    どうも プロジェクトホームページは、ここらしい。アクセスできる人は、ここから入手するのが良さそうだ。

MCPU の概要

    ドキュメントを読むと 命令は なんと 4 つしかない。

    そんなものでプログラムを組めるのだろうか? という疑問にマクロを示すことで答えている。

      .. 確かにプログラムを書けそうな気はする。

    ソースコードは、VHDL版、Verilog 版が、ドキュメントの最後に添付されている。

      私は、VHDL版だけ見て、自己流の Verilog 版を作ることにした。... というより Verilog 版があるのを知らないで作ってしまった。まぁ、後でいじるつもりだし著作権的には自己流の方が都合が良いかも知れない。

      -- 著作権は、アイディア(ロジック)を保護するものではなく、表現を保護するもの。言語が違うから、表現も違う。オリジナルは尊重すべきだが、どうもこういうことらしい。

      verilog 版をよく見たらバグがあるようだ。要注意。

最初のインプリメント

    さて ... 規模をまずは見たい。メモリを付けて合成してみよう。

    メモリ空間は、なんと 6bit 64バイト分しかない。初期値付きの RAM として合成してみたら 59/128 スライス しか消費しなかった。

      module sram # (
      parameter SIZE = 64
      ) (
      input CLK,
      input WEB,
      input [5:0] ADDRB,
      input [7:0] DIB,
      output [7:0] DOB
      );
      reg [7:0] mem [0:SIZE-1];

      reg [7:0] r_addr;
      always @(negedge CLK)
      begin
      if (WEB) mem[ADDRB] <= DIB;
      r_addr <= ADDRB;
      end
      assign DOB = mem[r_addr];

      initial
      begin
      $readmemh("rom_data.mem" , mem, 0 , SIZE-1);
      end
      endmodule


    つけた RAMは、こういうもの。negedge で駆動。アドレスラッチ付き。

構想

    まずアドレス空間が狭すぎる。ハーバードアーキテクチャにしよう。これで RAM 専用空間に 64 バイト割り当てられる。

    で、何をしたいかと言うと I2C やらタイマがある EFB を割り当てたい ... ただ EFB の空間は 256 バイトもある。

EFB の調査

    MachXO2 和訳テクニカルノート にある
     
  • TN1205 ユーザフラッシュメモリ(UFM)と組み込み機能ブロック(EFB)の使用ガイド
    を見てみよう。

    まずは、アドレスマップ

     プライマリI2C   0x40 〜 0x49
     セカンダリI2C  0x4A 〜 0x53
     SPI       0x54 〜 0x5D
     タイマ/カウンタ  0x5E 〜 0x6F

    一応 64 バイト以内に収まっている。0x70 〜 0x7f の 16 バイトも空いている。あと、使わない機能のレジスタは RAM としても使えるはず。

    独自の I/O ポートを付けたいなら どこかを削らなければならない。これは、後で考えよう。

    次に EFB との接続インターフェイス。

    EFB は、WISHBONE インターフェイス。この説明は、TN1205 に載っている。

  • wb_clk_i posedge で動作
  • wb_rst_i active high の同期動作
  • wb_adr_i {2'b01, adreg}
  • wb_dat_i EFB の入力
  • wb_dat_o EFB の出力
  • wb_we_i 1 で Write だが レベルセンシティブ
  • wb_stb_i 1 で EFB を選択 ( adreg[5:4] != 2'b11 )
  • wb_cyc_i 1 でバス有効?
  • wb_ack_o

    こんな感じだが、ライトもリードも 最低3サイクル必要と書いてある。

    WISHBONE 用のクロックをまず生成し、それを3分周してマスタクロックにすることにしよう。

MCPU の拡張 (1) ハーバードアーキテクチャ

    これは、実はすごく簡単。(元が簡単だし)

    メモリから READ しているもの のいくつかを プログラムメモリに変えれば良い。
     
  • adreg にロードしている所
     
  • 上位 2bit だけをロードしている所

MCPU の拡張 (2) アドレス空間の拡張

    ハーバードアーキテクチャ に変更しても プログラムメモリは、64B しかない。MachXO2-256 は、128B までいけるはずなのだ。もう少し増やせないか?

    空間を増やすためには、プログラムメモリのビット幅を増やせば良い。分散メモリの場合、使わない bit は 最適化で消えるから、気前よく 12 bit にしてしまおう。

    で、アドレス空間自体は、7bit にする。これで規模がどうなるか。

    Number of Inst. 64(org) 64 96 128
    Design Summary
    Number of registers: 32 34
    Number of SLICEs: 51 92 107 124
    SLICEs(logic/ROM): 32 32
    SLICEs(logic/ROM/RAM): 19 60 75 92
    As RAM: 6 24
    As Logic/ROM: 13 36 51 68
    Number of logic LUT4s: 77 126 156 188
    Number of distributed RAM: 6 24
    Number of ripple logic: 5 5
    Total number of LUT4s: 99 184 214 246

    分散メモリは、ROM に格納するデータによって規模が変わる。64B 分しか使わないなら 128B 全部使うのと比べ 32 スライスも減った。

    同じ 64B でも ハーバードアーキテクチャ版から随分増えた。これは、メモリ(RAM) を 16B から 64B に増やしたのが主な理由。-- メモリが 16B しか使えないという制限で良いなら、変に拡張しないほうが良い。

      ちなみに、オリジナルは 57 スライスで、ハーバードアーキテクチャ版は規模が減っている。

      メモリは、RAM 64B だったのが、ROM 64B + RAM 16B になったわけだ。2 種類に増えた上、トータルの容量も増えた。さらに EFB まで付けて 減ったわけだ。

      オリジナルは、ハーバードアーキテクチャ版を元に書きなおした。分散メモリの RAM実装が 重いということになるのだろう。

アドレスマップ と I/O ポート

    何種類か設計したわけだが、アドレスマップを整理して I/O ポートをどうしたら良いのか考えてみよう。


    オリジナル EFB版 MCPU EFB + アドレス拡張
    0x00 - 0x2F : プログラム EFB EFB
    0x30 : 0xFF (allone) 0xFF (allone) 0xFF (allone)
    0x31 : 0x00 (zero) 0x00 (zero) 0x00 (zero)
    0x32 : 0x01 (one) 0x01 (one) 0x01 (one)

    0x34 - 0x3F : RAM RAM
    0x40 - 0x7F : --- ---  拡張RAM

    プログラムROM : ---- 64B 64B - 128B

    マクロを見ると 0xFF,0x00,0x01 がメモリ上に必要なのだ。そして書き換えられるのは都合が悪い。アドレスは、EFB 版とアドレスを合わせることにすると 0x30 〜の 3 バイトが良さそうだ。

    実際に付けるかどうかは、別にして ... 出力ポートは、0x30 - 0x32 の 3バイトを割り当てることにする。入力ポートは 0x33 の 1 バイトのみ ということにしたらどうだろう。

ソースコード

  • qfn32samples-04.zip

      バグなど
    • mcpu.v , mcpu_efb.v , mcpu2_efb.v の sram モジュールで WEB の論理が逆になっていた。


追記: シミュレータ(iVerilog) でデバッグ

    iVerilog を使ってデバッグした。いろいろ修正したが、どうやら動かせるようになったようだ。

    動かせたのは、EFB を組み込んだりした拡張版。オリジナルに一番近いのは、まだ。

    テストコードは、PDF に載っていたサンプルコード。どうも 最大公約数をもとめるものらしい。あと、アセンブラもどきを perl スクリプトで組んだりもしている。

    作った MCPU のバージョンは4つある。

      (1) mcpu.v オリジナルをもとに作ったもの
      (2) mcpu_efb.v ハーバードアーキテクチャ版 にした上で EFB を組み込んだもの。
      (3) mcpu1_efb.v 拡張しやすいように、rewrite したもの。
      (4) mcpu2_efb.v アドレス空間を拡張したもの。

    (1) だけ動いていない。

    アセンブラもどきは、後方参照した場合、アドレスが分からないというレベルのもので、出力を参考にしてコードを転記している。

    規模は、(3) が、53スライス、(4) が 103 スライス。EFB を組み込んだ上で、adreg, O_DATA などをピンに出力している。(4) は、LDI 命令を追加しての規模で、なしにすると 92。なにか使い物になりそうな気もしてきたのだが ...

    よくよく考えると bit 操作すらできない代物だった。(3) は随分余裕があるようなので、これを元に ALU を付けたCPUを設計したほう方が実用的だろう。

    あと RAM のアクセスの仕方に難がある。分散メモリ専用ならこれでも良いのだが、今はブロックRAM を使えない。一方 ROM の方は問題ないようだ。

    (3) について、ちょっとメモっておこう。


    ADD 命令 + STA 命令
    _______ _______ _______
    CLK ______| |_______| |_______| |______|

    code_data 01AAAAAA | 01BBBBBB |

    inst 000 | 101 | 000 | 110
    ______________
    WE _______________________________________| |__

    @
    (RAM_USE_CLK)
    ______________
    WE_mem ______________________________| |__
    @ @ @ @

    分かりにくいと思うが、2 クロックで 1 命令実行 。posedge で CPU は動作している。最初の状態は、000 で アドレスだけは確定している。

    code_data は ROM 出力で negedge で変化する。アドレスは、ラッチを持たず ROM データをそのまま使っている。

    で、ROM データは、毎クロック読み出しているが、inst==0 の時だけの方が良いかも知れない。

    問題の RAM は、WE の立ち上がりで書き込みとしていた。一般的なコードにするとすれば ...

    posedge で動作させることにして、WE = 1 で書き込み。ただし WE は半クロック前に確定させないといけない。

    実際にやってみたら動いたのだが、規模は +7 スライスの増加。

     ・ qfn32samples-05.zip

新たな CPU へ

    mcpu2 では、命令用メモリを 12bit にした。そのうち 下位 7bit はアドレス。命令用に 5bit 使えるわけだが今は 2bit しか使っていない。ここを再構成し、ALU を入れることによって 別の CPU にしたい。

    といっても基本は変えない。演算する、ストアする、条件ジャンプするという枠組みは出来ているのだ。枠組みを壊さなければ、書きなおすところが圧倒的に減る。

    改造の要点

      10 : STA -- 変更しない。
      00 : NOR -- 演算命令 8 つ に変更

      使う ALU は、自作AVRコア用 ALU 。ちょうど 8bit だし、都合が良い。
      00XXX -- 3bit 使えるが まるまる ALU の S に使う。

      01 : ADD -- 即値演算命令 4 つに変更

      即値演算にも ALU を使う。ただし、論理演算のみ。

      01XX -- 即値は、2bitしか使えないのだ。命令の割り当ては、演算命令との兼ね合いで決める。

       即値は、01 S[1] S[0] 8bit即値 (S[2] = 1) とすることにしよう。
       演算は、00 S[1] S[0] S[2] 7bitアドレス

      11 : JCC -- 条件を拡張+α

      条件ジャンプ命令は、3bit 使える。C or Z で 1bit ,条件を逆にするのに 1bit 。あと 1bit は、C の値としておこう。 C をロードする命令がないのだ。

    動くかどうか分からないのだが、ROM 64 words , RAM 16 bytes なら 97 スライスに収まった。これならいけそう。

    命令表

      (inst == 100)
      00 00 0 ADD
      00 01 0 ADC (with carry)
      00 10 0 SUB
      00 11 0 SBC (with carry)
      00 00 1 AND
      00 01 1 XOR
      00 10 1 OR
      00 11 1 LD

      (inst == 101)
      01 00 ANDI
      01 01 XORI
      01 10 ORI
      01 11 LDI

      (inst == 110)
      10 XX X ST

      (inst == 111)
      11 00 C JCS jump if carry set
      11 01 C JCC jump if carry clear
      11 10 C JNE jump if zero-flag set
      11 11 C JEQ jump if zero-flag clear

      carry,zero-flag が変化するのは、ADD などの 算術演算命令のみ。

    全部で 17 命令。... だがコード上は 4 種類のまま。ALU が何をしているか関知してないから。

    シフト命令は .. ないなぁ。
    これを付けるとすれば ... 001 〜 011 の inst を使うことになる。

      (inst == 100)
      10 00 STA
      (inst == 001)
      10 01 拡張命令 1
      (inst == 010)
      10 10 拡張命令 2
      (inst == 011)
      10 11 拡張命令 3

    どんな命令にするか別にして、こういう割り当てにする。

    だいたい作った上で動作周波数を見てみた。4 グレードで 20 MHz 〜 25 MHz ぐらい。クロックは、EFB を操作する都合で 3 倍クロックを入力している。命令実行は 2 クロックに 1 回なので 1/6 ... 4 MIPS ぐらい?

    多分なにか間違っている。制約の設定が足りないのだろう。だが、EFB のクロック関係は適当すぎたかも。

    EFB を外して CLK で駆動したら 22.9 MHz になった。これでも 違うはずだが、この 2 倍は無理だろう。
    改造前の mcpu2 だと 45.5MHz と出た。ALU 周りがボトルネックと見做されたわけだ。だが、1.5 クロックかけて演算している。これを 0.5 クロックと見られたら 低い結果になりそう。

      どうも、MULTICYCLE制約というので設定するらしいので試してみた。

      FREQUENCY PORT "CLK" 36.000000 MHz ;
      MULTICYCLE TO CELL "alu_impl_I/alu_impl/alu_lo/akku_i0" 1.500000 X ;
      MULTICYCLE TO CELL "alu_impl_I/alu_impl/alu_lo/akku_i1" 1.500000 X ;
      MULTICYCLE TO CELL "alu_impl_I/alu_impl/alu_lo/akku_i2" 1.500000 X ;
      MULTICYCLE TO CELL "alu_impl_I/alu_impl/alu_lo/akku_i3" 1.500000 X ;
      MULTICYCLE TO CELL "alu_impl_I/alu_impl/alu_hi/akku_i4" 1.500000 X ;
      MULTICYCLE TO CELL "alu_impl_I/alu_impl/alu_hi/akku_i5" 1.500000 X ;
      MULTICYCLE TO CELL "alu_impl_I/alu_impl/alu_hi/akku_i6" 1.500000 X ;
      MULTICYCLE TO CELL "alu_impl_I/alu_impl/alu_hi/akku_i7" 1.500000 X ;
      MULTICYCLE TO CELL "C_68" 1.500000 X ;
      MULTICYCLE TO CELL "Z_69" 1.500000 X ;

      ... と 22.9 MHz が 57.0 MHz まで上がった。 いくらなんでも 上がりすぎのような ...

      FREQUENCY PORT "CLK" 36.000000 MHz ;
      DEFINE CELL GROUP "akku" "alu_impl_I/alu_impl/alu_hi/akku_i7"
      "alu_impl_I/alu_impl/alu_lo/akku_i1"
      "alu_impl_I/alu_impl/alu_lo/akku_i2"
      "alu_impl_I/alu_impl/alu_lo/akku_i3"
      "alu_impl_I/alu_impl/alu_lo/akku_i0"
      "alu_impl_I/alu_impl/alu_hi/akku_i6"
      "alu_impl_I/alu_impl/alu_hi/akku_i4"
      "alu_impl_I/alu_impl/alu_hi/akku_i5"
      "Z_69"
      "C_68" ;
      DEFINE CELL GROUP "code" "rom_impl/r_addr__i5"
      "rom_impl/r_addr__i4"
      "rom_impl/r_addr__i3"
      "rom_impl/r_addr__i2"
      "rom_impl/r_addr__i6"
      "rom_impl/r_addr__i1" ;
      MULTICYCLE FROM GROUP "code" TO GROUP "akku" 1.500000 X ;

      よく分かってないのだが、GROUP というのを定義して、その間を設定するやり方もある。指定したいのは、こっちのような気がする。基本的に rom の アドレスが変わることによって 結果が出るのだ。これだと 37.6 MHz ...

      mcpu2 だと 45.5MHz が 63.0 MHz に。

追記

    mcp3 の 命令の仕様を決めて、簡易アセンブラを 作った。ちょっと改良して後方参照も 見るようにした。やはり、ないとデバッグが不便。あと 出力ポート追加。

      MCPU3 命令表(全 21 命令)

      (inst == 100)
      00 00 0 ADD
      00 01 0 ADC (with carry)
      00 10 0 SUB
      00 11 0 SBC (with carry)
      00 00 1 AND
      00 01 1 XOR
      00 10 1 OR
      00 11 1 LD

      (inst == 101)
      01 00 ANDI
      01 01 XORI
      01 10 ORI
      01 11 LDI

      (inst == 110)
      10 00 X ST
      (inst == 001)
      10 01 ASR
      (inst == 010)
      10 10 ROL
      (inst == 011)
      10 11 ROR
      (inst == 111)
      11 00 C JCS jump if carry set
      11 01 C JCC jump if carry clear
      11 10 C JNE jump if zero-flag set
      11 11 C JEQ jump if zero-flag clear

      (MACRO)
      SEC set carry JCS *+1 (C=1)
      CLC clear carry JCC *+1 (C=0)
      JMP addr JCC adr (C=0), JCC adr (C=0)
       ・carry が変化するのは、ADD などの 算術演算命令
        と JCC 等のブランチ命令, シフト命令
       ・zero-flag は、論理演算やロード LD,LDI でも変化

    これで コードは作れるようになった。最初に作ったのは、MCPU のサンプルの GCD の移植。単純変換したら、1命令しか減らなかった。

    さて、次は EFB にアクセスしてみたい ... のだが、ちょっと出来が悪かったので再考。

      ・ まず 3 倍速というのがダメ。CPU の CLK が 2:1 になり ボトルネックになる。2 倍速にする。
      ・ 2 倍速 を検討したのだが、CPU は、ちょうど 2 クロック毎の処理になっている。
      ・ ROM を非同期アクセスに変更すると具合が良いことが分かった。

      READ サイクル
      _____ _____
      CLK | |_____| |_____|

      inst | 000 | 100 |
      ____________
      wb_cyc ______| |_____
      @ @
      ADDR DATA @
      ラッチ 実行
      WRITE サイクル

      _____ _____
      CLK | |_____| |_____|

      inst | 000 | 110 |
      _______________________
      wb_we | |_
      ____________
      wb_cyc ______| |_____
      @
      ADDR
      DATA

      READ/WRITE サイクルを図示するとこんな感じ。
      READ では、wb_cyc=1 と同時に アドレスが決まってないといけない。アドレスは、命令に含まれ、CLK 立ち上がりで読み込み開始。次の CLK_2X で データを読み込めるが、ここでラッチしないといけない。

      WRITE は、命令を読みこめばただちに分かる。DATA も用意しなければならないが、akku(アキュームレータ)を WRITE するだけなので、命令と同じタイミングで読める。

    あと、制約を書くのに C_68 とか変なサフィックスになるので、reg [1:0] flags に変更。

    だいぶ仕上がって来た。いままで作ってきたサンプルは、MachXO2-256 をターゲットにしている。当然 『MachXO2 breakout ボード』でも 動くはず。EFB アクセスはこれで確認してみたい。



      シミュレーション結果。赤い不定値部分は、RAM の範囲外ということ。EFB を読み込んでいるわけだ。(演算命令なので、値は使わないが)。 タイミングは上に書いた通りになっている。アクセスする時だけ wb_cyc をアサートしているので、wb_we のタイミングも想定通り。... なのだが、仕様を勘違いしているかも。

      ところで、EFB を使ったときの 最大周波数が低く出てしまう。赤い不定値部分のとなり -- RAM への書き込みをしているが、WE_mem が 1 になって、値が書き込んだときの値に変わっている。どうも ここがボトルネックと解析されているのだが、この値はだれも使わない。from WE_mem を 6X と設定したら CLK_2X が 61.5MHz になった。(命令実行は 1/4 なので 15 MIPS といったところ -- たいしたことはない)。

    あと作っておきたいのは、JTAG 経由の通信 。

関連記事
posted by すz at 10:34| Comment(0) | TrackBack(0) | CPLD

2012年06月13日

FPGA時計の設計

QFN32の FPGA』 を使ったなにかを設計してみたい。この際 AVR 使った方が有利で楽なものでも構わないが、実際に動かせるもの。ALU では、それを使ったものの敷居が高い。

で、時計はどうだろう? プロセッサなしで動かすには一体どうするのか? 実は意外にも簡単なことかも知れない。

構想1

    まず出力。今は 4桁の 7セグが入手できるからそれを使う。時計の : がないが、とりあえずは気にしない。気にする場合は、(配線が面倒になるのと引換に) 2桁の 7セグ x2 で間に LED を 2個入れられるようにして置けば良い。

    この FPGA だが ... DRIVE 能力の設定がある。LVCMOS33 だと デフォルト 8mA 、最大では 24mA の設定ができる。ただ、24 mA 流せてもコモンは 7 倍になるから 足りない。ドライバは必須。カソードコモンだと NPN トランジスタ が使えて楽そうな気もするのだが、7セグ側を H にして点灯させないといけない。そうなると白色 LED を使うのは厳しくなる。

    一応アノードコモンを使い 7セグ側を L で点灯ということにしておきたい。コモンのドライブも L 。こういったものは、出来た後見直すことにしよう。

    ピン数の合計 7 + 4 + 1(2) = 12(13)

      使える I/O は 21 しかない。ちゃんと入るものなのかどうか、常に気にするようにしよう。

    次にクロック。ダイナミック点灯や ボタンでのオペレーションを考えて 128 Hz を基本としておこう。 8MHz なら 128 で割り切れる。32768 Hz を原発信にしたい気もする。これは、あくまで最初の想定。出来上がってしまえば、対応できる範囲というのも分かってくるだろう。

    さて、これはどうやって入力するか -- 。取り敢えずは、外部のオシレータを想定すれば良い。ただ、水晶発振回路を内蔵したい。ピン数は、2 と見積もっておく。

    ピン数の合計 14(15)

    入力。時刻の設定は出来ないと困るだろう。最も簡単なのは、SEL と UP の 2 つ。DOWN も付けると、よくある時計のオペレーションになるはず。一応 3 つと見積もる。

    ピン数の合計 17(18) --- 残り 4(3)

    あと最大 4 つしか余らない。まぁ機能など付ける余裕もなさそう。JTAG はできれば空けときたいので、4 つ余らせることにしよう。

構想2 カウンタと表示

    ここからは、内部をどうするか ...

    まず時計というからにはカウンタが必要だ。それをどういう風に設計するか?

    前提としてダイナミック点灯するわけだ。ならば、出力は 4bitの BCD 1つで良い。これを 7seg エンコーダを通して 表示させるわけだ。

    考えたのだが、0〜59 や 0〜24 の 2 桁カウンタのモジュールをまず作ろうと思う。最大値は モジュールのパラメータで指定。あと 出力は 4bit で HI/LO を切り替える SEL 入力を持つことにする。

    入力は、128Hz のクロック と カウンタ動作の指定 UP(/DOWN)。あと上位に対する UP(/DOWN)。まずは、DOWN は後回し。回路が入るようなら検討。

    7seg エンコーダは、分散メモリを使ったテーブル ... にしたかったのだが Lattice の場合、妙な Warning が出るので assign と ? 演算子だけで何とかしようかと思う。(テーブルと同じ効果になるはず)。

構想3 カウンタと表示(続き)

    上のカウンタモジュールを 3 つ使い 時分秒に割り当てる。出力も 3 つ。とりあえず、時分 と 分秒 を表示する 2 つのモードを作ろう。

    セレクタでのこの 3 つの出力を切り替えられるようにして、モジュール内の HI/LO を切り替え を合わせてダイナミック点灯させる。

      ダイナミック点灯の 2bitカウンタがあるとする。下位は HI/LO に割り当てる。上位だけ考えれば良いのだ。

      0 1
      disp_mode 0 HH MM
      disp_mode 1 MM SS

      こうなるようにすれば良い。

    さて、これだけか? というと違う。時刻の設定である。時刻の設定ではセレクトされたものがブリンクする。設定モードについて考えておこう。

    モード自体の定義は、次のようにしよう。

      set_mode 0 : 通常表示 (HH:MM)
      set_mode 1 : 時設定 (HH:MM) で HH ブリンク
      set_mode 2 : 分設定 (HH:MM) で MM ブリンク
      set_mode 3 : 秒設定 (MM:SS) で SS ブリンク

      blink off blink on
      0 1 0 1
      set_mode 0 : HH MM HH MM
      set_mode 1 : HH MM -- MM
      set_mode 2 : HH MM HH --
      set_mode 3 : MM SS MM --

      ( -- : blank )

    だいぶややこしくなってきた。が、所詮これだけ。全部で 16 通りしかない。あと blink 信号は、クロックから 1Hz を取り出せば良い。

構想4 ボタン

    次は、どうやってボタンから入力をするかに飛ぼう。

    例えば、SELボタンを押したときは、set_mode をインクリメントするだけで良い。だが、どうやって押したと認識するのか? スイッチの入力をそのまま入れたのでは、128 Hz で set_mode が回転するだけだ。また、チャタリング対策というものも必要になる。

      (128 Hz で次の処理を行う)
      N 回 同じ入力が続いたら ボタンが押された、離されたと認識する。
      押された、離された という状態を作り、離された→押された と変化したとき ボタンON。
      使う側が、ボタンONを認識して リセット を送ってきたら (非同期に)ボタンOFF。

    こういう処理をするボタンモジュールを作ろうと考えている。

    N 回 同じ入力というのは、チャタリング対策。これを を認識するのに N -1 bit の レジスタが必要。N=4 にしたいなら、 128 Hzは、周波数が高すぎるかも知れない。これは、後で要調整。
 
実装編 カウンタ

    以上で重要な部分は説明した。後は実際のコードを示していこう。

    module clock_counter # (
    // parameter MAX = 60
    parameter MAX = 24
    ) (
    input CLK
    , input I_UP
    , input SEL // select output
    , output [3:0] O
    , output O_UP
    );

    reg [3:0] lower;
    reg [3:0] upper;
    reg r_ovr;

    assign O[3:0] = SEL ? lower[3:0] : upper[3:0];
    assign O_UP = r_ovr;

    always @(negedge CLK)
    begin
    if (I_UP)
    if ((upper >= (MAX-1)/10) & (lower >= (MAX-1)%10))
    begin
    r_ovr <= 1'b1;
    upper <= 0;
    lower <= 0;
    end
    else if (lower >= 9)
    begin
    r_ovr <= 1'b0;
    upper <= upper + 1;
    lower <= 0;
    end
    else
    begin
    r_ovr <= 1'b0;
    lower <= lower + 1;
    end
    else
    r_ovr <= 1'b0;
    end
    endmodule

    説明したとおりのもの。規模は1つ 10スライスのようだ。3つ使うから、これだけで 30 スライス。

実装編 ボタン

    module button
    (
    input CLK_128HZ
    , input I
    , output O
    , input R
    );

    reg [3:0] i_stat;
    reg prev_stat;
    reg r_out;

    always @(R, negedge CLK_128HZ)
    begin
    i_stat <= { i_stat[2:0] , I } ;
    if ( { i_stat[2:0] , I } == 4'b0000 )
    prev_stat <= 1'b0;
    else if ( { i_stat[2:0] , I } == 4'b1111 )
    prev_stat <= 1'b1;
    if (R) r_out <= 1'b0;
    else if (~prev_stat & ( { i_stat[2:0] , I } == 4'b1111 ))
    r_out <= 1'b1;
    end
    assign O = r_out;
    endmodule

    これもまた説明どおり。これは、4スライス。最低 2 つ使う。

一応完成

  • qfn32samples-03.zip

    Diamond プロジェクト込みのソースを置いておく。iVerilog シミュレータも一応通している。

    // XO2-256 modified ROM/RAM XO2-256
    // 27 B 1 24 VCC
    // 28 G 2 23 DIG1 25
    // 29 3 22 DIG2 23
    // 30 4 21 DIG3 21
    // 32 5 20 DIG4 20
    // 1 6 19 CLK_1HZ 17
    // 4 C 7 18 BTN_DN 16
    // 5 D 8 17 N.C.
    // 8 E 9 16 BTN_UP 14
    // 9 A 10 15 BTN_SEL 13
    // 10 F 11 14 CLK 12
    // GND 12 13 CLK_OUT 11

    ピン配置はとりあえずこうした。DIGは、LVCMOS33 の 24mA に設定。ACTIVE_HIGH に変更して、3mA 程度まで電流を減らせば直接ドライブできるかも。

    機能としては、
  • down ボタンを付けた
  • 7セグ制御の正論理・負論理を切り替えられるようにした。
  • クロックは、128HZ の倍数なら OK なようにした。

    一応説明で言及したものは、入れたことになる。-- これで規模は 86/128 スライス。
    機能追加はなかなか厳しそうだが、アラームクロックにするのは ... 可能かも。time_couner に比較用のレジスタを作って ... まぁ今後の課題にしておこう。

    追記: アラーム機能を付けてみた。

    .. といっても ポートを増やしたくなかったので、秒を示す LED を 1分間 高速点滅させるだけ。機能もちょっと見なおしている。


      set_mode 0 : 通常表示 (HH:MM)
      set_mode 1 : 時設定 (HH:MM) で HH ブリンク (アラーム)
      set_mode 2 : 分設定 (HH:MM) で MM ブリンク (アラーム)
      set_mode 1 : 時設定 (HH:MM) で HH ブリンク
      set_mode 2 : 分設定 (HH:MM) で MM ブリンク
      set_mode 3 : 秒表示 で SS ブリンク

      blink off blink on
      0 1 0 1
      set_mode 0 : HH MM HH MM
      set_mode 1 : HH MM -- MM
      set_mode 2 : HH MM HH --
      set_mode 3 : SS -- (秒表示のみ)

      ( -- : blank )

     ・ qfn32samples-04.zip (ソースコード)

関連記事
posted by すz at 20:03| Comment(0) | TrackBack(0) | CPLD

2012年06月10日

TTL ALU 74181

前の記事『QFN32の FPGA』から派生。

    FPGA MachXO2 の QFN32 パッケージが出るので、DIP にする基板を作ってみたい -- というところから、74HC181 (SN74LS181) の代替ができるものを .. となった。

    この IC は ALU(Arithmetic Logic Unit) で、部品を組み合わせて CPU を作ったりするのに欠かせない。有名な『CPU の創りかた』 でも 74HC181 を使っているとのこと。

    ただ入手がとても難しい。では、DIP にするついでにピン互換機能を持たせられるようにすれば、どうだろう。... 調べてみると、電子工作レベルで、ピン互換にできそうなものはあまりない。

    ならば、やってみようというのが動機。

手始めに コードを作ってみよう。

データシートを見てみる。

    www.alldatasheet.jp で検索してみる。
     
  • *4HC181
     
  • *4LS181

    とりあえず、TI の SN74LS181NE4 を参考書として使うことにする。

    で、見てみたのだが、難解。キャリー入力(Cn) が L と H で計算式が違う。これは面倒だなと思ったのだが、どうも ACtive-Low の表が、そういうことらしく、ACtive-High なら見れなくはない。

    ただ、キャリー出力がどうなるのかサッパリ分からない。結局頼りになるのは、回路図。回路図を読みこなすならば、再現してしまった方が 簡単のような気がしてきた。

      例えば、S == 3 では、キャリーありで F = 0 / キャリーなしで F = -1 と なっているのだが ..

      8bit に拡張した場合のことを考えると、0 を出力したときにキャリー出力が 1 (負論理なので L) にならないと変だ。だが、合っているのか? こういうことを、いちいち 回路図を眺めて確認するのは面倒すぎる。

回路図を元にコードを作る。

    回路図を見ると A/B を入力にして 2 つの出力にしている部分(左)と それを元に F などの出力を生成している部分(右)に分かれるようだ。

    左の出力を C/D という中間出力にして論理式にしてみよう。

    wire [3:0] C;
    wire [3:0] D;

    assign C[0] = ~( A[0] & ~B[0] & S[2] | A[0] & B[0] & S[3] );
    assign C[1] = ~( A[1] & ~B[1] & S[2] | A[1] & B[1] & S[3] );
    assign C[2] = ~( A[2] & ~B[2] & S[2] | A[2] & B[2] & S[3] );
    assign C[3] = ~( A[3] & ~B[3] & S[2] | A[3] & B[3] & S[3] );

    assign D[0] = ~( A[0] | B[0] & S[0] | ~B[0] & S[1] );
    assign D[1] = ~( A[1] | B[1] & S[0] | ~B[1] & S[1] );
    assign D[2] = ~( A[2] | B[2] & S[0] | ~B[2] & S[1] );
    assign D[3] = ~( A[3] | B[3] & S[0] | ~B[3] & S[1] );

    上の部分を C , 下の部分を D とするとこうなった。なんか随分すっきりしている。調子に乗って次。

    assign F[0] = ~( ~M & C_IN ) ^ D[0] ^ C[0];
    assign F[1] = ~( ~M & ( D[0] | C_IN & C[0] )) ^ D[1] ^ C[1];
    assign F[2] = ~( ~M & ( D[1] | D[0] & C[1] | C_IN & C[0] & C[1]))
    ^ D[2] ^ C[2];
    assign F[3] = ~( ~M & ( D[2] | D[1] & C[2] | D[0] & C[1] & C[2]
    | C_IN & C[0] & C[1] & C[2])) ^ D[3] ^ C[3];

    wire Yinv = D[3] | C[3] & ( D[2] | C[2] & ( D[1] | C[1] & D[0]));
    wire C_OUT = Yinv | C[3] & C[2] & C[1] & C[0] & C_IN;
    wire EQ = F[0] & F[1] & F[2] & F[3];

    wire X = ~( C[3] & C[2] & C[1] & C[0] );
    wire G = ~ Yinv;
    wire P = X;

    なにかバグがあるかもしれないが、こんな感じ。

    これを合成してみると ...

    Number of SLICEs: 9 out of 128 (7%)
    SLICEs(logic/ROM): 9 out of 32 (28%)
    SLICEs(logic/ROM/RAM): 0 out of 96 (0%)
    As RAM: 0 out of 96 (0%)
    As Logic/ROM: 0 out of 96 (0%)
    Total number of LUT4s: 17
    Number of PIO sites used: 20 out of 22 (91%)

    なんと 9/128 スライス。楽勝ではないか。P/G は生成していないが、C_OUT(Cn+4) の計算で使っているし、生成しても 僅かの差のはず。

    ただ、17 LUT で作れてしまうものなのだろうか? C/D 生成は、4 入力1出力 が 8 個だから 8LUT で確かにできる。残り 9 個だが .. 配線のために消費しなければ、出来そうな 気もする。

    訂正: F3 の括弧の位置が違った。直したら さらに規模が減った。

    ソースコード (Diamond プロジェクト込み)

     
  • qfn32samples-02.zip (2012/06/12 最新版に更新)
     
  • qfn32samples.zip (ここで説明したもの 旧版)

    ちなみに以前作った 74281 (レジスタ付き ALU = アキュームレータ) P/G なし (上記ソースコードに添付)

    Number of registers: 4
    Number of SLICEs: 39 out of 128 (30%)
    SLICEs(logic/ROM): 32 out of 32 (100%)
    SLICEs(logic/ROM/RAM): 7 out of 96 (7%)
    As RAM: 0 out of 96 (0%)
    As Logic/ROM: 7 out of 96 (7%)
    Total number of LUT4s: 78
    Number of PIO sites used: 20 out of 22 (91%)

    こちらは、高機能だし、最適化された回路図なしだから効率が悪いのかも。それにしても楽勝なのは変わりない。確か 64 マクロセルの XC2C64A(CoolRunner II) にようやく入れられたような 規模だったはずなんだが ...

      追記: これなのだが、後述の 74181 拡張をしてそれをベースにしたら 規模が多少小さくなった。そうであれば自作AVRコアにも適用したくなるし、いずれは 32bit CPU も作りたいので 整理して使いやすくしておこうかと思う。

      自作AVRコアにも適用しても確かに規模は減る。ただ、規模が減れば速くなるものかどうか? あと厳密に機能を作らないといけないのでデバッグが面倒。

検証するには

    規模のチェックは、これぐらいで良いだろう。次はどうやって検証するか。

    C のコードに変換するのは、簡単だ。で、実際にいくつかのパターンを入力して OK そうか見る。大丈夫そうになったら、真理値表を作る。

    確か誰かが全入力の真理値表を作っていたような ... 探してみよう。答え合わせができれば、完了。

    追記: 実際に C 化してみた。

    #define _C(v) (((v)&1)?'1':'0')

    #define wire
    #define assign

    void alu181() {
        (上記の Verilog コード)
    printf("M %c ", _C(M) );
    printf("S = %c%c%c%c ", _C(S[3]), _C(S[2]), _C(S[1]), _C(S[0]) );
    printf("C_IN %c ", _C(C_IN) );
    printf("A = %c%c%c%c ", _C(A[3]), _C(A[2]), _C(A[1]), _C(A[0]) );
    printf("B = %c%c%c%c ", _C(B[3]), _C(B[2]), _C(B[1]), _C(B[0]) );
    printf("F = %c%c%c%c ", _C(F[3]), _C(F[2]), _C(F[1]), _C(F[0]) );
    printf("C_OUT %c", _C(C_OUT) );
    printf("\n");
    }

    こんな風にすると、Verilog のコードを触らなくて済む。

      M 1 S = 0000 C_IN 1 A = 0011 B = 0111 F = 1100 C_OUT 1
      M 0 S = 0000 C_IN 1 A = 0011 B = 0111 F = 0011 C_OUT 1
      M 0 S = 0000 C_IN 0 A = 0011 B = 0111 F = 0100 C_OUT 1

      M 1 S = 0001 C_IN 1 A = 0011 B = 0111 F = 1000 C_OUT 1
      M 0 S = 0001 C_IN 1 A = 0011 B = 0111 F = 0111 C_OUT 1
      M 0 S = 0001 C_IN 0 A = 0011 B = 0111 F = 1000 C_OUT 1

      M 1 S = 0011 C_IN 1 A = 0011 B = 0111 F = 0000 C_OUT 1
      M 0 S = 0011 C_IN 1 A = 0011 B = 0111 F = 1111 C_OUT 1
      M 0 S = 0011 C_IN 0 A = 0011 B = 0111 F = 0000 C_OUT 0

      M 1 S = 0110 C_IN 1 A = 0011 B = 0111 F = 0100 C_OUT 1
      M 0 S = 0110 C_IN 1 A = 0011 B = 0111 F = 1011 C_OUT 1
      M 0 S = 0110 C_IN 0 A = 0011 B = 0111 F = 1100 C_OUT 1

    幾つか試したが、合っているようだ。 (最初は合わなかったので、括弧の間違いが見つかったわけだが)

所感

    実を言うと、MachXO2-1200 とか使っていても もっと規模が欲しい。256 ぐらいで何が出来るのか? と思っていたりしたのだが ... 制限内で何かを作るのも面白いかも知れない。CPLD なんかよりずっと回路が入りそう。それでも複雑なものは作れないから、単機能のものをじっくりやることになる。お手軽に使えるように環境を整えて、いろいろ設計してみようかと思う。

74181 の拡張

    74181 は、ものすごく高機能な印象があったのだが、74281 の ALU や 74381 をこれを元に実装しようとすると機能が足りないことが分かった。

    281 の ALU や 381 では、" B - A " があるのだが、181 では無理なのだ。さらに 281 の ALU では、" ~B - 1" なんてものまである。

    で、どうしようか 作ったのを眺めて考えた。181 では、前段の C,D を作るところだけで、機能セレクトを使っている。ようく見ると A と B は対称ではないが、機能セレクトを追加すれば、対称にできる。

    assign C[0] = ~((~A[0] & S[6] | A[0] & S[7])&(~B[0] & S[2] | B[0] & S[3]));
    assign C[1] = ~((~A[1] & S[6] | A[1] & S[7])&(~B[1] & S[2] | B[1] & S[3]));
    assign C[2] = ~((~A[2] & S[6] | A[2] & S[7])&(~B[2] & S[2] | B[2] & S[3]));
    assign C[3] = ~((~A[3] & S[6] | A[3] & S[7])&(~B[3] & S[2] | B[3] & S[3]));

    assign D[0] = ~( A[0] & S[4] | ~A[0] & S[5] | B[0] & S[0] | ~B[0] & S[1] );
    assign D[1] = ~( A[1] & S[4] | ~A[1] & S[5] | B[1] & S[0] | ~B[1] & S[1] );
    assign D[2] = ~( A[2] & S[4] | ~A[2] & S[5] | B[2] & S[0] | ~B[2] & S[1] );
    assign D[3] = ~( A[3] & S[4] | ~A[3] & S[5] | B[3] & S[0] | ~B[3] & S[1] );

    こうするのだ。S が 4bit から 8bit になってしまうわけだが、使い方は次のようにする。

    S[7:4] S[3:0]
    1 0 0 1 FS[3:0] --- (1)
    FS[3:0] 1 0 0 1 --- (2)

    0 1 1 0 FS[3:0] --- (3)
    FS[3:0] 0 1 1 0 --- (4)

    新設の上位 4bit を 1001 にすると ... 今までと互換(1)。 で、上位ビットと下位ビットを入れ替えると ... A と B が入れ替わる(2)。これは計算式を眺めれば分かるはずだ。

    さらに (1) の 1001 を 0110 にすれば A がビット反転する(~A)。 A と B を入れ替えた上で B をビット反転するには、(4) のようにする。

    これでようやく 281 の ALU や 381 の機能を作れるようになった。

メモ: (ピン)互換モジュールのピンアサイン案

    XO2-256 74181 74181 XO2-256
    27 B0 1 24 VCC
    28 A0 2 23 A1 25
    29 S3 3 22 B1 23
    30 S2 4 21 A2 21
    32 S1 5 20 B2 20
    1 S0 6 19 A3 17
    4 ~Cn 7 18 B3 16
    5 M 8 * 17 N.C. 26
    8 F0 9 16 ~Cn+4 14
    9 F1 10 * 15 SWAP 13
    10 F2 11 14 EQ 12
    GND 12 13 F3 11

    前の記事にも書いたが、実際は有効なピンが足りず互換にできない。P/G は使わないだろうということで、17 は N.C. 扱い。(N.C. とは書いたが無接続にすること)

    15 は、入力 A と B を入れ替える機能にしようかと思う。どうせ回路は余っているのだ。9 スライスが 13 スライスになったが さほどのことはない。

    あ、あたかもモジュールが存在するような書き方をしたが、部品も入手できておらずあくまで予定。

    181 の 機能

    S3 S2 S1 S0 M = 1 C_IN = 1 C_IN = 0
    logic (no carry) (with carry)

    0 0 0 0 ~A A A + 1
    0 0 0 1 ~(A | B)
    0 0 1 0
    0 0 1 1 0 -1 0
    0 1 0 0 ~(A & B)
    0 1 0 1 ~B
    0 1 1 0 A ^ B A - B - 1 A - B
    0 1 1 1
    1 0 0 0 ~A
    1 0 0 1 ~(A ^ B) A + B A + B + 1
    1 0 1 0 B
    1 0 1 1 A & B
    1 1 0 0 1 A + A A + A + 1
    1 1 0 1
    1 1 1 0 A | B
    1 1 1 1 A A - 1 A

    使う可能性があるものをピックアップしてみた。結構スカスカ。SWAP を追加しても M = 1 は結果が同じ。役に立ちそうなのは、B - A , B - 1 , B + 1 ぐらい。

オーバーフラグ(OVR)の 追加

    AVRコアだと H フラグ, V フラグというのがある。H フラグは、4bit のキャリーフラグで 181 ベースでの ALU なら 出力するだけで済む。(自作のコアでは、Verilog の演算をしていたので、別途生成しないといけなかった)

    さて、V フラグは どういうものか ... 現状のものは、次のような式を使っている。

    assign V_out = ~M &
    ( ~(S[1]) & (F[7] & ~A[7] & ~B[7] | ~F[7] & A[7] & B[7])
    | (S[1]) & (F[7] & ~A[7] & B[7] | ~F[7] & A[7] & ~B[7]) )
    ;

    M=1 が論理演算で、~(S[1]) は、算術加算。 で S[1] が算術減算。... 要するに A/B/F の最上位ビットを 比べているわけだが、加算/減算で論理が違う。

    一方 74LS382 (381 のモディファイ版) には、OVR という出力があって、こんな計算はしていない。よくわからなかったのだが、どうも C_OUT(n) ^ C_OUT(n-1) という計算をしているようだ。

    C_OUT(n) は、既にあるわけだが、181 は内部で C_OUT(n-1) も作っているはず。そうであれば、比較的簡単に OVR を作れるのではないか?

    wire C_OUT1 = ~( D[0] | ~C_IN & C[0]);
    wire C_OUT2 = ~( D[1] | C[1] & D[0] | ~C_IN & C[0] & C[1]);
    wire C_OUT3 = ~( D[2] | C[2] & ( D[1] | C[1] & D[0])
    | ~C_IN & C[0] & C[1] & C[2]);

    assign P = ~( C[3] & C[2] & C[1] & C[0] );
    assign G = ~(D[3] | C[3] & ( D[2] | C[2] & ( D[1] | C[1] & D[0])));
    assign C_OUT = ~(~G | ~C_IN & C[0] & C[1] & C[2] & C[3]);

    assign F[0] = ~( ~M & ~C_IN ) ^ D[0] ^ C[0];
    assign F[1] = ~( ~M & ~C_OUT1 ) ^ D[1] ^ C[1];
    assign F[2] = ~( ~M & ~C_OUT2 ) ^ D[2] ^ C[2];
    assign F[3] = ~( ~M & ~C_OUT3 ) ^ D[3] ^ C[3];

    assign OVR = ~M & (C_OUT3 ^ C_OUT);
    assign EQ = F[0] & F[1] & F[2] & F[3];

    どうもこうらしい。これで、たいぶすっきりした。

    で、この修正を入れたら、15 スライスにまで増えた。( ただし 使わなければ 元と同じ )

8bit への拡張

    この alu を 2 つ使って 8bit 版を作ってみている。C_OUT と 上位 4bit の C_IN をつないだもの。

    35 スライス / 68 LUT になった。だいぶでかくなった。

    P/G の生成は、

    assign P = PL | PH;
    assign G = GH & (PH & GL );

    こんな風にやるものらしい。PH , GH を出力すれば良いものではないようだ。8bit 版単体で使うなら関係ないのだが、いずれは、32bit CPU を作りたいので対応しておいた。また、8bit 版 になるとピンが増えるので、想定しているモジュールでは合成できない。

    最初の目的は、 自作AVRコアに適用すること。まだ機能が厳密に合っているのかどうか分からないが .. 42 スライス(83 LUT) が、31 スライス(62 LUT) にまで減った。問題は、規模よりは 速度のボトルネック。もとのやつより速いと良いのだが...

  • ここまでのソースコード (Diamond プロジェクト込み) → qfn32samples-04.zip

     2012/06/17 更新: iVerilog 用テストベンチを追加し、自作AVR コアに適用できるようデバッグ。

     
  • rtavr では、C_OUT/HALF フラグの意味が 減算では反転している。( 1 で ボロー )
     
  • 論理演算では、C_OUT/HALF フラグ は無視してよい。( 結果が違っても良い) -- 実際違うので テストで比較に入れない。
     
  • EQ の意味を取り違えていた。
      ( F == 1111 で EQ = 1 だから Zero Flag とは関係なし。)
     
  • (alu4.v 自体は無変更)

関連記事
posted by すz at 13:27| Comment(0) | TrackBack(0) | CPLD

2012年06月06日

QFN32の FPGA

ふと、MachXO2 でググってみたら、あらたに 32pin QFN が出るらしい。



デジキーでも LCMXO2-256HC のエントリーが出来ている。製品ページを見ても、なにやら情報が出ている。

Mouser では、1個買いの単価が出ている

    330円 (4 グレード)
    371円 (5 グレード)
    418円 (6 グレード)
    まだ在庫なし。工場リードタイム すら出ていない。

      (2012/7/3) 6 グレードだけだが、リードタイムが出ていた。9 週間。価格も安くなっていた。
      244円 (4 グレード)
      279円 (5 グレード)
      314円 (6 グレード)
      256 なんだし、これぐらいでないと。お、4 グレード は、25個時 単価 214円 か。これぐらいだと、AVR とかのサポート用に使える。


  • I/O 数は 22 -- これはどういう計算なんだろう?

    BSDLファイル は既にある。VCCIO が 4 バンクあって 電源だけで 10 pin 。残りが I/O という計算らしい。

    JTAG を専用にすると .. 18 I/O 。それに、PROGRAMN/DONE/JTAGENB の扱いをどうするか。

WLCSP25 は、1200 なのに、QFN32 は、256 のみ。1200 だったら大喜びしてたのに... 残念。

... とここまで書いて、以前の自分の記事に QFN32 のことが載っていることに気がついた。 忘れていたのか。

まぁ、そのことは置いておいて、今は、実際に 電子工作で扱える小ピンの FPGA が出ることはすなおに嬉しい。



これは、ストロベリーリナックスの CP2103 USBシリアルボードだが、こんな風に変換基板を作ることができれば、ナローDIP FPGA ボードになる。ただし、作ることができるとは限らない。CP2103 は、QFN28 なので QFN32 だとより条件が厳しい。1個分のホールを潰せば、ナローDIP化はできそうだが、ランドが少ない。果たして手ハンダが可能なのか? リフローもやってみたいが、それしか方法がないのもどうかという気がする。

    QFNパッケージのはんだ付け

    この記事には、『位置合わせさえ確実であれば無洗浄タイプのフラックスを使ってはんだ付けが可能です。』と記されている。楽々だったとも。

    ランドは、標準より少し 広げているようだ。パッケージの端から 0.5mm ぐらい?

それは後にして、そもそも この LCMXO2-256HC は何に使えるのだろう?

  • 4LUT 数 256
  • ブロック RAM なし
  • I2C, SPI, タイアカウンタ ハードマクロあり
  • PLL なし
  • 内蔵 クロック あり

まぁ ALU ぐらいは出来るだろう。ならば 74HC181 ピン互換が可能になるような、ピン配置にして 24pin の DIP モジュールにするのはどうか? 出来れば、データシートすら、なかなか見つからない 74LS281 互換にもしてみたい。

『CPUの創りかた』で 74HC181 を使っているらしいのだが、入手困難らしい。価値のある使い方がひとつできることになる。ランドも大きくすることが出来て、手ハンダも可能になるはず。

    電源を 3.3V 専用にして、2 pin 分にし、残りの 22 I/O を出すことは可能。

    ただ、Config で JTAG を Disable にすると、JTAGENB が JTAG を強制的に enable するための専用ピンになる。-- 要するに I/O が足りず完全互換にするのは無理。

    出力のうち めったに使われない P または G に JTAGENB を割り当てることでごまかそう。

    あとの問題は、電圧範囲で 3.3V 専用になることぐらい。



    こちらは、aitendo の CP2103モジュールだが、ちょうど 24pin 。こんな風に部品を載せる余裕が随分ある。

そうそう 低容量(128B)の ROM/RAM にはなる。

    8KB ROM と 2KB RAM は、

    A7 (1) (24) VCC
    A6 (2) (23) A8
    A5 (3) (22) A9
    A4 (4) (21) A12 /WE
    A3 (5) (20) CS /OE
    A2 (6) (19) A10
    A1 (7) (18) A11 /CE
    A0 (8) (17) D7
    D0 (9) (16) D6
    D1 (10) (15) D5
    D2 (11) (14) D4
    GND (12) (13) D3

    こんな ピン割り当て。(9) または (11) に JTAGENB を割り当てるので、互換にするのは無理。

    D2 を A8/A9/A10 のどれか に持っていくしかないかな。

    低容量(128B)でも、CPU を創るなら役にはたつ。マイクロプログラムなら 容量よりビット幅だし。

    訂正: 256B が行けるかと思ったのだが、実際にやってみると 128B までしか作れなかった。

    1LUT は、16bit (2B) の容量のはずで、256 LUT あれば 512B 分。ロジックに使う分があるから 256B の計算だったのだが ...

あとは ... 折角 I2C やら SPI やら付いているのだから、なにか デバイスを作ってみるとか。CPUは、入らないから、ステートマシンで作ることになる。内蔵クロックは、最大 133 MHz なので、超高速 PWM ってのも可能。

差動入力もある。コンパレータがわりに使えるかも。

ところで、こいつの電圧範囲はどうなるのだろう? 上限が 3.3V なのは良いとして下限は?
VCCIO は、3.3V/2.5V/1.8V/1.2V は行けそうなのだが、Config で決めた電圧でないといけないのだろうか? それとも、半端な電圧でも良いのだろうか?

ちなみに、ライタは、FT232RL が使えるものを 作った。デバイスを追加しないといけないし、実際には FT232RL での動作を確認していないが、たぶん大丈夫。論理合成ツールは、Diamond 1.4.2 以降で対応済みだそうだ。

追記: 74281 (P/G なし)を合成してみる。

    ピン配置
    XO2-256 74281 74281 XO2-256
    27 A1 1 24 VCC
    28 A2 2 23 A0 25
    29 RS1 3 22 CP 23
    30 RS0 4 21 SIO0 21
    32 RC 5 20 AS0 20
    1 SIO3 6 19 AS1 17
    4 A3 7 18 AS2 16
    5 Cn 8 17 M 14
    8 ~G 9 16 F0 13
    9 Cn+4 10 15 F1 12
    26 ~P 11 14 F2 11
    GND 12 13 F3 10

    以前 74281 の コードを XC2C64A 向けに作ってあったので、試してみることにした。

    実は基板は、eagle で設計済みで、モジュールへのピンアサインも決めてしまっている。

    実際にピンを割り当てるときに、まず JTAG_PORT を DISABLE にしないといけなかった。次に JED ファイル生成でエラーになった。どうやら MUX_CONFIGURATION_PORTS を ENABLE にしないといけないらしい。

    Number of registers: 4
    Number of SLICEs: 24 out of 128 (19%)

    Number of logic LUT4s: 42
    Number of ripple logic: 3 (6 LUT4s)
    Total number of LUT4s: 48


    CPLDだと厳しかったが、小規模でも FPGA だけあって 楽勝 のようだ。74181 は作ったことがないが、これも P,G なしにするし 楽勝だろう。

    基板は、もうすこし練りたい。例えば TDO は出力 だが、JTAG を Disable にし忘れると 回路を壊してしまう恐れが ... 抵抗ぐらいは入れておきたい。他にもオプションとして仕込んでおきたいものもある。

    思ったより回路が入るようだし、サンプルをいくつか用意出来るといいなと思っている。

    ALU と ROM/RAM は作るとして、後は?

    4桁7セグを使った時計とか? 電流は多少流せるようだし、いけるかも。あと、周波数カウンタなんかも出来そう。

基板の設計(1)



    まだ部品も手に入らないわけだが、基板を設計してみた。

  • QFN は、デザイン優先で(というかワザを覚えたので)ナナメにマウント。
     ただ、ちゃんとしたパッドの作り方がわからないので、そこは適当。
     シルクもナナメを使ってみたり。

  • コネクタ部分は、0.8φで小さめの径。秋月の細ピンヘッダを想定。

  • 今回は、裏に部品を付けない。いずれ リフローやってみたい。

      ホットプレートを使うらしいが、小型の電気鍋 (鍋 MG-500 とか 鍋 KG-152 とかでググると多数みつかる) ではダメなんだろうか? 保管場所を取るのはちょっと避けたい。

  • I2C は、プルアップ抵抗を付けられるように。XO2 は、I2C からコンフィグできたりするので実験用。 (普通は)付けない。
  • TDO は、ミスで出力がぶつかるのを危惧して抵抗付き。LED を付けるのにも便利なように配慮。
  • セラミック(or 水晶)発振子を付けられるようにしてみた。
     もうひとつ端子間に抵抗を入れられるようにしてある。
     この 2 つ -- 1M Ωを入れてしまうと、使い方に制限が出るわけだが、私が作るものは、配慮する。

    いつもの gerbtool で画像はつくれなかった。ナナメの部品には対応できていないようだ。



      原因だけは、分かった。ナナメの部品を使うと G36 というコードが使われるようになる。これは、多角形の塗りつぶしを指定するもの。

      そんなアルゴリズムは持っていないので、おかしくなっていたのだった。とりあえず G36 で アパーチャ を小さな矩形にしたところ上のようになった。対応するのは面倒なので、放置になりそう。

  • xo2qfn-05.zip

    eagle の ソース。部品が手に入るまで寝かせておく。(最新版に更新)

      更新: JTAGENB の位置が違うパターンを追加。

  • ここまで作って 74HC181 に合わせられないことが分かった。P/G のピンアサインを確認したつもりが ... 違った。どうしたものか。...



    結局、74HC181 の互換にできるように変更。281 互換にできたとしても、設計できる人しか有用である可能性がない。設計できるなら、ピン互換であることは重要でないだろうし、そもそも こういうものは使わないだろう。

    JTAGENB は、G である 17pin に移動。

    ところで、74HC181の コードを作るのは (P/G なしでも) 結構面倒だと分かった。そもそも Cn+4 の論理が分からない。回路図があるんだから、追っていけば分かるのだろうけど。

    追記: 多角形のフィルに対応。ちょっとインチキで形に条件が付くのだが、多分大丈夫。



    ナローDIP 版も設計してみた。1pin 分潰すだけではダメで 2pin 分になった。でも DIP28 だしソケットは使える。ブレットボードなんかでは、N.C. があるのは逆に便利かも。信号の並びは、ワイド版と同じだが ... おまけの部品は付けられず。まだまだ FPGA が手に入るのは先だろうから、これをベースに練っていこう。



    追記: 練ってみたら、こんなものに ... 。ワイドとナロー両方いけるうえに、1 列だけのユニバーサルエリア付き。切ればナローにもなる。なにか不恰好だが、発注するならこれか。

  • gerbtool-0.8.zip

    多角形のフィルに対応したので、gerbtool 単体もアップデート。

74HC181 とかの コード

  • qfn32samples.zip

    書いてみただけで、ピンアサインも前の案ベースになっていたりするのだが、74281, 74HC181, ROM, RAM のコードをまとめた。

    74HC181 は、とりあえず、回路図のロジックをそのまま組んでみた。

    追記 : ALU については、別記事にした。→ 『TTL ALU 74181』 。
    結構わかってきたので、拡張したりしてみている。

  • qfn32samples-03.zip とりあえず更新版 (2012/06/12)

    ALU だけではなく、いろいろ作ってみたいと思っている。ちなみに、I2C や SPI のモジュールは、バスから使う仕様なので、マイクロコントローラが必須に思えてきた。なので、256 では無理。何故 256 にこんなものが付いているのか? .. とも思ったのだが、コンフィグに使えるから意味はあるのだろう。

    次は、7seg 使った時計 .. かな? 時計自体は楽勝で入るのだが ... 時刻設定のインターフェイスが必要。ここが難しそう。チャタリング対策も要りそうだし。

    追記: 『FPGA時計の設計』設計はできてしまった。思いの外簡単だった。規模もまだ余裕がある。

  • qfn32samples-04.zip 更新版 (2012/06/17)

    なんと 無理だと思っていた CPU の実装が出来た。EFB にもアクセス可能。ただしメモリは、プログラム 128B(最大) + RAM 16B 。これでまともなコードが書けるかというと 無理そう。もうひとひねり要りそうだ。

    あと、FPGA時計にアラーム機能を追加したり、ALU の検証をしたり。

    後はなにを設計しよう --- 周波数カウンタ? 全然違うものとしては、DC/DC コンバータ? 高速 PWM も可能だし、コンパレータも 差動入力の流用で可能。面白いかも。

      そう言えば 『簡易シグマデルタ ADC』なんてものが、リファレンス・デザインにある。規模は 54 LUT だそうだから、載らないことはなさそう。温度計とか作れないかな? 一体 どれぐらいの周波数(sps)で AD変換可能なのだろう? 手軽に買える範囲だと PIC32MX が 1.1Msps だそうだ。それ以上になると AD9283BRS-80 の 80Msps 。10 Msps 程度がない。6bit でも良いから 簡単にできるのなら、(各種)液晶を RGB モニタに出来るかも。 まぁこの FPGA で作る必要はないのだが、何種類か ADC のモジュールを持っていると応用範囲が広がりそうな気がする。

      ... 高性能なのは、やっぱり無茶か。温度計とかが精々?

      コンパレータとして使うには、LVDS25 などを設定する。設定できるピンには制限がある。xxxT2_0 , xxxC2_0 とか T/C が含まれるピンのペア。T が非反転入力で このピンにアサインする。C は反転入力で指定しなくとも自動で選ばれる。QFN32 では、4/5 , 11/12, 13/14, 21/20, 28/27 の 5 ペアのみ。

      コンパレータとして使う場合、入力電圧の範囲が広いかどうか? ドキュメントには、LVDS を使ったときは、わずかに 低くなると書いてある。 VCCIO - 0.5V まで?

      MachXO2 のデータシートには、 (VCCIO=3.3Vのとき)入力コモンモード電圧 は、0.05V 〜 2.6V と書いてあった。(2.5V のときは 0.05V 〜 2.0V ) あと差動入力閾値 は、± 100mV だそうだ。

      入力電圧の範囲が問題になるのは、非反転入力に ダイレクトに ADC入力 を接続する場合。オペアンプと同じような話で、抵抗を直列に入れて (ADC入力 + 生成電圧) を 仮想GND と比較する場合は関係なくなる。

      ところで ADC が出来たとして データを 10進数に変換するのは、どうしよう? MachXO2-256 の規模では、無理なんじゃないかと思えてきた。可能にする方法として思いつくのは、内部形式を 出力形式に合わせることぐらい。そんなことが出来るものなのかどうか?

追記(2012/6/21)

  • qfn32samples-06.zip 更新版 (2012/06/21)

    ADC は置いておいて ... DAC が出来ないか検討。なんかいけそうなので、コード追加。

    あと MCPU 。オリジナルベースは捨てて、rewrite 版のみ残した。何種類もあってもメンテできないし。

    ところで、Mouser で、1個買いの単価が出ているが、6 グレードが発注可能になった。リードタイムが9週間になっているが、ボチボチか。基板を発注する時期が近づいている。

    アナログ回路を組むなら、VCCIO のいくつかを別電源にしたいところ。なのだが ... ナロー型では、無理だった。ワイド型なら とも思ったのだが、なかなか難しい。VCCIO1 と VCCIO3 の 4pin 分をパターンカットで分離可能にするのが精一杯。

追記(2012/6/23)

    基板変更。VCC, VCCIO 0/2, VCCIO 1/3 をパターンカットで分離可能にした。VCCIO 1, VCCIO 3 だけもさらに分離可能。追加したコンデンサが 4 つになったが、全部裏側。従来どおり 追加コンデンサなしでも使えるのだが、位置の関係で、パターンをいくつかショートさせた方が良い ... という変なものに。まぁ 追加コンデンサ付けるし。

    電源は、VIA を寄せて 2mm ピッチのコネクタにしてみた。

    これをIteadStudio (新サイト)に、ついに発注。発注したのは 2 つで 最初に作ったワイド版と ナロー版。IteadStudio の DRC でチェックしたら、0.3mm のドリルが DRC でエラーになった。0.4mm に変更。

    送料は、$5.59 。

    6/30 : 発送の連絡

    実は、ナロー版について、『問題が出るかもしれない、そのときは相談させてくれ』という内容のメールをもらった。が、なにごともなく製造できたようだ。

    7月9日 20:27 国際交換支店に到着

    来ても眺めるしかないが、いよいよか。
    実を言うと Muser で 6 グレードのやつを 6/24 に発注した。8/27 に発送できる見込みだそうだ。

    7月13日 基板受け取り。

    来た。書くのを忘れていたのだが、両方 1mm 厚にした。大きい方は 10 枚ぴったりで、テープで巻いてあるだけだった。小さい方は 16 枚でパックされていた。

    一見しただけだが、とても作れそうに見えない。まぁチップが来たら頑張ってはみるが。

    8 月 1日 Shipment Notification がキタ。予定よりずいぶんはやい。



追記: 2012/8/26 ようやく組立て



    はんだ付けは、位置さえ決まれば、簡単だった。足がないためか .. ハンダがとなりとくっつかず切れが良い。吸い取り線を使うまでもなかった。

      (注意)簡単なのは、底面と側面のパッドがつながっているタイプなので QFN ならなんでも簡単というわけではない。あと PIC32MX にも QFN があって興味が出てきたのだが、こちらのピッチは、0.65mm 。基板を起こすときに注意しないと。

    今は、とりあえず組み立てただけ。PIC32MX が終わったら、こちらに戻ってくる予定。

    LC など部品についてすっかり忘れていた。

      R2/R3/R5 -- I2C のプルアップや、セラミック発振子を使うときピン間に入れる 1MΩ用。これは今後も使わないようなオプションなので付けない。

      右下のソケットと R1/C5/C6 は、水晶振子を付けるためのもの 1MΩ/22pF で一応付けてみた。

      忘れていたのが、ジャンパなのだが、左下 と 右(ナナメ)の VIA は、電源の引き回しがながいのを嫌う場合のショートカット用。裏面にパスコンを付けるなら不要だし、そもそも不要かも知れない。様子見するので、ショートカットしない。

      あと、上の2x3の VIA は、I/O電圧を 3.3V 以外にする場合に使う。ウラのパターンをカットして使うが、3.3V 以外は考えていないので変更なし。

      左の 300mil 幅のやつは、オプションがほとんどない。(あっても裏面を使う) 。付けたのは、コンデンサ 3 つのみ。

    作ったは良いがどう書き込むかについて。

      JTAGツールとSYNCBB』にある、rtavr_tools-0.10 を使って 書き込む予定だが、MachXO2-1200 しか対応していない。ちょっと修正が必要。

      あと、『MachXO2 1200ZE Breakout ボード』 も 少しの改造でライタにできる。Diamond から直接書き込めるからお薦め。JTAGENB を有効にする オプションで なにもしない回路をコンフィグし、JTAGENB を L にするスライドスイッチを付けるだけ。JTAG 用のコネクタがあるので、そこから 出力。JTAG をチェーンする方法もあるが、パターンカットとか配線とかが面倒。

eagle の ソース

関連記事
posted by すz at 22:11| Comment(0) | TrackBack(0) | MachXO2

2012年05月26日

dealextremeの電子パーツ

dealextreme で扱っている 電子パーツが増えてきている。(コンパチ品ばかりだが) Arduino関係 まで扱うようになっている。

お買い得なものや 日本で手に入りにくいものもあるので、ピックアップしてみよう。

お買い得なもの

日本で手に入りにくいもの

これぐらいにしておこう。電子パーツと言いながら、コネクタとか スイッチばかりになってしまった。こういうのは、実際安いし種類も豊富にある。探してみると掘り出しものが見つかるかも知れない。

追記: ミニミニバナナ

EAGLEの45°回転

    ナビゲーションスイッチ MT-008A は、(反時計回りに)45 °回転して マウントする。このライブラリを作ろうとしていたのだが、どうやって 45 °回転した PAD を作ろうか悩んでいた。-- i アイコンでの 設定で、回転角があるのだが、ふと 45 と入れてみたら見事に回転した。(使っているのは、EAGLE-5.7)

    なんだ、EAGLE でも 45 °回転した部品は作れるのか ... と嬉々としてライブラリを作ってみた。座標を計算するのが面倒なのだが、なんとか 出来上がった。 出来上がってから、部品も回転できるのでは?... と思いついてやってみたら、できた。 45 °どころか任意の回転ができるようだ。

    90 °単位しかダメだとばかり思っていた。

    ところで、MT-008A は、ユニバーサル基板にマウント可能かも。作ったライブラリをじっくりみると ... 位置決め用の でっぱり? が、2.54mm ピッチ。三連の真ん中さえ絶縁して引き出せれば なんとかなりそうだ。
posted by すz at 12:29| Comment(0) | TrackBack(0) | 日記

2012年05月24日

JTAGツールとSYNCBB

前記事で MPSSE についてちょっと調べてみたわけだが ... 自分のツールで対応してみたいというのが理由だった。だが、結局は 機能が増えるわけではなく、性能が改善されるだけだ。それはそれで興味深くはあるのだが ... 後回しでも良いだろう。

MPSSE はちょっと置いておいて ... 他のことを考えてみよう。

一般に JTAG Cable は、けっこう高価だ。自作なんかも 行われているわけで、JTAGkey clone が人気がある。ただ、これにしても 部品も揃えないといけないし、それなりにはコストがかかる。なにより作るのが面倒で、お試しでちょっと使うには敷居が高い。

であれば...

  • AE-UM232R を使って、配線だけで 広範囲な電圧(1.8V-5V)に対応。ただし遅い
     -- VCCIO を ターゲットから貰えば良い。配線だけで済むが、接続の手順というものがあるかも。
  • UM232H を使って、3.3V 固定なものの 配線だけで高速に 使える。
     -- UM232H は、3.3V 専用。またシリアルの設定のままだと基本 MPSSE は使えない

こういう風になれば、少しは敷居が下がるのではないだろうか?

    SYNCBB でも FT2232H で 3.87 Mbps までは出た。MPSSE の 1/5 ぐらいの性能だが、常に最高性能を出せるとは限らないわけで、使い物にはなるはず。FT232R だと 随分(ひとけた)落ちると思うが、お試し用と割り切れば悪くないはず。

でも、なかなかこうならないのは、ツールの対応が進まないからだと思う。それについて考察してみる。

OpenOCD

    まずはこれ。FT232R のドライバは標準ではない。誰かパッチを作っていないか調べてみると ...

    なんとあった。
    FT232R based JTAG with OpenOCD patch

    これである。ただし、

    I do not have FT232R. I just feel this might be interesting.

    なんてことが書いてあって、ちょっと心もとない。コード自体はしっかりしているようなので、まぁこれベースで 改造していけば、使えそうな感じはする。ちなみに、OpenOCD-0.5.0 に対してパッチを当ててみたら 2 ヶ所だけ reject された。手で直すのは簡単ではあった。

    ちょっと見た範囲では、ピンアサインがいまいち

    * Bit 7 (0x80): unused.
    * Bit 6 (0x40): /SYSRST output.
    * Bit 5 (0x20): unused.
    * Bit 4 (0x10): /TRST output.
    * Bit 3 (0x08): TMS output. (CTS)
    * Bit 2 (0x04): TDO input. (RTS)
    * Bit 1 (0x02): TDI output. (RXD)
    * Bit 0 (0x01): TCK output. (TXD)

    Bit2 が RTS だから もともと出力。これに TDO を割り当ててしまうと 出力がぶつかり、配線だけで 使うわけにいかなくなる。ピンアサインについては、後で検討してみよう。

UrJTAG

    OpenOCD ほどではないが、次ぐらい? に有名なツール。これのパッチ があるのかどうか 調べてみたが見つからなかった。

    対応するのにどれぐらい大変なのか? ちょっと見てみた。

    まず、UrJTAG は、FT245 ベースの USB-Blaster と FT2232(MPSSE) ベースの各種 Cable に対応している。ドライバは二段構成で ftd2xx , libftdi に対応した 下位ドライバ2 種類と、上位ドライバの構造をしている。

    で、FT2232 ドライバは 2000行ほどあるのだが、各種 Cable に対応している部分が 半分を占める。Cable を1つだけにすると 1000 行弱で、それをベースに すれば、それほどは難しくないかも知れない。USB-Blaster のコードもあり 500行ぐらいとさらに小さい。でも FT2232 ドライバベースの方が良さそうな気がする。

    ただ、ちょっと問題がある。下位ドライバで FT_SetBitMode して SYNCBB(Synchronous BitBang) モードにしたいわけだが、そのときに Direction の パラメータが必要なのだ。MPSSE だと read/write で Direction を変更できるから良いのだが ... SYNCBB だと なにか API を追加しないといけなさそう。

cblsrv-0.1_ft2232

  • Amontec JTAGkey-Tiny (FT2232) を Xilinx iMPACTから使う

    URL はここ。どれだけ知られているのか分からないのだが、JTAGkey clone を iMPACT から直接使えるようにするもの。ただ、Linux では使えないし、MinGW の環境でビルドできなくなっている。そのままでは、(私が)いじるのには向いていない。

    ところで cblsrv は、ネットワーク経由で iMPACT から司令を受けて JTAG の処理をする サーバ。で、司令がどういうものか ... ちょっと見てみたところ、どうも JTAG の STATE 設定 と TDI へ bit ストリームを送り込む (+ TDO から受け取ったストリームを 返す) 構造のようだ。

    ちょうど JTAG のツールを作っているところだから、上位レイヤーと自作のコードを くっつけた方が (私には)扱いやすそうな感じ。いっそのこと 上位レイヤーのロジックをコピーして re-write しても良いかも知れない。

というわけだ。このなかでは パッチが既にある OpenOCD の改造が 一番敷居が低い。ピンアサインを決めるだけなのかも知れない。( 作った人は FT232R は持っていないものの、ピンアサインは MPSSE に準じているところから見て FT2232X でデバッグ済みのような気がする。)

なら、まずはピンアサイン。avrdude-serjtag で基本のアサインは 2 つある。やはり TXD/RXD は空けておきたいから
 
TMS = D7/RI
TCK = D5/DSR
TDI = D6/DCD
TDO = D3/CTS

これが基本か。 あとは 2 pin だが、

/SYSRST = D4/DTR
/TRST = D2/RTS

これで良いのじゃないか?

あと、JTAGkey clone では、SYSRST は双方向 が基本みたいだが、このピンアサインだと 出力専用 にせざるをえない。(これで良いのだろうか?)

cblsrv の調査

    どんなコマンドがあるか調べてみた。

    MSG_COMMANDS:
    CMD_DONE
    CMD_SET_CABLE_OPTION
    CMD_GET_CABLE_OPTION
    CMD_IS_CONNECTED
    CMD_READ
    CMD_WRITE
    CMD_SET_PIN
    CMD_PULSE_PIN
    CMD_START_OPERATION (open みたいなもの)
    CMD_NAVIGATE_TAP (from to の STATE遷移)
    CMD_WAIT_TIME (sleep)
    CMD_WAIT_TCK (N 個のクロック送出)
    MSG_GET_INFO:
    MSG_SET_CABLE_MODE:

    MSG_CLOSE_CABLE:
    MSG_CHECK_SERVER:
    MSG_0x06:

    これで全部。MSG_XXX で、ひとつのコネクション。違う MSG を送るたびに一旦コネクションを切る。MSG_COMMANDS だけは、他のと違って CMD_XX がひとつのコネクションのなかで連続して発行される。

    まず重要なのが、 CMD_NAVIGATE_TAP -- 簡単なものだとしても JTAG のレイヤーを 持っていないといけない。

    CMD_WRITE は、TDI ストリームを送り込む司令で、CMD_READ は、最後の CMD_WRITE に対する TDO ストリーム を返す。常に read しておかないといけないので、ちょっと嫌らしい。

    MSG_GET_INFO/MSG_SET_CABLE_MODE は対になっていて、ケーブル名 や ケーブルタイプ , port , speed を GET/SET する。

    CMD_SET_CABLE_OPTION/CMD_GET_CABLE_OPTION は、オプション名 に値(文字列) を読み書きするもの。これも 汎用的すぎてちょっと嫌なかんじ。

    cblsrv 自体は、C++ だが、クラスを使ってなくて、C に変更するのは容易。これを書き換えていくというのは、ひとつの手なんだが、書き方が自分の趣味に合わない。MSG_XX や CMD_XX に対して関数が割り当てられていて、case 文 と処理するコードが離れている。関数作る分だけ冗長だし、流れを読みにくい。

    やっぱり、re-write したいような ...

自作のツール

  • rtavr_tools-0.10.tar.gz

    一応 作っているものの最新版。ただし 前記事の MPSSE 対応とか この記事に関係するところをいじっている最中。あと、ちゃんと書いておくと もともと汎用的なものは目指していない。自分が使う範囲で便利なものを目標としている。
posted by すz at 20:06| Comment(0) | TrackBack(0) | artemis

2012年05月23日

MPSSEめも

いままで作ってきた コードは、Synchronous BitBang(以下 SYNCBB) Mode を使っている。FT2232H でも FT232H でも SYNCBB は持っているので、コードはそのまま使えるのだ。

遅いという問題はあるが、実用上さほど問題になることはないと思っている 。FT2232H とか使ったら それなりに高速になる。ただ、UM232H とか安価な モジュールも出てきたし MPSSE を使ってみたいような気もしている。MPSSE は、JTAG ケーブルで良く使われているが、実際どういう機能なのか知りたくも思っていた。まずは、どのように使うものなのか調べていこう。

初期化:

    SYNCBB も MPSSE も FT_SetBitMode() を使ってモード設定する。だから、FT_SetBitMode() するまでの手順は、どちらも共通なのだ。

    FT_SetBitMode() で MPSSE モードにした後は、送受信するデータの意味が SYNCBB とは違う。

  • AN108: Command Processor for MPSSE and MCU Host Bus Emulation Modes

    このドキュメントがその詳細。初期化に必要そうなコマンドをちょっと抜粋しておこう。

  • GPIO の設定と読み出し (初期値の設定)
    MPSSI で使う TCK/TDI/TDO/TMS を含めて ADBUS/ACBUS (BDBUS/BCBUS) の設定と読みだしが出来る。


    Set Data bits LowByte 0x80 Value Direction
    Set Data bits HighByte 0x82 Value Direction
    Read Data bits LowByte 0x81
    Read Data bits HighByte 0x83

    LowByte は、ADBUS の Bit番号に対応し、HighByte は ACBUS の Bit番号に対応する。
    また、ADBUS の bit0 - bit3 は、 デバイスにかかわらず TCK/TDI/TDO/TMS が割り当てられる。Direction は 各bit の値が、1 で出力 0 で入力。

      ここで注意点がある。RS232C のモードだと TXD/RXD/RTS/CTS に割り当てられている。bit2 TDO はデバイスからの出力 だが、RS232C でも RTS でホストからの出力でぶつかるのだ。

      なので、一般的には シリアルに割り当てないように EEPROM の設定が必要になる。

  • クロックレートの設定
    FT_SetBaudRate とは別に クロックレートの設定をしなければならない。

    Clock 30MHz 0x8A
    Clock 6MHz 0x8B (default)
    Set TCK/SK divisor 0x86 ValueL ValueH

    0x8A/0x8B は、FT2232D にはない モードで ベースクロック値を変更する。0x86 の Value はこのクロックに対して分周する値(-1)。bit clock を 1 MHz に設定したければ、5 を設定する。30 MHz にした場合は、29。

    この説明は、正確ではないがだいたいこんなもの。

    GPIOの設定 の周期が、この設定で変わるのかどうかは不明。

  • ループバックの設定
    デバッグの初期にしか必要ないと思えるのだが、TDI と TDO を内部でつなげるモード。

    Loopback Enable 0x84
    Loopback Disable 0x85

    ひょっとしたら 初期化で Disable にしないといけないかも。

  • 2232D にない機能
    2232D にない機能は、無視してよいかと思ったのだが、気になるものがあるので、追記


    Enable 3 Phase Data Clocking 0x8C
    Disable 3 Phase Data Clocking 0x8D

    他にもあるが、とりあえず。

データの入出力

    データの出力方法に様々なパターンがあるのだが、JTAG で使いそうなものだけピックアップ。

    Clock Data Bytes Out on +ve clock edge LSB First (no read)
    0x18 LengthL LengthH byte1 .... ByteN
    Clock Data Bytes In on -ve clock edge LBS FIrst (no write)
    0x2C LengthL LengthH
    Clock Data Bytes In and Out (Out +ve / In -ve)
    0x3C LengthL LengthH byte1 .... ByteN

    Clock Data Bits Out on +ve clock edge LSB First (no read)
    0x1A Length byte1
    Clock Data Bits In on -ve clock edge LBS FIrst (no write)
    0x2E Length
    Clock Data Bits In and Out (Out +ve / In -ve)
    0x3E Length byte1

    -ve clock edge とは TCKの 立下り(↓)だと思えるが、説明はないようだ。8bit 単位でない操作は、bit mode を使う。それぞれの mode は、Out/In を行うかどうかで 3 通りがある。 byte mode に設定できる Lehgth は 1 〜 65535。bit mode は、1 〜 7 。

    基本はこの 6 種類で済むはずだが ... ルールがあるのでそれについて

    bit0 : -ve CLK on write
    bit1 : 0 byte mode / 1 bit mode
    bit2 : -ve CLK on read
    bit3 : 0 MSB First / 1 LSB first
    bit4 : DO write TDI
    bit5 : DO read TDO
    bit6 : DO write TMS
    bit7 : 0

    ピックアップした 6 つは、

    0 x x x 1 1 x 0

    のパターンが基本。ただし no read の場合は、bit2 は 0/1 どちらでも良いのかも知れない。 あと 出力は TMS 入力は TDO というパターンがある。TDI/TMS とも write に設定するとどうなるのか? ... 説明は見つけられていない。

rtavr_tools とのマッピング

    rtavr_tools での CABLE ドライバのインターフェイスは、次のように決めている。

    open
    close
    delay bitclock ベースの遅延
    put_tdi_bits TDI ストリームの出力 , Read あり/なし
    put_tms_tdi_bits TDI+TMS ストリームの出力 , Read あり/なし
    setup_port TCK/TDI/TMS の値を設定。
    setup_gpio INIT/PROG/M1/M2 と名付けた GPIO の状態設定
    get_gpio      INIT/PROG/M1/M2 と名付けた GPIO の状態取得
    set_bitclock bitclock の設定

  • put_tdi_bits

    上に書いてないが、最後のビットだけ TMS を H にするオプションがあり、JTAG では良く使われる。

    コマンドの組立てを考えると...

    MPSSE_PUT_BYTES (MPSSE_PUT_GET_BYTES read あり)
    :
    MPSSE_PUT_BITS (MPSSE_PUT_GET_BITS read あり)
    (TMS_HIGH オプションの場合 の追加)
    MPSSE_SET_LOW
    MPSSE_PUT_BITS (MPSSE_PUT_GET_BITS read あり)
    MPSSE_SET_LOW

    こんな感じになる。ただし、bit 数によっては、MPSSE_PUT_BYTES / MPSSE_PUT_BITS のどちらかがない場合がある。read なしの場合は、単に一気に 送れば良いのであまり問題でないのだが ...

    read ありでは、read データを解析しないといけない。MPSSE_GET_PUT_BYTES / MPSSE_GET_PUT_BITS がどういう組み合わせになっていようが、綺麗なビットマップになる。TMS_HIGH オプションがあると 1 bit 分のデータがそれにくっつく。... これぐらいだったら、BitBang 用として作ったものをベースに改造すればいけそうだ。

  • put_tms_tdi_bits

    これは、JTAG の ステートを変更する 時に使っている。操作するビット数はあまり多くない(最大 10bit)が、jtag の API がステート + TDI ストリーム という構造なので、put_tdi_bits と同じような頻度で使われることになる。

    もともとの仕様は、read あり になっているのだが ... どう実装するのが良いのだろう?

    (bit 数分のくり返し)
    MPSSE_SET_LOW (TMS が 変化する場合のみ)
    MPSSE_PUT_GET_BITS (1bit 分)
    MPSSE_SET_LOW (TMS を最後の状態に戻す)


    read の結果には MPSSE_SET_LOW は関係せず、1 バイト 1bit と決まるから、解析は難しくない。

    これで一応仕様を満たすことにするが ... 実は read ありは使っていない。read が入らなければ、write が連続で出ることになり、レイテンシは無視できる。BitBang だと write した分は、かならず read が入る。たぶんこの理由で、MPSSE の方が速くなりそう。

      ところで、JTAG の ステート変更では、TMS のみを TCK で出力するパターンを使う。そうであれば、TMS を変化させる コマンドを使った方が効率が良い。

      ただ、API まで変えるつもりはないので、TDI が全部 0 のとき TMS を変化させるコードにする .. とか最適化のひとつと考えておく。

  • delay
    クロックを発行しつつ delay する というコード。MPSSE_GET_BITS を必要クロック分発行すれば良さそう。ただし、実装する必要はなくオプション。

    実装されていなければ、put_tdi_bits で代替する。

  • setup_port / setup_gpio / get_gpio

    BitBang 用のコードをベースにすることで、簡単につくれる。

    ちなみに、INIT/PROG/M1/M2 は、Xilinx の信号線をベースに決めている。どのように操作するかは、

    (cbl->setup_gpio)(cbl, CABLE_GPIO_PROG, -1);
    (cbl->setup_gpio)(cbl, CABLE_GPIO_M2, 1);
    (cbl->setup_gpio)(cbl, CABLE_GPIO_M1, 0);
    (cbl->setup_gpio)(cbl, CABLE_GPIO_PROG, 0);
    (cbl->setup_gpio)(cbl, CABLE_GPIO_PROG, -1);
    (cbl->setup_port)(cbl, 1, 0, 0); // TMS = 1, TDI = 0, TCK = 0;

    こんな風に固定にしている。-1 は HI-Z (入力) 、あと config ファイルでの割り当てがなければなにもしない。それに加えて論理を逆にする config の設定がある。

(おまけ)I2C の考察

    I2C のコードはますます作る気はないが、メモ。

    MPSSE_SET_LOW/MPSSE_SET_HIGH は、アトミックに 方向を切り替えられる。だから L または HI-Z (入力) という操作は簡単にできる。読み込みの MPSSE_GET_LOW/MPSSE_GET_HIGH も期待通り同期してくれるだろうから、似非 I2C マスターのコードは簡単そうだ。

    似非 と書いたのは、ちゃんと作ると SCL を H にしたい場合は H になったことを確認しないといけないから。読み込みの結果によってループするようなコードにすると、USB は極端に遅くなる。だから、応答性能 の保証がないデバイス相手だと、ちょっと面倒なことになりそう。

    対策としては、遅くなるのを覚悟で、H になったことを確認する (1)。このパターンだと すごく遅くなるだけでなく、AVR USI を使うときに AVR も止まるという弊害がある。

    もうひとつは、delay をちゃんと計算する(2) 。AVR USI 相手 だと、割り込みが起きる フレームの最初のところだけ遅くして、あとは 普通にするとか。たぶん このやりかたが適切だろう。
posted by すz at 21:45| Comment(0) | TrackBack(0) | artemis

2012年05月19日

昇圧 DC-DC コンバータ覚書

前の記事に関係あるが、ステッピングモータ SPG20-1362を使うなら、15V 近い電源が必要になる。これをどうしたら良いかちょっと考察。

MC34063A

    汎用の DC-DC コンバータだと MC34063A がある。これは、昇圧にも使うことが出来て 5V → 12V なんかでも使える。あまり凝らないのなら、これで作るのも良いだろう。

    以前に書いたのだが、この MC34063A の派生版のような IC で M5291FP というのがある。日本語の PDF もあって、細かい説明が書かれていて参考になる。ググるキーワードは、RJJ03D0805 。現在も ルネサスのサイト から ダウンロードできる。

    4.8V (NiMH x4) を入力として 13V 0.5A を作りたいとして、ちょっと検討してみよう。

    まず 部品として、
  • 表面実装用(SMD) インダクタ (27uH , 3.1A) 4個 100円 
  • 表面実装用ショットキーバリアダイオード SS2040FL (40V , 2A) 20個 300円
    を使うことにする。

      Ton/Toff = ( Vout + Vf - Vin ) / ( Vin - Vsat )
       Vf は、ダイオードの 順方向電圧
      Vsat は、トランジスタの飽和電圧

    こういう式がある。Vin から上げたい電圧:Vin が Ton:Toff になるということか。

    ダイオードの 順方向電圧 は電流を流せば増える。0.5 V と見積もっておく。Vsat は、M5291FP のデータシートでは、外付け Tr を使わないなら 0.6V だそうだ。あと電流検出抵抗 Rsc の分がある これは Vin から 0.3V 引いておくことにしよう。

      Ton/Toff = ( 13 + 0.6 - 4.5 ) / ( 4.5 - 0.5 )
      = 2.275

    結果はこうなった。Ton は結構長い。

      Ipk = 2 x Iout x (1 + Ton/Toff)

    次にこういう式がある。電流は 線形で増えていくから ピークは平均の 2 倍。で、平均電流と出力電流の関係は、Iout x (1 + Ton/Toff) 。Toff の時間に 線形に減っていく電流の面積。こういうこと?

      Ipk = 2 x 0.5 + (1 + 2.275)
      = 3.275 (A)

    13V で 0.5A 流したいなら Ipk は 3.275 になる。インダクタの定格をちょっとオーバするが気にしない。

      Lmin = (Vin - Vsat)/Ipk * Ton
      1/Ton = (Vin - Vsat)/Ipk / Lmin
      Ton = Lmin * Ipk / (Vin - Vsat)

    Ipk はこの式で使い、Ton(MAX) を出す。

      Ton = 27u * 3.275 / ( 4.5 - 0.6)
      = 22.7 (us)
      Toff = 22.7 /2.275
      = 10.0 (us)

    計算した Ton + Toff から周波数を計算すると 30.6 kHz になった。

    これで良いの? という気がするのだが ... 5V → 12V 1A の回路例で 10uH なのに 50kHZ に周波数を設定している。0.5A なら 20uH で50kHZ 前後のはずだから だいたい合っているような ...

    効率はどうなるのだろう?

      出力は、13V x 0.5A
      入力は、Vin (4.8V) x ( 0.5A + 1/2 Ipk x Ton/(Ton + Toff) )
      で計算してみた。0.5A 足しているのは、昇圧は Vin に 上乗せするような計算になっていたから。理由ははっきりわからないが、こうしとかないと辻褄が合わなさそう。

      計算すると 82% ... 理論値みたいなものだし、実際はそんなはずはないか ...

    ところで、Ipk と 定格の関係。ダイオードなんかは、定格は平均電流。ダイオードの定格は 2.0A だが、大丈夫なんだろう。インダクタは、10% インダクタンスが減るときの 電流値で、実はもうすこし流せるようだ。これも問題ない。問題は、MC34063A自体。1.5A と書いてはあるのだが、ピークなのか平均なのか?

    ピークなら Ipk = 3.275 (A) だから全然ダメ。だが平均は、

      1/2 Ipk x Ton/(Ton + Toff)
       = 1.14 (A)

    だからいけることになる。

    どっちだろうか? それはやってみれば分かる。ただ、やってみるには、Rsc として 0.1 Ωが必要。... これの入手に難がある。

  • コスモ電子: 酸化金属皮膜抵抗 1W

    とかあるところにはあるようだ。

  • MCR25JZHFLR100 0.1Ω 3225
  • MCR50JZHFLR100 0.1Ω 5125

    デジキーならこのあたり。

    MC34063A の互換品には、NJM2360ADがある。 あと、100均の シガープラグ の 5V アダプタでも使われているのは有名。

    発振周波数設定用のコンデンサの値

      Ct (pF) = 40 x Ton (us)

    だそうだ。1000p ぐらい。


Tiny13A

    上の計算で、周波数や Duty比は分かった。なら Tiny13A とかの PWM でも良さそうなものだ。ADC があるから 電圧を測定できる。出力電圧を上回ったら スイッチングをやめれば良い。

    追加部品は、Nch MOSFET。

  • シングルNchチップMOSFET FD6612A (30V , 8.4A) 10個 200円 売り切れ
  • シングルNchチップMOSFET FD5680 (60V , 8A) 5 個 200円
  • DMS3016SSS SO-8 シングル(デジキー)
  • DMG3420U SOT-23 (デジキー)
  • DMG3415U SOT-23 (デジキー)
  • IRLML6246 SOT-23 (デジキー)

    沢山書いたが、FD6612A,FD5680 は VGS が高く 4.8V をそのまま AVR の電源にしないといけないという制限になる。 DMS3016SSS はデジキーで買えるものだが、置き換えが可能。はなからデジキーから買うつもりなら SOT-23 の DMG3420U も良いかも。

    ... というわけで、Nch の MOSFET の選択もなかなか面倒。

Tiny85/Tiny45

    Tiny85/Tiny45 だと もっと高度なことが出来る。やってみたいのは、コンパレータを使った電流モード制御の追加。

    電流測定用 抵抗として 0.1Ωを用意して、Nch MOSFET と GNDの間に入れる。あと、比較用に 0.3V を 分圧して作る。分圧の元は VCC (4.8V) でも良い。

    制御は、3A 流れることがあれば、Ton を短くする。毎周期 3A 流れた時点で Off にするというのは 厳しいので、3A 以上流れないように Ton を調整するわけだ。

    ピンアサイン案:

    ~RESET 1 8 VCC
    ADC3 2 7 ADC1 (SCK) voltage
    L 電流検出 ADC2 3 6 PWM (MISO)
    GND 4 5 (0.3V)基準電圧 (MOSI)

    #5 は、AIN0 だが、AREF でもある。こちらに 基準となる電圧を入れたほうが融通が利きそうだ。AIN1 は、ADC0-3 と置き換えることができる。Tiny85/Tiny45 は、差動入力 ADC2-ADC3 が使えるので、応用の可能性を考慮して、電流検出は #3 ADC2 にする。
posted by すz at 02:31| Comment(0) | TrackBack(0) | 日記

倒立振子ロボットめも

メモたんく』の ぱんと氏 のところで倒立振子ロボットを作っているのを見つけた。興味深いのでメモしておこう。

オリジナルは、『からくり小僧』の iCHIRO 氏の LIBRA-ZERO/ONE 。こちらの記事も合わせて見ている。

モーター + 車輪:

    まず、モーターは、ギア付きの ステッピングモータ SPG20-1362。 (ぱんと氏は) これに、タミヤの 楽しい工作シリーズ No.96 オフロードタイヤセット を直接付けている。

      記事をみていると、 オフロードタイヤセットの(ホイールではなくて)タイヤが外れる? -- みたいなことが書いてあった。iCHIRO 氏は 同じシリーズの ナロータイヤセットを使っている。ただ、ちゃんとセットアップできれば オフロードタイヤセットの方が良いようなことも書いてあった。

      ... なかなか タイヤの選択も難しいらしい。

    いままでにも、倒立振子ロボットに興味を持ったことはあるのだが、駆動部のトルクと速度をどうするのが良いのか分からなかったので、パスしていた。なるほど、SPG20-1362 が具合が良いのか。-- この組み合わせで 倒立振子ロボットとして実績があるというのは 心強い。

モータ用電源

    モータの駆動電圧は 15V 近いようだ。オリジナルの LIBRA-ZERO/ONE では PIC の PWM で 昇圧 DC-DC コンバータを自作している。

    キーになる要素をメモすると ..

    表面実装用(SMD) インダクタ (27uH, 3.1A) を使用し、PWM周波数は、200KHz位。出力電圧14.4Vで 電流0.4A (5.76Wの出力) 。入力は約4.8Vで2.0A (約60%位の効率)

    この DC-DC コンバータは I2C デバイスとして実装されているとのこと。

その他の部品

    (ぱんと氏は) センサに、小型圧電振動ジャイロモジュールを使っている。

      iCHIRO氏も 使っているのは ジャイロセンサ 秋月の旧製品? 。それはともかく、ジャイロセンサは、角加速度を検出するものではなく、角速度。ふうむ Gセンサは使わないものなのか。

    モータドライバは、何だろう? ユニポーラ型だそうだから、表面実装用トランジスタアレイTD62083AFNG とかで十分? 8ch だから これで 2 個のモータを制御できるし。

モーターを回すだけでも 電源の問題もあるし、なかなかに手応えがありそうだ。その上で 倒立振子 としての制御 、さらに 自由に動かすための制御 がある。

駆動系を作るのは比較的簡単そうで、動かすのに頭を使う。なかなか良さそうなテーマだ。 実際に動かすのも狭い場所で楽しめそうだし、その面でも良い。

部品についても、良い物が結構安く手に入るようになってきた。良い時代になったものだ。

その他のメモ

SPG20-1362

    今は、SPG20-1332 と 2 種類がある。以前は SPG20-332 というのが売られていたのだが、性能が上がってコンパクトになったのが、SPG20-1332 。1332 は、1 ステップ 0.75°で遅い。1362 は、1 ステップ 1°で若干高速で こちらの方が 倒立振子 として向いているそうだ。

      (参考) からくり小僧:ステッピングモータ(SPG20-1362)を使ってみた

      これを見ると、高速回転ではトルクが低下していく。グラフを見ると 600 pps ぐらいで半分。とりあえず 限界を 720 pps と仮定すると 2 回転/秒 (= 0.083sec/60°)。55mm のタイヤなら 35cm /sec 。このときの トルクは 25 mN・m ぐらい ... 1N・m = 10.2 kg・cm だそうだから 0.25 kg・cm ?

      無理やりサーボモータで使われる単位にしてみたが ... 速度はサーボモータ並みだけれども トルクは(小型のものと比べても)はるかに(一桁) 小さい感じ。

    データシートを見ると 2W と書いてある。抵抗は 68Ω。電流を流しつづけたときに 14.4 ^2 / 68 = 3.0W だから こんなもの? 電流的には 14.4 / 68 = 210mA (最大) 。0.4 A 流せれば 2 個駆動できる。

DC-DC コンバータ

    AVRで再実装するとして、PWM は 8MHz が使えるから オリジナルと同じ条件。200kHz だと 40 ステップ。ステッピングモータの駆動専用だから、スイッチングの ON/OFF 制御だけでも良さそうな。

    Nch MOSFET は、平均 2A は 流せないといけないが、どういうのが良いのだろう?

    20V耐圧の SOT-23 品を使うとか ... デジキーになってしまうが、DMG3420U,DMG3415U , IRLML6246 とか。-- Pch版が 秋月にあるもの を選んでみた。
    これらだと、AVR を 3.3V で使うことにしてもちゃんとスイッチングできる。秋月にあるのは、VGS が高いので、4.8V のバッテリーをそのまま電源しないといけない。

    あるいは、秋月で手に入る SO-8 パッケージ シングルの FD5680 (60V , 8A) を取り敢えず使うことにしておいて、デジキーで 手に入る DMS3016SSS に置き換え可能にするとか。

    それはともかく、モータ専用で凝らないなら Tiny13A 程度でも作れそう。

タイヤ

    楽しい工作シリーズだと、

      No.96 オフロードタイヤセット
      No.145 ナロータイヤセット
      No.111 スポーツタイヤ
      No.193 スリムタイヤセット
      No.194 ピンスパイクタイヤセット

    と各種ある。直径 55mm 前後 が安心だが、もうすこし小径でも良いらしい 。他のメーカだと MYU-004 あたりが使えるかも知れない。

(不完全)パーツリスト

SPG20 モーターの代替

    SPG20-1362 のようなギア付きのステッピングモータは、入手が難しい。秋月で安く手に入るから良いが、いずれは在庫がなくなるだろう。手に入らないようになるとすれば .. どうするのが良いのだろう?

    だいたいの性能は、最大 2 回転/秒(120RPM) で トルクは 0.25 kg・cm 程度。( 静止トルクはこの 4 倍ぐらい)。120RPM ぐらいまでで これ以上のトルクがあるものを探せば良い。

    ダブルギヤボックス

      4つのギア比を設定できる。その中に 114.7:1 のギア比があり 115 RPM / 0.8 kg・cm だそうだ。

      車軸の位置は 2 通りあるが、114.7:1 のとき 車軸の位置は外側になるので、問題なさそう。

    ツインモータギアボックス

      227 RPM / 0.42 kg・cm 。少々早く トルクが少ない。

      車軸の位置が良さそう。

    このあたりの ギアボックスが 速度・トルクの面で使えそう。これが使える以上他のものを探す必要はないぐらいに思える。モータは最大 3V 。逆回転が必要なので、フルブリッジ(モータドライバ)も必要。

    問題は回転速度検出だが、中間のギアが露出しているのだから、ストライプ状に塗って、反射型フォトリフレクタ を使えば良さそうな気がする。ただしノウハウがないので どうやるのが適切なのかは分からない。

    あと、DC モータなので、(電圧ではなく)電流をモニタしていれば、回転数は分かるのではないか? 10000 RPM というと 166 Hz 。この値か その 2倍の周波数で 電流が変化するに違いない。

    モータドライバは、秋月で扱っている BD6211F-E2 が良さそう。正転・逆転 ができて、PWM での 速度制御もできるようだ。ボリュームを使った 電圧での回転制御すら可能で なかなか興味深い。

    (参考) モーター性能比較表

      上記のギアボックスは、FA-130 モータを使用している。このモータは ミニ四駆でも使われているので、高性能モータが いろいろ存在する。モータ置き換えも考慮に入れた方が良さそう。

ステッピングモータ制御覚書

    Wikipedia にも 項目があり 制御の仕方の説明がある。

    回し方の基本方式は、一相励磁 と 二相励磁。二相励磁は、2 個のコイルに同時に電流を流すやりかたで、トルクが強いらしい。なら基本はこれ?

      一-二相励磁 というのもある。二相励磁のタイミングを変えて 一相励磁の状態が間にある感じ? なめらかになるだけで、トルクは変わらない?

    回し方の原理は簡単だが、負荷が大きすぎたり、パルス周波数が高すぎると脱調する。脱調しないように制御することが重要。

    負荷が小さければ、電圧は高くなくて良いはず。5V でも 制御の実験はできるかも知れない。DC-DC コンバータ自体が怪しげなら、5V でとりあえず制御の基本コードを作るという方針でも良いかもしれない。

    さて、脱調しないようにするには、回転のスタートとストップで 加速度が一定になるような 制御が必要。ものには慣性があるから 当然だ。また、どこまでも速度を上げられるわけではないから、ある速度に達したら その速度を維持する。

    基本はこういうことだが、倒立振子だから扱うものは基本的に加速度。定めた加速度を発生させるような 機能になっていないといけなさそう。

    それを守った上で、目標の速度にしたりすれば良い? あとは移動距離。方向転換とかは、移動距離をベースにした制御?
posted by すz at 00:06| Comment(0) | TrackBack(0) | 日記

2012年05月14日

ACT8796

興味深い電源IC を見つけたのでメモ。

    Android Tablet に使われている電源用IC として Active-Semi の IC がある。

    ここ を見ると各プロセッサー向けにカスタマイズした電源ICを提供しているようだ。

    所有している Tablet の Novo7 Paladin は、JZ4770 という MIPS の チップを採用しているが、それ用の ACT8600 というチップを使っている。これの データシートがダウンロードできるので見てみた。

    なんと 1つの昇圧 DC-DC コンバータ(OTG 用 5Vに使う)、3つの降圧DC-DC コンバータ(3.3V , core電圧 , DRAM 電源?)、5 つの LDO(レギュレータ) を持っていてさらに バッテリー(1セル)の充電まで出来る。すべての電源をこれだけで管理できて、結構すごいと思ったのだが、Tablet の中に入っているもので、電子工作には無関係。単独で入手もできそうにない。

    では、入手可能で データシートも入手できるものはないかと探したら、1つ見つかった。それが ACT8796 。パッケージは、QFN24 (0.75mmピッチ) で 敷居は高いものの電子工作で一応使える範疇。

    チップ自体は、taobao で入手できる。値段はいろいろあって どれが妥当なのか 判別しがたいが 10個 42元(600円ぐらい?)のところ がある。

    さて、このチップの機能は 3 つの降圧DC-DC コンバータと 3つの LDO 。そして、(LDO も含め)それぞれの出力を、I2C で設定できるようだ。AVR と組み合わせて 実験用の 電源にするとか ... バッテリー駆動の なにかを作るときの電源にするとか ... なにか有用な使い方があるかも。

PowTech PT1502

    ついでに電源用 IC PT1502 のメモ

    これも taobao で購入可能 + データシートあり。

    こちらは、バッテリー充電 機能に加えて 降圧 DC-DC コンバータ + LDO 2 つ。I2Cなどはない。充電関係では、AC アダプタ , USB を区別できる。あと Power-on 回路。AVR とかをバッテリーで 制御するには便利かも。 降圧 DC-DC コンバータ は 1.2V とか core 電圧向きで、ARM とか FPGA/CPLD でも使えそう。

    降圧 DC-DC コンバータの電圧は、FB の分圧抵抗で決める。LDO1 は 3.0V 固定。LDO2 は、(ピン設定で) 2.5/2.8/3.0/3.3V から選べる 。

      PowTech PTxx を買うなら、taobao の この店が 良さそう。PT1502 だけでなく、1セル充電IC(PT6181) , LED 向け昇圧IC(PT4181) , 降圧 DC-DC(PT1281 等) を扱っている。ただ、値段が 安すぎで 不安 -- なにか誤解しているかも。

posted by すz at 23:26| Comment(0) | TrackBack(0) | 日記