2018年03月17日

iCE40 を使ってみる

手始めに iCE40 UP5K で 以前作った MachXO2 QFN32 用の Verilog ソースを論理合成してみようと思う。iCE40 は、iCEcube2 というツールを使う。論理合成エンジンは、Synplify Pro と Lattice LSE で Diamond と同じである。だが、iCE シリーズは、買収した SiliconBlue Technologies が開発元であり、なにかと違うものと思われる。

    iCEDIP-01t.png

    icedip.png

alu181

    // iCEDIP24 modified 74181 iCEDIP24
    // 37 B0 1 24 VCC
    // 43 A0 2 23 A1 36
    // 44 S3 3 22 B1 35
    // 45 S2 4 21 A2 34
    // 46 S1 5 20 B2 32
    // 47 S0 6 19 A3 31
    // 48 Cn 7 18 B3 26
    // 2 M 8 x 17 N.C. 25 (/P)
    // 3 F0 9 16 Cn+4 21
    // 4 F1 10 x 15 N.C. 20 (/G)
    // 9 F2 11 14 EQ 19
    // GND 12 13 F3 18

大昔の 4bit Arithmetic Logic Unit(ALU) 74181 である。本物は今や超高価で取引されている。せっかく 24 pin にしたのだから互換品を作ってみよう。ただし /P と /G は、carry-lookahead generator 74182 と共に使用するもので、パス。
ALU は、FF を持たないただの組み合わせ回路で非同期に動作する。
1) alu181,v を デザインファイルに入れて、論理合成 -- 問題ない。
2) pin Constants Editor で ピンアサインを変更。

    不思議なことに、制限がある信号が出てきた。とりあえず割り当てられたものをロックして、再度やりなおすと 制限がなくなっている。さらに不思議であるが、とりあえずロックして pcf ファイルを作成。(alu181.pcf: 以降使用可能)
acc281

    // iCEDIP24 modified 74281 iCEDIP24
    // 37 A1 1 24 VCC
    // 43 A2 2 23 A0 36
    // 44 RS1 3 22 CP 35
    // 45 RS0 4 21 SIO0 34
    // 46 RC 5 20 AS0 32
    // 47 SIO3 6 19 AS1 31
    // 48 A3 7 18 AS2 26
    // 2 Cn 8 17 M 25
    // 3 N.C. 9 x(/G) 16 F0 21
    // 4 Cn+4 10 15 F1 20
    // 9 N.C. 11 x(/P) 14 F2 19
    // GND 12 13 F3 18

74281 は ALU にレジスタが付いたアキュームレータで、74181 より もっとレア。... というか現物がない!
こちらは、同期回路でありクロックがある。さて、どうなる?

1) acc281,v を デザインファイルに入れて、論理合成 -- 問題ない。
2) pin Constants Editor で ピンアサインを変更。

    こちらも何か変? だが、ピンアサインは成功した。(acc281.pcf)

    ワーストで 79.5 MHz で動作すると出た。

sram128

    // iCEDIP24 2K RAM/ROM iCEDIP24
    // 37 A7 1 24 VCC
    // 43 A6 2 23 A8 36
    // 44 A5 3 22 A9 35
    // 45 A4 4 21 /WE 34
    // 46 A3 5 20 /OE 32
    // 47 A2 6 19 A10 31
    // 48 A1 7 18 /CE 26
    // 2 A0 8 17 D7 25
    // 3 D0 9 16 D6 21
    // 4 D1 10 15 D5 20
    // 9 D2 11 14 D4 19
    // GND 12 13 D3 18

かつて 24pin の SRAM や PROM があった。8bit 幅で 2KB である。これを再現する。が、MachXO2-256 は EBR がないので、128B までしか生成できなかった。
とりあえず、128B のものがどうなるか?

1) sram128,v を デザインファイルに入れて、論理合成 (RAM_USE_CLK を指定)。
2) 2KB SRAM 用 ピンアサイン sram2k.pcf を使用。


    Device Utilization Summary
    LogicCells : 3/5280
    PLBs : 3/660
    BRAMs : 1/30
    IOs and GBIOs : 18/36

    RAM は、非同期である。が、それでは FPGA では具合が悪い。同期SRAM というものもかつてあったが、簡易的に CE ↓ で動作するように変更した。(RAM_USE_CLK)。これだと全然問題なく、EBR を使用する。

    で、RAM_USE_CLK を undefine すると、WE ↓ で書き込みをするが、非同期にデータを出力する。

    Device Utilization Summary
    LogicCells : 2181/5280
    PLBs : 329/660
    BRAMs : 0/30
    IOs and GBIOs : 18/36

    なんだかものすごいことに。128 x8 だから 1024 個の D-FF で作れるのだが、実際に 1024 個の LUT を D-FF として使用している。
    MachXO2 は 256 なのに、この 1024 bit が入る。これは LUT に機能追加して 4bit レジスタに出来るからである。こういう工夫をしてもザイリンクスの方がさらに少ない LUT 数で実装できる。iCE40 は、単純な LUT 構造なのかも知れない -- 要調査である。

    さて、他にオプションがある。RAM_INCLUDE_DAT - 初期値つきである。うまく出来ないと今後困る。また、書き換え不可にして、rom 化も試さなければ。rom 化では、普通は構造が変わる。組み合わせ回路になり、LUT あたり 16bit 分実装する。EBR を使うようにするには、何か指定がいる。

      rom は、論理的には case 文で書くようなロジック。case 文の中身を 別ファイルにして `include するという方法はある。

    最初の問題は、データファイルの読み込ませ方。ググると 「iCEcube2 User Guide」に書いてあるとのこと。$readmemh を使えば良いらしいが、うまくいくのかどうか?
     - 実は思うように行ってない。後回し。

sram2k

    まずは単純に サイズを大きくしてみる。

    Device Utilization Summary
    LogicCells : 3/5280
    PLBs : 3/660
    BRAMs : 4/30
    IOs and GBIOs : 22/36

    クロックに関する情報を期待したのだが、見つからない。

    さて、$readmemh だが、
     Cannot find data file rom_data.mem for task $readmemh
    要するに、どこにファイルを置くのかという問題。面倒なことに warning であって ファイルがないと初期値が入らないだけ。Synplify Pro だと write 禁止にすることで、0 を出力するだけの回路になって アドレスが削除された結果になる。

    ファイルを プロジクトディレクトリの上階層に置いて、ファイル名を "../rom_data.mem" とすることで、上手くいった。EBR を 4 つ使った 2KB の ROM も OK 。ただし、繰り返しデータのパターンだと EBR が1つになったりする。

    他にツールで 初期値を設定する方法もあるらしい。物理的な EBR を指定しないといけないが、データだけを変更して使うような用途では、良いかも知れない。

    つでに SPRAM もやってみた。SPRAM は、16K x 16bit のファンクションブロックが4つ。初期化できるかどうかは分からない。

clock1

    // iCEDIP24 iCEDIP24
    // 37 1 38 24 VCC
    // 43 2 23 36
    // 44 3 42 22 35
    // 45 DIG1 4 21 E 34
    // 46 A 5 20 D 32
    // 47 F 6 19 DP 31
    // 48 DIG2 7 18 C 26
    // 2 DIG3 8 17 G 25
    // 3 B 9 16 DIG4 21
    // 4 10 15 BTN_UP 20
    // 9 11 14 BTN_DN 19
    // GND 12 13 BTN_SEL 18

ボタン操作がある時計である。表示は 7セグメントx4 ダイナミック点灯。論理合成できるかどうか?というのが最初のポイント。
ピンアサインは、4桁の7セグに合わせてみた。4桁の7セグは大きさが2種類ある。ピンアサインは同じだが幅が、400 mil と 600mil 。400 mil の裏側に付けるイメージで割り当て。

1) 4つのファイル clock1,v button.v seg7dec.v time_counter.v を使用
2) clock1.pcf を指定

    No support for synthesis of mixed edge and level triggers. (Lattice LSE)
    Can't mix posedge/negedge use with plain signal references (Synplify Pro)
      → always @(R, negedge CLK_128HZ)

    ダメですな。どういうつもりで作ったか思い出さないと、先に進めない。当時 posedge/negedge を気にしないで作ってたような ... これがダメなら、どう対応するのが良いかちゃんと調べないとまずい。

    クロック関係のメモ:
    8MHz などのクロックを negedge で動かし分周し、128Hz や 1Hz を生成して、新たなクロックソースにしている。 CLK_128HZ は、posedge と negedge を混ぜて使っているようだ。

    上記の問題だが R はリセットのつもりなのだが、外してしまっても良さそうなので、外すと OK だった。混乱した理由は、ファイルのセーブをちゃんとしてから論理合成しないといけないという点。ファイルの編集はただのエディタであった。なお、posedge と negedge を混ぜることは問題ないようだ。

    ボタン:
     チャタリング対策をしてある。シフトレジスタに 128Hz でボタンの HL を記録していって、0000 または 1111 で状態遷移。このためにクロックが必要なのであった。
    ボタンは、プルアップにして −スイッチーGND と接続する。pcf ファイルは、

      set_io BTN_UP 20 -pullup yes

    こんな風に記述する。

    XIN と XOUT :

    時計なのだから、水晶発振器を XIN につなぐのが、ひとつの方法。XOUT は XIN の反転出力。うまくすれば、水晶発振子をドライブできるはずである。その際に入力のディレイとか設定がいるかも知れない。

    また実験では、内蔵オシレータを使ってみようかと思う。10kHZ で十分だが、HFOSC にプレスケーラがあるので 48MHz/8 = 6MHz を使ってみる。

    Device Utilization Summary after Packing
    LogicCells : 235/5280
    PLBs : 38/660
    BRAMs : 0/30
    IOs and GBIOs : 17/36
    LFOSCs : 0/1
    HFOSCs : 1/1

    うまくいった。

    ドライブ能力の問題:
    1つのピンの能力は 3.3V 8mA である。これだと、DIGx ピンの制限がネックになるため LED 1つへの電流が 1mA になるようにしないといけない。それでダイナミック点灯させるのは厳しいので、ドライブ用に トランジスタを付けたい ... となるとカソードコモンを使用して DIGx の論理を逆転させる必要がある。結局点灯させたいときは、両方 H にする。アノードコモンならば、逆。両方 L で点灯。PCH MOSFET を使う。

    時計用 4桁 7セグ:
    clock7seg.jpg
    aliexpress で探すと、中央に 2dot がある 時計用 のものがある。5 個セットとかになってしまうが、安価に入手できる。ピンアサインは 12ピンのものは互換性があるようだ。小数点もあるものは、2桁め 小数点も含めて 3 dot 同時点灯になる模様。(”7 Segment Clock Digit” で検索)

      TM1637mod.jpg
      ちょっと逸脱するが、モジュールも安価に買える。TM1637 を使用したものでユーザガイドも手に入る。

dac

    DSD64 は、44.1kHzの64倍=2.8224MHz での 2値データらしい。ΣΔ DAC なら PCM データを 64 倍にオーバーサンプリングして、ΣΔ変調すれば、良さそうである。この程度であれば、周波数的に難しいことではない。コンポジット出力などでは、14.318MHz で データを出力しなければならない。28MHz 8bit ぐらいの性能が必要。FPGA が 4倍の 112 MHz で動くかどうかすら怪しく、多値出力をしないといけないのだが、R2R ラダーは精度を取るのが難しいらしい。3bit あるいは 4bit で R2R を作って、ディザでごまかす程度ならなんとかなるかも知れない。

      液晶を使う場合、SPI 液晶が扱いやすい。しかし、SPI では書き換え速度を速くできない。パラレルを使えば良いのだが、信号線が増えて面倒。CR で扱えるのであれば コンポジット出力も悪くないとは思う。

    さて、こういうことを考えて、ΣΔ DAC を作ってみよう。... というのを過去にやった。今はソースだけ残っていて、思い出すところから始めないと。

dac_sd.v

    とりあえず論理合成はできる。16bit を外部から入力して Frequency: 73.81 MHz だそうだ。しかし MODE とか何のつもりだったのか?

dac_sd3.v

    こちらは、8bit を外部から入力して 3bit 出力。 Frequency: 116.16 MHz だそうだ。
    14MHz の 8倍 クロックが使えるかも。

    中身は思い出せない。今回はクロックの見積もりだけ。

    アンプについて:
    AD8091.png
    R2R ラダーは、抵抗の精度が必要な上に、FPGA の出力ポートの抵抗値も考慮する必要がある。そうすると、1KΩ以上の抵抗を使用したい。となると今度はアンプが必要になる。OP アンプを ボルテージフォロワで使えば良いのではないかと思うのだが、それなりに帯域が必要。小さいものを探すと SOT23-5 のものがある。aliexpress だと 110MHz の AD8091ARTZ が見つかった。安価に入手できなくなる可能性があるので、mouser でピン互換のものを探すと MCP6L91 が安かった --- ただし帯域は 10MHz。NJM2741F も安いがピン互換ではなかった。他に TSV991 (20MHz) など。

    R2R-DAC.png
    この回路そのもの。アンプに抵抗などいらないので、配線は簡単である。R は、誤差 1% のもので 1.5K, 3K を使おうかと思っている。

    LM321.png
    サウンドの場合は、もっと安いオペアンプが使える。aliexpress では、LM321 や MCP6001T が安価。ただし、ピンアサインが違う。(MCP6001T として売ってるのは AFxx というマークであり MCP6001U の模様)

    イヤホンや小型スピーカーを鳴らしたいのであれば、aliexpress で CKE8002B がとにかく安い。
    CKE8002.png

    メモ:
     ・https://opencores.org/project,sigma_delta_dac_dual_loop

    ΣΔ DAC について VHDL で作成されているが、まともそうな作例があった。

    オーバーサンプリングについて甘くみてたかも。

      考え方として、データの間に 0 を挿入したものを処理前データとする。64 倍なら、1 つのデータと 63 個の 0 。それを LPF にかけると ... 補間されたデータが出てくる。LPF には FIR フィルタというものを使うが、タップ数が非常に多くなる。64 タップでも 1つしか実データがないのだから当然だ。FIR フィルタは、タップ数分の 積和演算が必要で オーバーサンプリングの度に行わなければならない。
      まっとうにやるとすごい量だが、63 個は 0 なので計算する必要がない。結局のところ タップ数 / 64 の計算で済む。... だが、タップ数がべらぼうに多くなる。128 タップ程度では 2 つの実データを含むだけである。32 個分で 2048 とか?
      実をいうと ここ 見て自分の理解を書いているだけなのだが、4 倍オーバーサンプリングで 128 タップ = 32個の実データとなっている。周波数特性がどうのという話だろうから、64倍だろうと、32個の実データで良いのだろうと想像した。
      44.1 kHz の 64倍 で 32 回の 積和演算を 1つの乗算器で行うならば、90 MHz で毎回計算しないといけない。DSP 16x16 は 最大 50 MHz だから無理ですな。
      しかし別のヒントがあるかも知れない。「ポリフェーズフィルタの基本を知る」 これを理解しなければならないようだ。
      あるいは、3bit R-2R DAC 出力 にして、16 倍オーバーサンプリングにまで落とすとか。これなら実現可能である。

      オーディオは上記のような話だが、コンポジット信号はどうなのだろうか? 
      「14.314MHzでV、U、−V、−Uを順番に出力する」ということなので、サンプリングデータ間に関係がないのである。波形全体に LPF をかけるのはダメのような。さらに 8 倍クロックで動かすとして 8 クロックで V なら V を出力し、前後のことは知らないということで良さそうな気がする。それならば波形データを持っていても良い。3bit DAC + ディザなら 5clock 分で 15bit だ。5 倍クロックにしよう。元の色空間が 12bit だけとすれば、4096 x 16bit = 8KB で済む。VとUが独立ならば、例えば 16 x 16bit + 256 x 16bit とか。
      もはやΣΔは関係ない世界なのであった。

      CVBS.png
      ついでなので書いておくと、Nanopi DUO などは、最終段に 50Ωと LC LPF が入っている。

他にもいろいろ設計したのがあるが、とりあえずここまで。

 ・icedip-samples-01.zip


さて、ネタが溜まってくると基板を設計したくなる。
まずコンポジット信号のお勉強から。

信号レベル 1Vpp (-40 IRE 〜 100 IRE)
水平同期 -40 IRE 〜 0 IRE
カラーバースト -20 IRE 〜 20 IRE
信号レベル 0 IRE 〜 100 IRE

どうも 1Vpp を -40 IRE 〜 100 IRE になるよう単位を決めているようだ。バースト信号などを切りの良い値にするため 4bit の R-2R DAC にして、0 - 14 を使うのが良さそう。そのうち 4 - 11 の 8レベル をY信号に割り当てる。

カラーサブキャリア周波数: 3579545Hz これを 1T とする。
水平期間 227.5T
  水平ブランキング 39T
    0IRE 6T
    水平同期パルス(-40IRE) 17T
    0IRE 2T
    カラーバースト(10 -20 20 ... 20 -10 RE) 9T
    0IRE 5T
残:188.5T
 画像範囲  140T (apple2) , 128 ? (SFC) 2dit/T ?

間違ってるかも知れないが、おおむねこんな感じ。あと、全く同じタイミングで画像を出力すると、1ライン毎に 0.5T ずれて表示される(らしい)。

ノンインターレースでは、1フレーム 262H で 20H の垂直ブランキングから開始。画像は 242H まで。
 画像範囲  192H (apple2) , 224H or 239H (SFC)

めんどくさくなったので、とりあえずここまで。まず知りたいのは、信号レベルの話。

Y信号は、4 - 11 の 8レベル を割り当て、2dot/1T で表示する。
色差信号は、V、Uを 1T 毎に生成して、V、U、−V、−Uを順番に Y信号に加算?
 - 絶対値を 5 レベルまでにしないと オーバーフローが起きる。
 - 負の値もあるので、 9 レベル

さて、R-2R のレベルは? ボルテージフォロワなら、0 - 3.3 x 15/16 = 3.094
出力を 1/3 にしないといけないから、アンプの出力に 100Ω を入れて 50Ω の 抵抗でプルダウン。

普通のオペアンプの使い方だと、RI = 30kΩ , RF = 10kΩ とかで ゲインを 1/3 にして 出力の 100Ωは入れない。また反転だから、値の扱いを逆にする。

どっちが良いのだろうか?

次、ディザ。端数だけ 0/1 で表現するなら 5 clock で 5 レベルしか表現できない。Y は 8x5 = 40 階調、U,V は 45 階調ということに。
だいぶ半端な感じである。フレームバッファは 8bpp にしてパレットを使うというのが良いかも知れない。
参考)
 ・ビデオ信号計測・生成の基本
 ・RS-170A NTSCビデオ信号タイミング規格の概要

だいぶ作れそうな気がしてきた。次のお題はクロック。14.314 MHz の水晶を 元として 内蔵 PLL を 使い 5倍にして、71.57 MHz をメインクロックにすれば良いのだろうか? そうしたときサウンドはどうするのだろう?
71.57 MHz / 44.1 kHz = 1622.9 だから 1623 が割と近い。だが、3 x 541 にしか素因数分解できないく、扱いにくい。1622 にしても 2 x 811。1624 なら、7 x 8 x 29 うーん。
1625 まで行くと 5 x 13 x 65 。
だいぶずれるが 1620 なら 4 x 5 x 9 x 9 。そのかわりサンプリング周波数が 44.179 にまでなってしまう。0.18 % の誤差。こんなので作れるのだろうか? 予定と随分と違う −不安になって来た。

あるいは、48kHz 系。8kHz や 16,24kHz サンプリング周波数に対応できる。
71.57 / 1488 = 48.098 (0.2% の誤差) , 1488 = 16 x 3 x 31

別に高性能なものを作りたいわけではないので、こちらの方が良いかも。
参考)
  ・素数判定ツール

追記)すごく参考になりそうな所を見つけた
 ・FPGA1ピンでNTSC出力をする方法
 ・FPGA 1pinで NTSCを出力する方法 ソース付き (最終)

    ・48fsc(171.8MHz)で動作させる。
    ・ΔΣADPCM(1bit)
    なるほど、計画したのは、20fsc(71.57MHz) だから倍ほどのクロック。FIR フィルタを使わなければ、実現できるのかも知れない。ソース付きか、勉強させてもらおう。

    他に、「NTSCベースの44.056 kH」? 14.314 MHz の 1/325 ということ?

 ・FPGA活用回路&サンプル記述集(3) ―― ビデオ信号処理回路

    これもチェックしておこう。

他にこういう説明を発見
「NTSC は 858x525 の信号(ITU-R BT601 の場合)で構成され、このうち帰線消去期間(垂直・水平同期信号、カラーバースト信号、文字放送信号、放送局制御信号)などを除いた画像表示領域が 720x480 の大きさである。 しかし、実際の TV では 720x480 の情報を全て表示できるものは少なく、大抵は 686x456 程度 ...」

    メモ:
    14.314 MHz のクロックを基準にすると、1 ラインは、910 クロックである。水平ブランキングに 39*4 クロック必要なので、754 クロック。 このうち 686/858 が表示できるということは、727.5 クロック。余白が左右 13 クロック必要と。2 クロックで 1 dot 表示することにするならば、363 dot ぐらいが限界。また、ライン数はノンインターレースで 228 程度。全部で 262.5 ラインあるが、垂直同期に 9 or 10 ライン使用し、さらに文字放送などで 12 ライン分つかう。262 - 21 = 241 あるが 228 ということは、上下 13 ラインは表示しないほうが良さそうということか。



その他、簡単なものだと、ADC とかも可能。
RD1066.png
 ・https://github.com/mcmayer/iCE40/tree/master/adc
Lattice 社がリファレンスデザインを出している。差動入力があれば FPGA を選ばないようだ。
リファレンスデザインは、PWM で電圧を出力して 入力と比較するやり方。
 ・https://github.com/mcmayer/iCE40/tree/master/adc

UP5K は SPRAM がある。フレームバッファとか表示系が簡単に作れそう。未だにコンポジット入力の液晶モニタが安価で買える。4.3 inch なら $12 程度で 解像度はたぶん 480 x 272 。 16bpp だと無理だが、8bpp ならなんとか。
http://fpgapark.com/ntsc/ntsc.htm
こういうのを作っている人もいるし出力は作れそう。
http://bitluni.net/esp32-composite-video/
ただ ESP32 で結構なことが出来るのである。DAC でコンポジット出力が可能! 白黒のみみたいだが。

    car_display.jpg
    車のバックモニタ用として、まだ現役で安価に買える。写真のものは 4.3 インチで $11.84 。電源は 12V 、2系統の入力がある。いずれはなくなって行くのだろう。よく知らないが、代わりにデジタルのものが出てくるのだろう。そうなれば ... かえって簡単になるのかも知れないが。
     ・このショップが安いようだ。4.3 inch $12 , 5.0 inch $16 ぐらい。

その他メモ
 ・https://github.com/grahamedgecombe/icicle

Icicle is a 32-bit RISC-V system on chip for iCE40 HX8K and iCE40 UP5K FPGAs.

https://github.com/aventuri/iceProgrammer
i used direct memory map access for GPIO I/O, suitable for A10 A20 Allwinner

https://github.com/nesl/ice40_examples
posted by すz at 12:58| Comment(0) | TrackBack(0) | MachXO2
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/182673517
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック