LinkIt Smart 7688を使ってみる

アナログ入力

LinkItにはアナログポートが有りません。
アナログデータを読むためには、A/Dコンバータが必要になります。
そこで、PCF8591を使ってアナログデータを読んでみました。
PCF8591はi2cの4チャンネル、8ビットのA/Dコンバータです。
LinkItとの接続は以下の通りです。
LinkItのfritzingパーツ図はこ ちらからダウンロードすることができます。



以下のコードで4チャンネル全てのアナログ値を読むことができます。
#!/usr/bin/python
#-*- encoding: utf-8 -*-
import mraa
import time

def bytes_to_int(bytes):
  result = 0
  for b in bytes:
    result = result * 256 + int(b)
  return result

# initialise I2C
i2c = mraa.I2c(0)
i2c.address(0x48)

while(1):
  for channel in range(4):
    i2c.writeReg(0x40+channel, 0x00)
    value = i2c.read(1) # Dummy Read
    #print bytes_to_int(value)
    value = i2c.read(1)
    data = bytes_to_int(value)
    print('value={:d}'.format(data)),
  print
  time.sleep(1)

ボリュームを回すとチャンネル0の値が変化します。
チャンネル1は3.3Vなので常に255、チャンネル2は0Vなので常に0、チャンネル3は未接続なので不定です。
root@mylinkit:~# python ./pcf8591.py
value=0 value=255 value=0 value=0
value=0 value=255 value=0 value=1
value=0 value=255 value=0 value=7
value=0 value=255 value=0 value=6
value=0 value=255 value=0 value=0
value=0 value=255 value=0 value=0
value=6 value=255 value=0 value=0
value=14 value=255 value=0 value=6
value=19 value=255 value=0 value=1
value=23 value=255 value=0 value=0
value=50 value=255 value=0 value=0
value=69 value=255 value=0 value=2
value=69 value=255 value=0 value=8



こちら
にMCP3004のA/Dコンバータからアナログデータを読み取るサンプルが公開されています。
MCP3004はSPIの4チャンネル、10ビットのA/Dコンバータです。
MCP3004(4Ch)とMCP3008(8Ch)はアナログのチャネル数が違うだけで、同じ命令セットなので、
手元にあったMCP3008を使って、このまま動かしましたが、データが正しくとれません。
LinkItとの接続は以下の通りです。

Bit8 Bit9の戻ってくる場所がなんかおかしいです。
ボリュームを微妙に調整してビットパターンを調べてみました。
rxbuf= 3 11111110 11111110 00000000 0011111110 0254
rxbuf= 3 11111111 11111110 00000000 0011111111 0255
rxbuf= 3 00000000 00000001 00000000 0100000000 0256

rxbuf= 3 11111111 11111111 00000000 0111111111 0511
rxbuf= 3 00000000 00000000 10000000 1000000000 0512
rxbuf= 3 00000001 00000000 10000000 1000000001 0513

rxbuf= 3 11111111 11111110 10000000 1011111111 0767
rxbuf= 3 00000000 00000001 10000000 1100000000 0768
rxbuf= 3 00000001 00000001 10000000 1100000001 0769

Bit8は赤の場所、Bit9は紫の場所に戻ってくることが分かりました。
以下のソースで10Bitのアナログ値がとれます。
#!/usr/bin/python
# Read the analog sensor value via MCP3004/3008.

import mraa
import time

# initialise SPI
dev = mraa.Spi(0)

# prepare data to send
txbuf = bytearray(3)
txbuf[1] = 0x01
txbuf[0] = 0x80
#txbuf[3] = 0x00
txbuf[2] = 0x00

while True:
  # send data through SPI
  rxbuf = dev.write(txbuf)
  print "rxbuf=",
  print len(rxbuf),
  for x in range(len(rxbuf)):
    print('{:08b}'.format(rxbuf[x])),
  #rxbuf[0]: X  X  X  X  X  X  X  X
  #         B7 B6 B5 B4 B3 B2 B1 B0
  #rxbuf[1]: X  X  X  X  X  X  X  X
  #         -- -- -- -- -- -- -- B8
  #rxbuf[2]: X  X  X  X  X  X  X  X
  #         B9 -- -- -- -- -- -- --
  value = rxbuf[0]
  value = value + ((rxbuf[1] & 0x01) << 8)
  value = value + ((rxbuf[2] & 0x80) << 2)
  print('{:010b}'.format(value)),
  print('{:04d}'.format(value))
  time.sleep(0.5)

MCP3004/3008のデータシートを見ればわかりますが、このチップは、MSBのデータの後ろにLSBのデータが戻ります。

0x01 0x80 0x00 0x00 0x00
出力  0  0  0  0  0  0  0  1  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
入力  0  0  0  0  0  0  0  0  0  0  0  0  0  0 b9 b8 b7 b6 b5 b4 b3 b2 b1 b0 b1 b2 b3 b4 b5 b6 b7 b8 b9  0  0  0  0  0  0  0

無効なデータ MSBのデータ LSBのデータ 無効なデータ

普通はMSBのデータだけ読んで、LSBのデータは読みません。
実際に読めるデータから判断して、赤字の部分だけが読めているように思われます。
先頭の2バイトはどこに行ったのでしょうか??



SPIのwrite()では先頭の2バイトが読めないと仮定して、MCP3002のA/Dコンバータからアナログデータを読み取ってみました。
MCP3002はSPIの2チャンネル、10ビットのA/Dコンバータです。
チャネル0のデータを読む場合、0x60でデータを読みますが、今回はLSBデータも必要なので0x68でデータを読みます。
MCP3002のデータシートを見ればわかりますが、0x68-0x00-0x00-0x00を指定した時は、MSBのデータの後ろに
LSBのデータが戻ります。

0x68 0x00 0x00 0x00
出力  0  1  1  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
入力  0  0  0  0  0  0 b9 b8 b7 b6 b5 b4 b3 b2 b1 b0 b1 b2 b3 b4 b5 b6 b7 b8 b9  0  0  0  0  0  0  0

無効なデータ
MSBのデータ LSBのデータ 無効なデータ

先頭の2バイトが読めない場合、b0のデータが読めないので、0x68を1ビット右にシフトして0x34のコマンドを発行してみました。
普通はこのようにデータが戻るはずですが、先頭2バイトが読めないと仮定すると赤字の部分だけが戻ります。

0x34 0x00 0x00 0x00
出力  0  0  1  1  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
入力  0  0  0  0  0  0  0 b9 b8 b7 b6 b5 b4 b3 b2 b1 b0 b1 b2 b3 b4 b5 b6 b7 b8 b9  0  0  0  0  0  0

無効なデータ
MSBのデータ LSBのデータ 無効なデータ

結果はビンゴ!!で、赤字の部分だけデータが戻ってきます。
以下のコードでチャネル0のアナログ値を読むことができました。
SPIのブロック転送はメチャクチャ怪しいです。
#!/usr/bin/python
# Read the analog sensor value via MCP3002.

import mraa
import time

def reverse_bit(value):
  value = ((value & 0x55) << 1) | ((value & 0xAA) >> 1)
  value = ((value & 0x33) << 2) | ((value & 0xCC) >> 2)
  value = (value << 4) | (value >> 4)
  return (value & 0xff)

# initialise SPI
dev = mraa.Spi(0)

# prepare data to send
txbuf = bytearray(2)
txbuf[1] = 0x68 >> 1
txbuf[0] = 0x00

while True:
  # send data through SPI
  rxbuf = dev.write(txbuf)
  print "rxbuf=",
  print len(rxbuf),
  for x in range(len(rxbuf)):
    print('{:08b}'.format(rxbuf[x])),
  #rxbuf[0]: X  X  X  X  X  X  X  X
  #         B0 B1 B2 B3 B4 B5 B6 B7
  #rxbuf[1]: X  X  X  X  X  X  X  X
  #         B8 B9 ?? ?? ?? ?? ?? ??
  print
  rxbuf[0] = reverse_bit(rxbuf[0])
  rxbuf[1] = reverse_bit(rxbuf[1])
  print "rxbuf(reverse)=",
  for x in range(len(rxbuf)):
    print('{:08b}'.format(rxbuf[x])),
  value = (rxbuf[1] << 8) + rxbuf[0]
  print('{:04d}'.format(value))
  time.sleep(0.5)

続く....