cygwinのruby + fiddleでFT232RLのBit-Bang modeを使う

 いろいろと作業をしていると、ある決まった変化をする信号を出力したくなることがあります。たぶん。そういうときにFTDIのFT232RLというチップを使うと便利です。
 Windowsの場合、C#のライブラリを使ってプログラム書いてもそれなりに簡単に書くことが出来ますが、cygwinrubyで動かせるようになるとよりお手軽かな、と思って試してみたところ問題無く動かせましたので、簡単にメモとして残しておきます。


 FT232RLの実装された基板は秋月電子で販売されているFT232RL USBシリアル変換モジュールキット: 半導体 秋月電子通商-電子部品・ネット通販を使用しています。実験で使用する場合、同じく秋月電子などで販売されているブレッドボードを使うと簡単に実験することが出来ます。


 ruby 2.0から、*.dllや*.soなどのダイナミックリンクライブラリを扱うためのライブラリとしてfiddleが使えるようになっています。こちらを使ってftd2xx.dllを使用するためのコードを作成します。

require 'fiddle/import'

module FiddleFTD2xx
  extend Fiddle::Importer
  dlload "ftd2xx.dll"

  extern "unsigned int FT_Open(int, void*)"
  extern "unsigned int FT_Close(void*)"
  extern "unsigned int FT_SetBaudRate(void*, unsigned int)"
  extern "unsigned int FT_SetBitMode(void*, unsigned char, unsigned char)"
  extern "unsigned int FT_GetBitMode(void*, unsigned char*)"
  extern "unsigned int FT_Write(void*, void*, unsigned int, void*)"
end

class FTD2xx
  attr_reader :handle, :write_length

  def initialize
    @handle = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP)
    @write_length = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT)
  end

  def open(idevice)
    FiddleFTD2xx.FT_Open(idevice, @handle)
  end

  def close
    FiddleFTD2xx.FT_Close(@handle.ptr)
  end

  def baudrate=(rate)
    FiddleFTD2xx.FT_SetBaudRate(@handle.ptr, rate)
  end

  def setBitMode(ucmask, ucmode)
    FiddleFTD2xx.FT_SetBitMode(@handle.ptr, ucmask, ucmode)
  end

  def getBitMode
    mode = Fiddle::Pointer.malloc(Fiddle::SIZEOF_CHAR)
    FiddleFTD2xx.FT_GetBitMode(@handle.ptr, mode)
    return mode.to_i
  end

  def write(data)
    write_data = [data].pack("C*")
    FiddleFTD2xx.FT_Write(@handle.ptr, write_data, 1, @write_length)
  end
end

 とりあえず必要な関数だけしか書いていません。必要に応じてftd2xx.hを見て追加しています。
 こちらをftd2xx.rbとして保存し、以下のようなソースコードで呼び出してBit-Bang modeでI/Oを制御することが出来ます。

require 'ftd2xx'

ftd2xx = FTD2xx.new

ftd2xx.open(0)
ftd2xx.setBitMode(0xff, 0x0)
ftd2xx.setBitMode(0xff, 0x1)

wait_time = 0.1

1.upto(10) {
  0.upto(6) { |i|
    data = 1 << i
    ftd2xx.write(data)
    sleep wait_time
  }
  7.downto(1) { |i|
    data = 1 << i
    ftd2xx.write(data)
    sleep wait_time
  }
}

ftd2xx.write(0)
ftd2xx.close

 FT232RLのD0~D7に抵抗とLEDを付けて、上記プログラムを実行すると以下のようにLEDが点滅します。

 こんな感じで簡単に信号を変化させることができるので、ちょっと思い付いたことや簡単なICの制御などに使用すると便利です。