· 

FT232HにdotnetIoTでSPIは

 

dotnet IoTでFT232Hをいじってみるんやけど、何かがおかしいんよ。

dotnet IoTからのFt232HでSPIを出すってのをやってみようと思う。SPIのターゲットはとりあえず考えない。
で、作成した回路はこんな感じ。
USB電圧を多回転可変抵抗で分圧して、それを基準電圧としてオペアンプの定電圧源回路にぶっこんでいる。これを2回路つくってあって、そのうちの一つをターゲット電圧として、ターゲットに供給するとともにFT232HからのSPIを秋月のFXMA108を使ったレベル変換ICでターゲット電圧ドメインに変換している。4066は可変抵抗で分圧した電圧を供給するか、GNDレベルを供給するかを選択できるようにしてある。これはFT232HのGPIO機能で操作する。
久しぶりのブレッドボードで、ちょっと苦戦した。いや、苦戦というよりは躊躇した。躊躇している時間って冷静に考えると、それは無駄時間。あーでもないこーでもない頭で考えるのならそれを文字起こしすればいいと思う。すっきり取りかかれる、、、仕事なら。今日は仕事じゃないので、躊躇することも許してほしい。
で、苦労の末に電源供給部は正しく動作して、SPIも何となく動作した(dotnet IoTのリファレンスではCSを-1にすれば指定しなないってことになる的な記述があったんだけど、この設定は物理的に存在するピンを必ず指定しないといけないらしいってのを気づくのにクソ時間かかった)んだけど、、、何かが違う。
8ビット送信後SCKが初期状態にならないまま次の8ビット送信が開始されているように見える、、、つまり使えんやん。自分が何か間違っていると思って、dotnet IoTのリファレンスやら見まくった。で、結局のところググってみたところ、こんなのがヒットした。
https://electronics.stackexchange.com/questions/360086/make-ftdi-2232d-do-spi-mode-1-properly-data-seems-1-2-clock-cycle-off
https://forums.adafruit.com/viewtopic.php?t=124869
つまりFT2XXHチップのMPSSEモードでSPIを撃つときはMode0かMode2しかまともに撃てないんだぜってことらしい、、、あかんやん。1バイトづつ撃てばいけるような気もするけど、心が折れた。
今回のソースコードはこちら。
  1. using System.Device.Gpio;
  2. using System.Device.Spi;
  3. using Iot.Device.Ft232H;
  4. using Iot.Device.FtCommon;
  5. namespace ft232h_device_test
  6. {
  7.     class Program
  8.     {
  9.         public static int[]? pins;
  10.         public static GpioController? gpioController;
  11.         public static SpiDevice? spi;
  12.         public static int pin_csn,pin_dummy;
  13.         static void Main(string[] args)
  14.         {
  15.             byte[] txdata=new byte[3]{0x55,0x55,0x55};
  16.             byte[] rxdata=new byte[3]{0x00,0x00,0x00};
  17.             var devices = FtCommon.GetDevices();
  18.             Console.WriteLine($"{devices.Count} available device(s)");
  19.             foreach (var device in devices)
  20.             {
  21.                 Console.WriteLine($" {device.Description}");
  22.                 Console.WriteLine($" Flags: {device.Flags}");
  23.                 Console.WriteLine($" Id: {device.Id}");
  24.                 Console.WriteLine($" LocId: {device.LocId}");
  25.                 Console.WriteLine($" Serial number: {device.SerialNumber}");
  26.                 Console.WriteLine($" Type: {device.Type}");
  27.             }
  28.             if (devices.Count == 0)
  29.             {
  30.                 Console.WriteLine("No device connected");
  31.                 return;
  32.             }
  33.             Ft232HDevice ft232h=new Ft232HDevice(FtCommon.GetDevices()[0]);
  34.             gpioController=ft232h.CreateGpioController();
  35.             pin_dummy=Ft232HDevice.GetPinNumberFromString("D7");
  36.             SpiConnectionSettings settings = new SpiConnectionSettings(0) {ClockFrequency = 100000, DataBitLength = 8,Mode=SpiMode.Mode1,ChipSelectLine=pin_dummy,ChipSelectLineActiveState=PinValue.Low};
  37.             spi = ft232h.CreateSpiDevice(settings);
  38.             pin_csn=Ft232HDevice.GetPinNumberFromString("D4");
  39.             gpioController.OpenPin(pin_csn, PinMode.Output);
  40.             gpioController.Write(pin_csn,PinValue.High);
  41.             pins=new int[4];
  42.             pins[0]=Ft232HDevice.GetPinNumberFromString("C0");
  43.             pins[1]=Ft232HDevice.GetPinNumberFromString("C1");
  44.             pins[2]=Ft232HDevice.GetPinNumberFromString("C2");
  45.             pins[3]=Ft232HDevice.GetPinNumberFromString("C3");
  46.             for(int i=0;i<4;i++){
  47.                 gpioController.OpenPin(pins[i], PinMode.Output);
  48.                 gpioController.Write(pins[i],PinValue.Low);
  49.             }
  50.             OUT1_0V_OUT2_0V();
  51.             Console.WriteLine("Entering test loop");
  52.             while(true){
  53.                 Thread.Sleep(500);
  54.                 OUT1_ON_OUT2_0V();
  55.                 Thread.Sleep(500);
  56.                 OUT1_ON_OUT2_ON();
  57.                 SendSpi(txdata,rxdata,3);
  58.                 Thread.Sleep(500);
  59.                 OUT1_0V_OUT2_ON();
  60.                 Thread.Sleep(500);
  61.                 OUT1_0V_OUT2_0V();
  62.             }
  63.         }
  64.         static void SendSpi(byte[] tx,byte[] rx,int n)
  65.         {
  66.             if((spi!=null)&&(gpioController!=null)){
  67.                 Span<byte> toSend = stackalloc byte[n];
  68.                 Span<byte> toRead = stackalloc byte[n];
  69.                 for(int i=0;i<n;i++){
  70.                     toSend[i]=tx[i];
  71.                 }
  72.                 gpioController.Write(pin_csn,PinValue.Low);
  73.                 spi.TransferFullDuplex(toSend,toRead);
  74.                 gpioController.Write(pin_csn,PinValue.High);
  75.                 for(int i=0;i<n;i++){
  76.                     rx[i]=toRead[i];
  77.                 }
  78.             }
  79.         }
  80.         static void OUT1_ON_OUT2_ON()
  81.         {
  82.             if((gpioController!=null)&&(pins!=null)){
  83.                 gpioController.Write(pins[0],PinValue.Low);
  84.                 gpioController.Write(pins[2],PinValue.High);
  85.                 gpioController.Write(pins[3],PinValue.Low);
  86.                 gpioController.Write(pins[1],PinValue.High);
  87.             }
  88.         }
  89.          static void OUT1_ON_OUT2_0V()
  90.         {
  91.             if((gpioController!=null)&&(pins!=null)){
  92.                 gpioController.Write(pins[0],PinValue.Low);
  93.                 gpioController.Write(pins[2],PinValue.High);
  94.                 gpioController.Write(pins[3],PinValue.High);
  95.                 gpioController.Write(pins[1],PinValue.Low);
  96.             }
  97.         }
  98.          static void OUT1_0V_OUT2_ON()
  99.         {
  100.             if((gpioController!=null)&&(pins!=null)){
  101.                 gpioController.Write(pins[0],PinValue.High);
  102.                 gpioController.Write(pins[2],PinValue.Low);
  103.                 gpioController.Write(pins[3],PinValue.Low);
  104.                 gpioController.Write(pins[1],PinValue.High);
  105.             }
  106.         }
  107.          static void OUT1_0V_OUT2_0V()
  108.         {
  109.             if((gpioController!=null)&&(pins!=null)){
  110.                 gpioController.Write(pins[0],PinValue.High);
  111.                 gpioController.Write(pins[2],PinValue.Low);
  112.                 gpioController.Write(pins[3],PinValue.High);
  113.                 gpioController.Write(pins[1],PinValue.Low);
  114.             }
  115.         }
  116.     }
  117. }
ちなみにうちのLinuxをxubuntu24にクリーンインストールしたらsudo dotnet runってしないとftdiデバイスを認識してくれなくなった。usbadmとかrulesとかいじらんといかんかったような、、、