FlashAirのiSDIO機能を使いPICから操作して見ます

〔FlashAir買ってみた編〕 〔PIO制御1〕 〔2〕 〔3〕 〔4〕   〔ESP-WROOM-02〕 〔マイコンのトップに戻る〕


FlashAirのLua機能を使い共有メモリでブラウザとのやり取りは、”PIO制御2””PIO制御3”で行いました
これで、マイコン側をI2CスレーブとしてFlashAirに接続は可能なのですが、少々煩わしいですね。
マイコンとSDカードは、”MMC/SDカードを接続し読書きを行って見ます”の記事の如くSPIモードで接続
出来ます。
でぇ、FlashAir(SDカード)は無線LAN機能を"iSDIO"の機能で制御出来る様になっています。

iSDIOとは?

SDカードの規格団体であるSDアソシエーションによって定められた、 FlashAirのような拡張機能付き
SDカードをホスト機器(マイコン等)からコントロールする為の規格で、内蔵の無線LANを制御出来る
様にコマンドのやりとり手順を定めたプロトコルです。

iSDIOは、拡張されたSDコマンドCMD48/49を利用して、FlashAir内のレジスタ無線LAN制御コマンド
を読み書きして操作します。
iSDIOのもう少し詳しい内容は、こちらの"FlashAir Developers"を参照しましょう。
また、iSDIOの仕様書は、”SD Association”サイトの”Part E7 Simplified - iSDIO Simplified Specifi-
cation pdf”を参考にして下さい。

このページでは、FlashAirの共有メモリの読み書きと、サーバーアップロードコマンドの
[SendHTTPMessageByRegister]と[SendHTTPSMessageByRegister]についてのみ記述します。
これによりブラウザからマイコンと共有メモリを介してデータのやり取りが可能になり、
指定したサーバーにHTTPリクエストを送信する事が出来ます。

尚、本ページは、"FlashAir Developers"の「Arduino向けチュートリアル」を大いに参考にしています。
このページではPIC(skSDlib)を使っています、Arduinoは上記サイトを参考にすれば良いと思います。

《実験回路》

実験回路図
PICは18F25K22で回路電源は3.3V、PICのMSSP2をI2C側(SCL2/SDA2)で使いLCDに配線し、
MSSP1をSPI側(SCK1/SDI1/SDO1)で使いSDソケットに配線しました、尚、SS(CS)はRC2ピンです。
I2Cのプルアップ抵抗はPIC内蔵を利用しています、SPI側もプルアップ10KΩを施して置きましょう。

SDソケットをこれから手に入れる人は、秋月電子のこちらが安くてお勧めですね。
(このソケットは私は持っていないのですがぁ多分動作するでしょう、SPIプルアップは施されています)
尚、18F25K22を使用していますが、Programメモリ8Kword、SRAM 1.5Kbyte、以上でMSSP機能が
2個(I2C/SPI)有るPIC(16F/18F)をお使い下さい。

《実験1》

実験1は、FlashAirの共有メモリの読み書き実験です。
・ブラウザから入力された文字をLCDに表示させます。
・PICは数値を1秒毎にカウントアップし、この値をブラウザで3秒毎に表示更新を行います。

ブラウザ側からは、HTTPリクエストを"javascript"で発行して、FlashAirの"command.cgi"を起動し
FlashAirの共有メモリの読み書きを行います。

ちょっとぉ実験

これは、前のページ[PIO制御2]で行ったものと同じですので解っている人はすっ飛ばしましょう。

※ 実行する場合は勿論、FlashAirのSSIDにパソコンの無線接続を切り換えますよ、念の為。
  (切り換えはこちらを参考にしましょう)

ブラウザのアドレスバーで下記を実行させて下さい。
("command.cgi"の正規なリファレンスマニュアルはこちらです)

http://flashair/command.cgi?op=131&ADDR=0&LEN=5&DATA=ABCDE
 op=131:共有メモリに書き込む為のコマンドです
 ADDR :書き込むメモリの番地を指定します(0-511)
 LEN  :書き込むデータの長さを指定します(0-512)
 DATA :書き込むデータをセットします(LEN長の文字列)

 成功すれば、"SUCCESS"がブラウザに表示されます。

http://flashair/command.cgi?op=130&ADDR=1&LEN=3
 op=130:共有メモリから読み込む為のコマンドです
 ADDR :読み込むメモリの番地を指定します(0-511)
 LEN  :読み込むデータの長さを指定します(0-512)

 成功すれば、"BCD"が表示されます、失敗は"400 Bad Request"が返るらしい。

レジスタマップ

こちらのレジスタマップを見て下さい、iSDIO機能を利用するにはこのレジスタでやり取りを行います。
でぇ、共有メモリで読み書きする部分は"Reserved for Vendor"部分の0x1000番地から512バイトです。
ですので上記の"command.cgi"はこの部分に読み書きされるのです。

この拡張レジスタの読み書きを行うSDコマンドが、拡張されたCMD48(30h:READ_EXTR_SINGLE)
CMD49(31h:WRITE_EXTR_SINGLE)です。

動作させて見る

@ 下記からダウンロードしたMemory.cをコンパイルし、PICに書き込んで置きます。

A "iSDIO_WEBtoMEM.htm"を、FlashAirのルートディレクトリにコピーします。

B FlashAirをソケットに入れて、実験回路を動かしましょう。
  LCDに「iSDIO Test」が表示され、10秒後にMMC/SDCの初期化が開始されます。
  「SDinitERR」が表示された場合は、回路等を見直しましょう。

C 数値を1秒毎にカウントアップして共有メモリの0-4番地に書き込みます、
  この時の書き込んだ内容をLCDの1行目に表示します。
  [xxxxx ans=???? ]  xxxxx=数値は5桁のゼロパディングです。
                 ????=書込んだ時の処理内容(HEX値)

D 共有メモリの5-20番地の16バイトを1秒毎に読み込んでLCDの2行目に表示します。

E FlashAirのSSIDにパソコンの無線接続を切り換えます。

F ブラウザのアドレスバーで"http://flashair/iSDIO_WEBtoMEM.htm"を実行すれば下図の様に
  表示されます。
  PICのカウント値が3秒毎に表示更新されます、PICに表示させる英数字文字列16文字までを
  書き込んで[送る]ボタンをクリックすればPIC側のLCDに表示されるでしょう。

  ※ 文字を[FlashAir Test]でFlashAirに送信して、その後[TOSHIBA]と送った場合は、
    共有メモリから常に16文字読取って表示を行っているので[TOSHIBAr TEST]と表示されますよ。

HTML実行画像
Windows7Pro SP1での環境ですが、IE10は上手く動作しません。
[Google Chrome Vr48]と[Firefox 44]は動作します。

《実験2》

実験2は、FlashAirの無線LAN制御コマンドを使い、サーバーにHTTPリクエストを送信する実験です。
ここでの接続サーバーは、「NICTサイト」にアクセスし”NTP時間”を得るサンプルです。

動作させて見る

@ FlashAirの同時接続機能を”有効”にします。
  有効の操作は、[PIO制御3]の"FlashAirの同時接続機能について"を見ましょう。
  (無線LAN制御コマンドを使い、同時接続機能を有効に出来るのですがここではパスです)

A 下記からダウンロードしたHTTP.cをコンパイルし、PICに書き込んで置きます。

B FlashAirをソケットに入れて、実験回路を動かしましょう。
  LCDに「iSDIO Test」が表示され、10秒後にMMC/SDCの初期化が開始されます。
  「SDinitERR」が表示された場合は、回路等を見直しましょう。

C NICTサイトからNTP時間を得る為に、NICTにアクセスします。
  その際にLCDに情報を表示します。
  [id=xx ans=xx   ]  id=シーケンス番号 ans=コマンドを書込んだ時の処理内容(HEX値)
  [Res xxxx ????  ]  xxxx=レスポンス情報を読み出した時の処理内容(HEX値)
                ????=返されたレスポンスのステータス値(HEX値)

  NICTのNTP時間の話しは、[PIO制御3]の"NICTのNTP時間について"を見ましょう。

D 正常にアクセス出来た場合は、3秒後にレスポンスデータから日付を読み取ります。
  (3秒後にしたのはCの表示内容を見る為の待ち時間です)
  [2016 Thu Mar 3 ]
  [17:32:06      ]
  失敗した場合は、「ResponseData ERR」が表示されるでしょう。

  ※ 返されるデータは、レスポンスヘッダが付きますよ、念の為に。

E 上記を1回処理したらプログラムは終了します。
  ループさせる場合は、アクセス制限が有るので3分に1回の割合でのアクセスとして下さい。

《ダウンロードファイルについて》

↓からダウンロードして下さい、このページで使うファイルを纏めて置きました。
FlashAir_iSDIO.lzh
FlashAir_iSDIO.lzh(skSPIlibの変更により修正) *1)
FlashAir_iSDIO.zip(skSDlibの変更により修正) *2)

プログラムソースをダウンロードしたら、MPLAB Xにてプロジェクトを作成します。
以下のファイルをプロジェクトディレクトリにコピーしてプロジェクトに取込んで下さい。
次にコンパイルPIC書き込みを実行して下さい。
MPLAB(R) XC8 C Compiler Version 1.32コンパイラを使用しています。

ダウンロードファイルを解凍すると下記の様なファイル構成です。
Memory.c・・・・・・・ 本体のプログラムソースファイル(実験1) *1)
HTTP.c・・・・・・・・・ 本体のプログラムソースファイル(実験2) *1)
skiSDIOlib.c・・・・・ iSDIOライブラリ関数ソースファイル
skiSDIOlib.h・・・・・ iSDIOライブラリ用ヘッダファイル
skSDlib.c・・・・・・・ SDライブラリ関数ソースファイル *2)
skSDlib.h・・・・・・・ SDライブラリ用ヘッダファイル *2)
skSPIlib.c・・・・・・・ SPI通信を行う関数ソースファイル *1)
skSPIlib.h・・・・・・・ SPI通信を行う関数のヘッダファイル *1)
(以下表示用)
skI2CLCDlib.c・・・・I2C接続LCDライブラリ関数ソースファイル
skI2CLCDlib.h・・・・I2C接続LCDライブラリ用ヘッダファイル
skI2Clib.c・・・・・・・・I2C通信を行う関数ソースファイル
skI2Clib.h・・・・・・・・I2C通信を行う関数のヘッダファイル
※コンパイル時はMemory.cかHTTP.cの何方かひとつで実行して下さい。

iSDIO_WEBtoMEM.htm ・・・・・ブラウザで共有メモリを操作するHTMLファイル(ブラウザから実行)
※このHTMLファイルは、FlashAirのルートディレクトリにコピーして置きます。

 尚、CPUのクロックは16MHzを想定しています。
 なので通信速度等(I2C)はシステムクロック16MHzで計算されています。

skiSDIOlib.h

FlashAirのiSDIOアクセスを行う関数のヘッダファイルです。
"skiSDIOlib.c"を利用する場合に
#include "skSPIlib.h"
#include "skSDlib.h"
#include "skiSDIOlib.h" をプログラムの先頭で記述して下さい。

skiSDIOlib.c

このライブラリはFlashAirのiSDIOで無線LAN機能にアクセスを行う為の関数集です。
この関数集はSDカードにSPIモードでアクセスします、なのでskSPIlib/skSDlibのファイルが必要です。

この関数集を利用する場合は、"skSPIlib.c"の"SPI_Init( )"関数を呼び出した後で、
"skSDlib.c"の"SD_Init( )"関数でFlashAirを初期化した後使います、
使い方の例は、”Memory.c””HTTP.c”を参照下さい。

FlashAirのiSDIOアクセス関数の使い方を説明します。

ans = SD_Init( )
 MMC/SDCの初期化を行う処理

  ans:正常=0 異常=エラーコード値(こちらの"初期化時のエラーコード一覧"を参照下さい)
     カードが未挿入なら ans=0x40(CMD0のレスポンスタイムオーバ)エラーが発生するでしょう。

 ※ この関数は、”skSDlib.c”に含まれています。

ans = readExtMemory(mio,func,addr,count,*dst)
 iSDIOレジスタのメモリ内容を読み込む(レジスタモード)処理
 こちらのレジスタマップのデータにアクセスします。

  mio    :メモリ領域とI/O領域の指定です、iSDIOでは常に 1=I/O領域 を指定します
  func   :機能番号の指定です(0-7)、FlashAirの無線LAN機能は 1 を指定します
       iSDIOレジスタを無線LAN機能で使用するので"1"、
       カード上の全ての機能を識別し、制御する為の共通のI/O領域とする場合は"0"。
  addr   :読み込むレジスタメモリのアドレスを指定します
  count :読み込むデータの長さを指定します(0-512バイト)
  *dst   :読み込んだデータの格納先を指定します
  ans    :0=正常 それ以外はエラー(下記の"iSDIO関連エラーコード一覧"を参照下さい)

 例) 共有メモリの先頭から10バイト読み込む場合
     char dt[12] ;

     readExtMemory(1,1,0x1000,10,dt) ;
ans = writeExtMemory(mio,func,addr,count,*dst)
 iSDIOレジスタのメモリにデータを書き込む(レジスタモード)処理

  mio    :メモリ領域とI/O領域の指定です、iSDIOでは常に 1=I/O領域 を指定します
  func   :機能番号の指定です(0-7)、FlashAirの無線LAN機能は 1 を指定します
  addr   :書き込むレジスタメモリのアドレスを指定します
  count :書き込むデータの長さを指定します(0-512バイト)
  *dst   :書き込むデータの格納した場所を指定します
  ans    :0=正常 それ以外はエラー(下記の"iSDIO関連エラーコード一覧"を参照下さい)

  ※ 尚、レジスタの読み書きには「データポートモード」「マスク書き込みモード」が有りますが、
    ここでは「レジスタモード」のみで行っています。

ans = iSDIO_getSequenceId()
 iSDIOのシーケンス番号を得る処理
 無線LAN制御コマンドを発行する際の処理番号をこの関数で得とくします。

  ans    :次のシーケンス番号を返します、上手く得とく出来なった場合は0を返します

ans = iSDIO_SendHTTPmsgBYreg(ssl,seq_id,*arg1,*arg2)
 iSDIOの無線LAN制御コマンド(21h/23h)を書込み送信する処理
 21h=SendHTTPMessageByRegister 23h=SendHTTPSMessageByRegisterのHTTP通信コマンドを
 発行します。

  ssl     :コマンド(プロトコル)の種類を指定します(0=HTTP 1=HTTPS)
  seq_id :シーケンス番号を指定します(iSDIO_getSequenceId関数で得ます)
  *arg1 :コマンドの引数1を指定します(サーバーのドメイン名)
  *arg2 :コマンドの引数2を指定します(リクエストヘッダ)
  ans    :0=正常 それ以外はエラー(下記の"iSDIO関連エラーコード一覧"を参照下さい)
 例)
     unsigned long id ;

     id = iSDIO_getSequenceId() ;
     iSDIO_SendHTTPmsgBYreg(HTTPS,id,"ntp-a1.nict.go.jp",
     "GET /cgi-bin/time HTTP/1.1\r\n"
     "Host: ntp-a1.nict.go.jp\r\n"
     "User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) 
Chrome/36.0.1985.125 Safari/537.36\r\n"
     "\r\n");
 ※ その他の無線LAN制御コマンドはご自分で必要に応じて作成しましょう。m(_ _)m

ans = iSDIO_waitResponseSts(*sts,seq_id)
 iSDIOのコマンド実行応答を待つ処理
 コマンドを発行した後に、この関数でNETからの通信応答を待ちます。
 この関数は最大20秒の待ちが発生します

  *sts   :レスポンスのステータス(処理結果)情報を返します
      [Command Response Status]
      00h: Initial (Default)
      01h: Command Processing
      02h: Command Rejected
      03h: Process Succeeded(正常に終了した)
      04h: Process Terminated
      80h to FFh: Process Failed where
       80h: general error
       81h: argument error
       82h: network error
       83h: file system error
       84h: buffer overflow error
       85h to BFh: reserved
       C0h to FFh: reserved for each application specification
      FFh=20秒以上過ぎた時かステータスの読み出し異常の時です。
  seq_id :コマンドを発行した時のシーケンス番号を指定します
  ans    :0=正常 それ以外はエラー(下記の"iSDIO関連エラーコード一覧"を参照下さい)
 例)
     int ans , sts ;
     unsigned long id ;

     id = iSDIO_getSequenceId() ;
     ans = iSDIO_SendHTTPmsgBYreg(HTTPS,id,arg1,arg2) ;
     if (ans == 0) {
           ans = iSDIO_waitResponseSts((unsigned int *)&sts,id) ;
           ans = iSDIO_readHTTPresData(id,workbuff) ;
           if (ans > 0) {
                // レスポンスデータを得たので何か処理する。
           }
      }
ans = iSDIO_readHTTPresData(seq_id,*dst)
 iSDIOのコマンドが受信したレスポンスデータを読出す処理
 FlashAirは2024バイトが受信可能データ数ですが、この関数はレスポンスヘッダを含め488バイト以内
 のデータのみ受信出来ます。
 488バイト以上読みたいとか、2024バイト以上読みたいのでファイルで受信したいとかの人は
 これまた、ご自分で作成しましょう。m(_ _)m

  seq_id :コマンドを発行した時のシーケンス番号を指定します
  *dst   :受信したデータの格納先を指定します
       レスポンスヘッダを含めてデータを格納するので、確保するバッファのサイズには
       十分な注意が必要です。
  ans    :正常時は受信データのサイズを返します、 0 or -1 はエラー

 ※ レスポンスデータの読出しはコマンドに応じて自分のやりやすい様に改造した方が
   メモリの少ないマイコンには良さげな気もします。

iSDIOアクセス時のエラーコード一覧

00??????xxxxxxxx コマンド送信後に受信したR1のレスポンスエラー
x x x x x x x x にはR1のレスポンスエラーをそのまま設定します
0bit : アイドル状態
1bit : 消去中にリセットが実行された
2bit : 送られてきたそのコマンドはおかしいよ
3bit : CRCのチェックエラー
4bit : 消去の動作中にエラーが発生したよ
5bit : アドレス指定エラー
6bit : パラメータ指定エラー
7bit : 常にゼロ
??????には "コマンド番号"を設定します。
01xxxxxx00000000 コマンド送信時のレスポンスタイムオーバ
x x x x x x に "コマンド番号" を設定します、0x4800 ならCMD8がR1レスポンスを返さなかったと判断します。
0xC600 CMD48(データ送信要求コマンド)の送信後、カードがデータトークンを返さなかったのでタイムオーバ
0xC6?? CMD48の送信後、カードがデータエラートークンを返した。
??(x x x x x x x x)にはエラートークンの情報がそのまま設定されます。
0bit : 常に1
1bit : カードコントローラのエラー
2bit : ECCの訂正が出来なかった
3bit : アドレス(セクタ)指定範囲外
4bit : カードはロック状態
5−7bit : 常にゼロ
0xC8?? CMD49(データ書込み要求コマンド)の送信と書き込みデータを送信したが、データのレスポンスエラーが返ってきた。
??にはレスポンスエラー情報がそのまま設定されます。
0x0B : データは、CRCエラーのため拒否された
0x0D : データは、書き込みエラーのため拒否され
0xC800 書き込みデータを送信しデータのレスポンスも正常であるが、その後ビジー状態が500ms以上続いてタイムオーバ。
注意)上記内容はCMD17/24でのエラー値なのでCMD48/49では異なる可能性が有ります。


以下のファイルはSDカードにアクセスを行う為のライブラリです。

skSDlib.c
skSDlib.h
skSPIlib.c
skSPIlib.h

この内容は”MMC/SDカードを接続し読書きを行って見ます”の記事を参照下さい。


以下のファイルはLCDに表示を行う為のライブラリです。

skI2CLCDlib.c
skI2CLCDlib.h
skI2Clib.c
skI2Clib.h

この内容は”秋月電子I2C接続小型LCDモジュールに表示を行う”を参照下さい。

尚、システムクロックを変えた人は"skI2Clib.c"ファイル内の"InitI2C_Master( )"関数と、
"skI2CLCD.h"のファイルを変更する必要が有ります。

《その他》

実験時の写真
上図は、”実験2”の時の写真です。

共有メモリのアクセス程度なら良いのですがぁ、HTTPリクエスト等のiSDIO機能を利用するには
メモリに余裕のあるマイコンでないとぉ、少々荷が重い様な気がします。
それとぉ、コマンドを発行してぇレスポンスを待ってぇ等は、時間が掛かる場合が有るので
マイコンがそれ以外の処理で時間待ち出来ない場合には、"iSDIO_waitResponseSts( )"関数は
このままでは使用出来ないでしょう。

こちらのページに、JPEGカメラが動きを検出したらiSDIO機能とLua機能(MailSend)を利用し、
その時の画像を添付して電子メールを送る記事を書いています。 *3)



記事を一部追加(*3) 2017/04/19
"skSDlib"を変更(*2) 2017/02/26
"skSPIlib"のSPI_MODEのCKE(クロック位相)を変更(*1) 2016/06/16


【きむ茶工房ガレージハウス】
Copyright (C) 2006-2017 Shigehiro Kimura All Rights Reserved.