FPGA SPI Bridge Panel(1)Arduinoスケッチ


2018/08/05 追記:OLEDモジュールを接続しない場合は、SSD1306Wire.h関連のコードを削除したスケッチを使ってください。
2018/06/09 追記:OLEDモジュールにIPアドレスを表示するようにしました。OLEDモジュールを接続しなくてもスケッチを変更する必要はありません。

 

 

Google Playに「GUI Maker for Avalon Bus – FPGA SPI Bridge Panel」を公開しました。

GUI Maker for ESP8266 & ESP32 – Python Inst. Panel」に「FPGA SPI Bridge Console for Avalon Bus」の機能を追加したものです。アンドロイド端末からFPGAを操作するGUIを短時間で作成できます。

「GUI Maker for ESP8266 & ESP32 – Python Inst. Panel」と同様にグラフ付きのGUIも作れます。

Google Playの説明文をこちらにも載せておきます。

Qsysのオンライン・マニュアル「Embedded Peripheral IP User Guide」の「SPI Slave/JTAG to Avalon Master Bridge Cores」に書かれているように、JTAG以外にSPIでも外部からFPGA内部を操作できます。
Arduino、Raspberry PiなどからSPI経由でFPGAに実装した回路をアクセスできるのです。Nios II CPUを組み込まなくてもいいんです。
例えば、ESP-WROOM-32をWifiーSPI変換器として使えばアンドロイド端末からWifi経由でFPGAを操作できてしまいます。

  アンドロイド端末 →(Wifi)→ ESP-WROOM-32 →(SPI)→ FPGA


このアプリは「Python Inst. Panel - GUI maker for ESP8266 & ESP32」と同様に、ボタン、タイマー、グラフ等を貼り付けて処理をPythonで記述することで、FPGA用の操作パネルを簡単に作ることができます。
GUI関連は「Python Inst. Panel - GUI maker for ESP8266 & ESP32」の説明文とこのアプリに入っている「SPI Bridge Console」と「PlotView Sample」のPythonスクリプトを見てください。
Pythonスクリプトの中で次のメソッドを使ってFPGA内のAvalonバスをアクセスします。

byte[] WriteBytePacket(UInt32 addr, byte data, int timeoutInSec)
byte[] WriteUInt16Packet(UInt32 addr, UInt16 data, int timeoutInSec)
byte[] WriteUInt32Packet(UInt32 addr, UInt32 data, int timeoutInSec)
byte[] WriteBytePacket(UInt32 addr, byte[] dataBytes, bool isIncremental, int timeoutInSec)
byte[] WriteUInt16Packet(UInt32 addr, UInt16[] dataArray, bool isIncremental, int timeoutInSec)
byte[] WriteUInt32Packet(UInt32 addr, UInt32[] dataArray, bool isIncremental, int timeoutInSec)
byte ReadBytePacket(UInt32 addr, int timeoutInSec)
UInt16 ReadUInt16Packet(UInt32 addr, int timeoutInSec)
UInt32 ReadUInt32Packet(UInt32 addr, int timeoutInSec)
byte[] ReadBytePacket(UInt16 size, UInt32 addr, bool isIncremental, int timeoutInSec)
UInt16[] ReadUInt16Packet(UInt16 size, UInt32 addr, bool isIncremental, int timeoutInSec)
UInt32[] ReadUInt32Packet(UInt16 size, UInt32 addr, bool isIncremental, int timeoutInSec)

以下は、ESP-WROOM-32用のOLEDありのスケッチです。

#include <SPI.h>
#include <WiFi.h>
#include <Wire.h>
#include "SSD1306Wire.h"

/* Set these to your desired credentials. */
//const char *ssid = "ESPap";
//const char *password = "thereisnospoon";

const char* ssid     = "your-ssid";
const char* password = "your-password";

WiFiServer server(2002);
WiFiClient client;

#define SPI_BUF_LEN 1024
byte spiBuf[SPI_BUF_LEN];
byte spiReadBuf[SPI_BUF_LEN];

SSD1306Wire display(0x3c, 21, 22);

void setup() {
  Serial.begin(57600);

  SPI.begin();
  SPI.setFrequency(24000000);
  SPI.setDataMode(SPI_MODE1);
  SPI.setBitOrder(MSBFIRST);
  pinMode(SS, OUTPUT);
  digitalWrite(SS, HIGH);
  
//  Serial.println();
//  Serial.print("Configuring access point...");
//  /* You can remove the password parameter if you want the AP to be open. */
//  WiFi.mode(WIFI_AP);
//  WiFi.softAP(ssid, password);
//  IPAddress myIP = WiFi.softAPIP();
//  Serial.print("AP IP address: ");
//  Serial.println(myIP);

  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  //WiFi.mode(WIFI_STA);  // Disable Access Point
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());  
  server.begin();
  Serial.println("Server started");

  display.init();
  display.flipScreenVertically();
  display.setFont(ArialMT_Plain_16);
  display.drawString(0, 0, WiFi.localIP().toString());
  display.drawString(0, 16, "Server started");
  display.display();
}

void loop() {
  if (!client.connected()) {
    // try to connect to a new client
    client = server.available();
  } else {
    // read data from the connected client
    int n = client.available();
    if (n > 0) {
      //Serial.print("available: ");
      //Serial.println(n);
      if (n > SPI_BUF_LEN) {
        n = SPI_BUF_LEN;
      }
      
      // transfer data to/from SPI
      client.readBytes(spiBuf, n);
      digitalWrite(SS, LOW);
      SPI.transferBytes(spiBuf, spiReadBuf, n);
      digitalWrite(SS, HIGH);

      // return data to client
      client.write(spiReadBuf, n);
    }
  }
}

 
以下は、ESP-WROOM-32用のOLED無しのスケッチです。

#include <SPI.h>
#include <WiFi.h>
#include <Wire.h>

/* Set these to your desired credentials. */
//const char *ssid = "ESPap";
//const char *password = "thereisnospoon";

const char* ssid     = "106F3F28087C_G";
const char* password = "xr84vyms434wt";

WiFiServer server(2002);
WiFiClient client;

#define SPI_BUF_LEN 1024
byte spiBuf[SPI_BUF_LEN];
byte spiReadBuf[SPI_BUF_LEN];

void printBytes(byte *bytes, int bytesSize);

void setup() {
  Serial.begin(57600);

  SPI.begin();
  SPI.setFrequency(24000000);
  SPI.setDataMode(SPI_MODE1);
  SPI.setBitOrder(MSBFIRST);
  pinMode(SS, OUTPUT);
  digitalWrite(SS, HIGH);
  
//  Serial.println();
//  Serial.print("Configuring access point...");
//  /* You can remove the password parameter if you want the AP to be open. */
//  WiFi.mode(WIFI_AP);
//  WiFi.softAP(ssid, password);
//  IPAddress myIP = WiFi.softAPIP();
//  Serial.print("AP IP address: ");
//  Serial.println(myIP);

  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  //WiFi.mode(WIFI_STA);  // Disable Access Point
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());  
  server.begin();
  Serial.println("Server started");
}

void loop() {
  if (!client.connected()) {
    // try to connect to a new client
    client = server.available();
  } else {
    // read data from the connected client
    int n = client.available();
    if (n > 0) {
      //Serial.print("available: ");
      //Serial.println(n);
      if (n > SPI_BUF_LEN) {
        n = SPI_BUF_LEN;
      }
      
      // transfer data to/from SPI
      client.readBytes(spiBuf, n);
      //printBytes(spiBuf, n);
      digitalWrite(SS, LOW);
      SPI.transferBytes(spiBuf, spiReadBuf, n);
      digitalWrite(SS, HIGH);

      // return data to client
      //printBytes(spiReadBuf, n);
      client.write(spiReadBuf, n);
    }
  }
}

void printBytes(byte *bytes, int bytesSize) {
  Serial.println();
  for (int i = 0; i < bytesSize; i++) {
    Serial.print(bytes[i], HEX);
    Serial.print(" ");
  }
}