Arduinoで遊ぶページ

Arduinoで遊んだ結果を残すページです。
garretlab
ムラタ 無線LANモジュール Type YD

概要

ムラタ 無線LANモジュール Type YD」 をArduinoで動かしてみます。このモジュールは村田製作所が作成し、スイッチサイエンスが販売しているモジュールです。mbed用のライブラリが公開されています。このモジュールのことを、SNIC(Serial Network Interface Controller)と呼ぶようです。

また、完璧なデータシートを入手していないので、いろいろ推測も交じっています。継続して更新予定です。最終的にはある程度実用になるものにしたいと考えていますが、いつになることやら。情報をお持ちの方はぜひ教えてください。

TCPクライアントとして、とりあえず、Arduino的な方法で、サーバに接続して、サーバからデータを取得するところまで動くようになりました。

TCPサーバとしても、とりあえず、Arduino的な方法で動くようになりました。

Ardino-1.6.0で動作するようにしました(古いArduinoソフトウェアでは動きません)。Serial周りが変わっていました。⇒割り込みハンドラの利用をやめて、全て、ユーザコンテキストで動くようにしました。試験が不十分です。

現状は、Arduino Due専用です。割り込みハンドラの利用をやめたので、Arduino Unoへの対応が簡単になったと思っています。まずは、レベルコンバータの入手から…

必要なもの

このページで必要なものは以下の通りです。

  • Arduino Due
  • ムラタ 無線LANモジュール Type YD

注意

ムラタ 無線LANモジュール Type YD は、3.3Vで動作するモジュールです。5Vをかけると壊れる可能性があるので注意してください。この実験では、Arduino Dueを利用しました。

このページ(に限らずこのサイトすべてに言えることですが)は、私が動作確認した結果であり、間違っている可能性もあるため、十分注意してください。

現状の問題点など

  • IPアドレス指定でモジュールを設定したとき、DNSサーバの設定方法が不明。
    • DHCPでIPアドレスを取得した場合は、DNSサーバも取得しているようです。(ホスト名を解決するコマンドが正しく動作するためそう判断しました)
    • DNSサーバを指定していないにもかかわらず、ホスト名の解決ができているようです。
  • TCPクライアントとサーバを試しただけ。UDPは未確認です。
  • TCPの状態遷移がいい加減。
  • メモリを大量に使っています。Dueだから大丈夫…→少し削減しました。
  • シリアル通信の割り込みハンドラをかっこよく上書きする方法がわかっていません。ベクタテーブルを書き換えようと思ったら、constと書かれてました。なので、variant.cppを直接書き換えています。このため、Serial1専用となっています。
  • 割り込みをきちんと制御していないので、何か副作用がある可能性があります。→とりあえず、危険そうな部分だけ割り込み禁止にしてみました。
  • バッファサイズがいい加減。
  • 試験が不十分(いつもですが)。

わかったことなど

  • SNIC_TCP_CREATE_SOCKET_REQやSNIC_UDP_CREATE_SOCKET_REQで、ソケットを作成するときの、ソケットIDは、4番からはじまる。
    • 4番から始まるので、ソケットIDを配列の添え字にする場合は注意が必要。
    • ソケットIDは、TCP/UDP関係なく順番に払い出される。
  • 利用可能なソケットは、UDPが4個、TCPが5個。
    • DHCPを利用すると、利用可能なUDPソケット数が1個減り、3個となる。
  • 相手サーバからSNICに送信されたデータは、非同期でArduinoに送信されてくる。なので、
    • 非同期データを処理する必要がある。
    • Arduinoが受信したデータはバッファに保存する必要がある。
    • (何もしないと)そのうちバッファは溢れる。
    • ただし、相手から送信されたデータを受信後、次のデータの送信を支持するために、ACKを送る手順も存在する。
    • SNIC_DATA_IND_ACK_CONFIG_REQを利用する。

ToDo

  • EthernetClientクラス相当の残分作成
  • EthernetServerクラス相当の作成
  • EthernetUDPクラス相当の作成
  • Arduino Unoでの利用
  • 割り込みを使わず、ユーザ空間だけで動作させる。

データシート

スイッチサイエンスのページからリンクされているデータシートだけではプログラムを作成することは、私にはできませんでした。このデータシートを読んでいくと、「Please refer to [murata SNIC Serial Interface Specfication.pdf] for more information.」と書いてあり、検索したところ、少し古いと思われる、データシートを発見しました。mbed用に公開されているライブラリと比較すると、一部動作が異なっているようです。

前述のmbed用のライブラリとWebで公開されているデータシートを参考にして、動作を確認していきます。

概要

Type YDは、シリアルインターフェイスを利用して操作する無線LANモジュールです。ピンは20ピンありますが、実際に利用するのは、そのうちの5本です。また、ピンのピッチは2.0mmと多くのモジュールよりは狭くなっています。どのピンがどの番号なのかはスイッチサイエンスのページに記載があります。電圧は3.3Vです。

Type YDのピン 意味 Arduino Dueのピン
1 VCC 3.3V
2 UART_TX 19(RX1)
3 UART_RX 18(TX1)
5 NRST 20
10 GND GND

このモジュールのピンピッチは2mmです。

プロトコル

ArduinoとType YDの間は、シリアル通信を用います。通信速度は、115200bpsです。Arduinoから送るデータとArduinoが受信するデータのフォーマットは以下の通りです。

送信 受信
7 6 5 4 3 2 1 0
SOM(Start Of Message, 0x02)
1 ペイロード長[0]
1 A ペイロード長[1]
1 コマンドID
サブコマンドID
シーケンス
データ


1 チェックサム
EOM(End Of Message, 0x04)
7 6 5 4 3 2 1 0
SOM(Start Of Message, 0x02)
1 ペイロード長[0]
1 A ペイロード長[1]
1 コマンドID
サブコマンドID
シーケンス
リターン値
データ

1 チェックサム
EOM(End Of Message, 0x04)

チェックサムは、ペイロード長[0]とペイロード長[1]、コマンドIDを含む3バイトを足し合わせたものです。オーバーフローは無視します。また、第7ビットは必ず1です。

シーケンス

TCPクライアントとして動作する場合と、TCPサーバとして動作する場合のシーケンスです。

概要

今回利用したコマンドの大まかな流れを以下に示します。

TCPクライアントとして動作する場合

TCPサーバとして動作する場合

コマンド

RESET(リセット)

これは、コマンドではなく、NRST端子をLOWにした後、HIGHにすることで実現するようです。

リセットすると、 UART_CMD_SID_GEN_PWR_UP_INDというデータが返却されるようですが、詳細は不明です。

SNIC_INIT_REQ(初期化)

SNICの初期化を行います。

WIFI_DISCONNECT_REQ((切断)

ネットワークからモジュールを切り離します。

WIFI_JOIN_REQ(接続)

アクセスポイントに接続します。

SNIC_DATA_IND_ACK_CONFIG_REQ

SNICから非同期で送信されてくるデータ受信後、(Arduino側から)ACKを返すかどうかを指定します。デフォルトは、ACKを返す必要がないモードなので、処理が遅いと受信バッファがあふれてしまいます。

ACKを必要とするモードに移行して、受信バッファに空きができたら、ACKを送り、次のデータを受信するようにしました。

SNIC_IP_CONFIG_REQ(ネットワーク設定)

IPアドレス等の設定を行います。IPアドレス、ネットマスク、デフォルトゲートウェイを指定できます。DNSサーバの設定方法がよくわかっていません。DHCPを利用することもできます。このときは、DNSサーバはDHCPサーバから取得しているみたいです。

SNIC_TCP_CREATE_SOCKET_REQ(ソケット生成)

TCP通信に利用するソケットを作成します。

SNIC_RESOLVE_NAME_REQ(名前解決)

FQDNをIPアドレスに変換します。

SNIC_TCP_CONNECT_TO_SERVER_REQ(サーバ接続)

サーバに接続します。

サーバに接続してみましたが、一旦SNIC_COMMAND_PENDING(0x06)というリターンコードが返ってきて、その後、非同期で、SNIC_TCP_CONNECTION_STATUS_INDというメッセージが送信されてきました。

SNIC_SEND_FROM_SOCKET_REQ(データ送信)

データを送信します。

接続したサーバから送信されてくるデータは、SNIC_CONNECTION_RECV_INDというメッセージにより非同期で送信されます。

SNIC_TCP_CONNECTION_STATUS_IND(コネクション通知)

SNIC_TCP_CONNECT_TO_SERVER_REQの後、非同期でコネクションを確立することになった際に、結果が通知されてきます。

SNIC_CONNECTION_RECV_IND(データ受信通知)

サーバからデータが送信されてきたときに、送信されたデータが通知されてきます。

ACK(データ受信通知に対する応答)

SNIC_CONNECTION_RECV_IND(データ受信通知)受信後、受信バッファに空きができたらACKを送信し、次のデータ受信が可能であることをSNICに伝えます。

SNIC_TCP_CREATE_CONNECTION_REQ(クライアントからの接続要求送信)

クライアントからの接続を待ち受けます。

SNIC_TCP_CLIENT_SOCKET_IND(クライアントからのコネクション要求通知)

クライアントからの接続要求があったときに、通知されてきます。

実験結果

www.arduino.ccに接続してみました。

スケッチ

Arduino Due以外でコンパイルしたときはエラーが出るようにしてあります。Arduino Due以外で使う場合は、SNICClass.hの最初のほうを自己責任でいじってください。

SNICClass.cppとSNICClass.hは、mbed用のライブラリを基に記述したので、オリジナルのライセンス(MITライセンス)に従います。

ソースコードが長くなったので、githubにソースを置きました。余分なコードが入っていたり、未整理の部分が多々あります。

最初のほうの、accessPointにアクセスポイント名を、keyに暗号化キーを設定します。また、SNICEthernet.begin()の第三引数は、WIFI_SECURITY_OPEN、WIFI_SECURITY_WPA_TKIP_PSK、WIFI_SECURITY_WPA2_AES_PSK、WIFI_SECURITY_WPA2_MIXED、WIFI_SECURITY_WPA_AESの中から選んでください。

クライアントの例:

#include "SNICEthernetClass.h"
#include "SNICEthernetClient.h"

SNICEthernetClient client;

void setup() {
  char *accessPoint = "AP";
  char *key = "KEY";
  char *server = "www.arduino.cc";

  Serial. begin(9600);
  Serial1.begin(115200);

  if (SNICEthernet.begin(&Serial1, accessPoint, WIFI_SECURITY_WPA_AES, key) == 1) {
    Serial.println("OK");
  } else {
    Serial.println("NG");
  }

  Serial.println("connecting...");

  if (client.connect(server, 80)) {
    Serial.println("connected");
    client.println("GET / HTTP/1.1\r\nHost: www.arduino.cc\r\nConnection: close");
    client.println();
  } else {
    Serial.println("connectionf failed.");
  }
}

void loop() {
  if (client.available()) {
    Serial.print((char)client.read());
  }

}

サーバの例:

#include "SNICEthernetClass.h"
#include "SNICEthernetClient.h"
#include "SNICEthernetServer.h"

SNICEthernetClient client;
SNICEthernetServer server((uint16_t)23);

void setup() {
  char *accessPoint = "AP";
  char *key = "KEY";

  Serial. begin(9600);
  Serial1.begin(115200);

  if (SNICEthernet.begin(&Serial1, accessPoint, WIFI_SECURITY_WPA_AES, key) == 1) {
    Serial.println("OK");
  } else {
    Serial.println("NG");
  }

  server.begin();
}

void loop()
{
  // if an incoming client connects, there will be bytes available to read:
  SNICEthernetClient client = server.available();
  if (client) {
    // read bytes from the incoming client and write them back
    // to any clients connected to the server:
    int c = client.read();
    if (c != -1) {
      Serial.print((char) c);
      server.write(c);
    }
  }
}

バージョン

Arduino Due/Arduino 1.6.0



メニューを表示するためにJavaScriptを有効にしてください。

Arduinoで遊ぶページ
Copyright © 2014 garretlab all rights reserved.
inserted by FC2 system