SPI: 送信する

SPIはコンピューター同士でデータをやり取りする通信方式です。といってもUSBのようにちゃんとしたものではなく、シンプルな通信に使われます。

よく使われるUARTと違う点は

  • クロック信号線というのが1本別にあるため、安定して高速に通信できる
  • SPIでは送受信ではなくデータを"交換"する通信。1バイト送信したら相手から1バイト必ず受信する。
  • 通信には親子関係があり、子は自分から送信できない。親の好きなタイミングで通信が始まる。

親子関係があるので、マイコン同士というよりはマイコンとセンサーなどをつなぐのによく使われます。
マイコンからSPIを使いセンサーに何をしてほしいかを伝えて、代わりにデータを受け取るといった形です。
親は自分の好きなタイミング通信できるためプログラムも簡単で、しかもかなり高速な通信ができるのも魅力です。

通信する相手とは3つの線でつなぎます。親がデータをやり取りするタイミングを送るためのCLK。そして親から子へデータを送るためのMOSI(Master Out Slave In という意味です)。逆に親がデータを受け取るためのMISOです。子からデータを受け取る必要がない場合はMISOを繋がないこともあります。

使ってみる。

では、obnizのSPIを使ってみましょう。obnizのSPIは2つあり、spi0とspi1です。
ioとspiは別のもので、spiのclkやmosiなどそれぞれを、12あるioのうちどれかで使えるようにして利用する。という感じになります。

例えば、io0をmosiに、io1をmisoに、io2をclkとするばあいは、このようにします。

var spi = obniz.getFreeSpi();
spi.start({mode:"master", mosi:0, miso:1, clk :2, frequency:100000}); 

obniz.getFreeSpi()とは2つあるspiのうち、使われていないspiを下さい。という意味です。
もし確実に使っていないspiがわかっている場合は、このようにすることもできます。

obniz.spi0.start({mode:"master", mosi:0, miso:1, clk :2, frequency:100000}); 

基本的にはこのようにせずにgetFreeSpi()を使って下さい。

modeはobnizをmasterにして自分からデータを送れるようにするのかを設定しますが、現在masterモードにのみ対応しています。
frequencyは通信周波数となります。clkでmasterから送り出される周波数です。標準であるpush-pull5vでは250khz以下が推奨値です。(詳しくはioのページを御覧ください)。
push-pull3vであれば、2Mhzなど、より高速な通信が可能です。

それぞれのioのドライブ方法とプルアップダウンはこのように変更できます。

var spi = obniz.getFreeSpi();
spi.start({mode:"master", mosi:0, miso:1, clk :2, frequency:100000, drive:"3v", pull:null}); 

driveで駆動方法を、pullでプルアップダウンを変更できます。指定できるものはそれぞれio.drive()io.pull()で指定できるものと同じです。

繋いで使う

UARTと同じくobnizだけで実験ができます。自分で送信したデータを自分で受信してみましょう。

io0とio1をつなぎます。

そして、spiでmosiから出力して、逆に相手からの受信を受け取ってみましょう。

通信するにはこのようにします。

var ret = await spi.writeWait([1,2,3]);

これで[1,2,3]という3バイトのデータをmosiと設定したio0から出力できます。
SPIはデータを交換する通信ですから同時にmisoと設定したio1からデータを受信します。
今回はmosiとmisoは直接電線でつないでいるので、自分の出したデータを自分で受信します。

await関数になっています。これは、obnizに対して[1,2,3]を送ったあとに、obnizが受信したデータをインターネッと経由で受け取る必要があるので、awaitを使って返事を待っています。

var obniz = new Obniz("OBNIZ_ID_HERE");
obniz.onconnect = async function(){
  var spi = obniz.getFreeSpi();
  spi.start({mode:"master", mosi:0, miso:1, clk :2, frequency:100000}); 
  var ret = await spi.writeWait([1,2,3]);
  console.log(ret);
}

どうでしょうか。[1,2,3]が受信できて、consoleに出てくると思います。
試しに線をobnizから抜いて実験すると意味不明なデータが受信されると思います。
きちんとobnizから出たものをobnizが受信しています。

UARTと違ってデータはバラバラになることはありません。送ったデータと同じ長さのデータを受信できます。

送れるデータの長さは1kbyte程度までです。(ファームウェアとobniz.jsのバージョンによります)

返事を受け取らない

返事が必要ないときがあります。
通信相手がディスプレイか何かで、とにかく大量のデータをSPIで送るだけ送りたい時などです。
そういうときはデータの受信をawaitで待ったりしたくないものです。そのための関数があります。

spi.write([1,2,3]);

write()関数はwriteWait()と同じくデータをmosiから送信しますが、misoから入ってきたデータをすべて無視します。awaitしないので、大量のデータや連続のデータもインターネッと経由でとりあえずobnizに送ってSPIで送ることが可能です。

var obniz = new Obniz("OBNIZ_ID_HERE");
obniz.onconnect = async function(){
  var spi = obniz.getFreeSpi();
  spi.start({mode:"master", mosi:0, miso:1, clk :2, frequency:100000}); 
  spi.writeWait([1,2,3]);
  spi.writeWait([4,5,6]);
  spi.writeWait([7,8,9]);
}

また、spiではmosi,miso,clkの”最低どれか1つ"があれば良いことになっています。
本当にmisoがいらない場合とか、逆に受信しかしたくないなど。このように設定することもできます。

var obniz = new Obniz("OBNIZ_ID_HERE");
obniz.onconnect = async function(){
  var spi = obniz.getFreeSpi();
  spi.start({mode:"master", mosi:0, clk :2, frequency:100000}); 
  spi.writeWait([1,2,3]);
  spi.writeWait([4,5,6]);
  spi.writeWait([7,8,9]);
}

終了

spiを終了してspiで使っていたioを開放するにはendを使います。
endが呼ばれた段階でioはフロートの状態に戻ります。

var obniz = new Obniz("OBNIZ_ID_HERE");
obniz.onconnect = async function(){
  var spi = obniz.getFreeSpi();
  spi.start({mode:"master", mosi:0, miso:1, clk :2, frequency:100000}); 
  spi.writeWait([1,2,3]);
  spi.end();
}


Next : I2C: Master Mode

You will Get in Few Days

Circuit for Starter “obniz Board” is available on Amazon and other online stores.
You can get it at below

Our products and resellers

Forum

Visit our developer’s forum to discuss and discover technologies.

Forum

Contact

Feel free to contact out support and technical team.

Contact us