MCP3002を使う(0x68と0x60)


MCP3002からデータを読むサンプルは、色々なところで公開されていますが、
チャネル0からデータを読む時の送信コマンドを0x60で紹介しているページと、0x68で紹介しているページが有ります。
そこで、0x60を指定した時と、0x68を指定した時の違いを紹介します。
まずは、以下のコードを実行します。
/*
* Read MCP3002 with wiringPiSPIDataRW
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wiringPi.h>
#include <wiringPiSPI.h>

#define DEBUG 1
#define SPI_CHANNEL 0 // /dev/spidev0.0
//#define SPI_CHANNEL 1 // /dev/spidev0.1
#define BCD(c) 5 * (5 * (5 * (5 * (5 * (5 * (5 * (c & 128) + (c & 64))\
 + (c & 32)) + (c & 16)) + (c & 8)) + (c & 4)) + (c & 2)) + (c & 1)

int main(int argc, char **argv){
  int retCode;
  int i;
  int a2dVal = 0;
  unsigned char data[4];


  // SPI channel 0 を 1MHz で開始。
  if (wiringPiSPISetup(SPI_CHANNEL, 1000000) < 0) {
    printf("SPISetup failed:\n");
    return 1;
  }

  unsigned char cmd[2];
  cmd[0] = 0x60;
  cmd[1] = 0x68;
  for (i=0;i<2;i++) {
    data[0] = cmd[i];  // first byte transmitted -> start bit
    data[1] = 0;       // don't care
if(DEBUG)printf("[MCP3002]data[write]=0x%02x-0x%02x\n",data[0],data[1]);
    retCode=wiringPiSPIDataRW (SPI_CHANNEL,data,2);
if(DEBUG)printf("[MCP3002]wiringPiSPIDataRW=%d\n",retCode);
if(DEBUG)printf("[MCP3002]data[read]=0x%02x-0x%02x\n",data[0],data[1]);
if(DEBUG)printf("[MCP3002]data[read]=0b%08d-0b%08d\n",BCD(data[0]),BCD(data[1]));
    a2dVal = (data[0]<< 8) & 0b1100000000; //first 2 bit
    a2dVal |=  (data[1] & 0xff);
    printf("a2dVal=%d\n",a2dVal);
    printf("\n");

    data[0] = cmd[i];  // first byte transmitted -> start bit
    data[1] = 0;       // don't care
    data[2] = 0;       // don't care
    data[3] = 0;       // don't care
if(DEBUG)printf("[MCP3002]data[write]=0x%02x-0x%02x-0x%02x-0x%02x\n",data[0],data[1],data[2],data[3]);
    retCode=wiringPiSPIDataRW (SPI_CHANNEL,data,4);
if(DEBUG)printf("[MCP3002]wiringPiSPIDataRW=%d\n",retCode);
if(DEBUG)printf("[MCP3002]data[read]=0x%02x-0x%02x-0x%02x-0x%02x\n",data[0],data[1],data[2],data[3]);
if(DEBUG)printf("[MCP3002]data[read]=0b%08d-0b%08d-0b%08d-0b%08d\n",BCD(data[0]),BCD(data[1]),BCD(data[2]),BCD(data[3]));
    a2dVal = (data[0]<< 8) & 0b1100000000; //first 2 bit
    a2dVal |=  (data[1] & 0xff);
    printf("a2dVal=%d\n",a2dVal);
    printf("\n");
  }
}

このコードを実行すると、以下の表示となります。
読み取ったアナログ値は全て同じ440ですが、0x68-0x00-0x00-0x00を指定した時は、2バイト目と3バイト目に値が戻ります。
[MCP3002]data[write]=0x60-0x00
[MCP3002]wiringPiSPIDataRW=2
[MCP3002]data[read]=0x01-0xb8
[MCP3002]data[read]=0b00000001-0b10111000
a2dVal=440

[MCP3002]data[write]=0x60-0x00-0x00-0x00
[MCP3002]wiringPiSPIDataRW=4
[MCP3002]data[read]=0x01-0xb8-0x00-0x00
[MCP3002]data[read]=0b00000001-0b10111000-0b00000000-0b00000000
a2dVal=440

[MCP3002]data[write]=0x68-0x00
[MCP3002]wiringPiSPIDataRW=2
[MCP3002]data[read]=0x01-0xb8
[MCP3002]data[read]=0b00000001-0b10111000
a2dVal=440

[MCP3002]data[write]=0x68-0x00-0x00-0x00
[MCP3002]wiringPiSPIDataRW=4
[MCP3002]data[read]=0x01-0xb8-0x3b-0x00
[MCP3002]data[read]=0b00000001-0b10111000-0b00111011-0b00000000
a2dVal=440

MCP3002は以下の4ビットで命令を出します。
Start:必ず1です。これ以前のデータは無視されます。
SGL/DIFF:シングルエンドモードまたは擬似差動モードを選択します。
ODD/SIGN:シングルエンドモードの時は使用するチャネルを選択し、擬似差動モードの時は極性を決定します。
MSBF:デバイスのLSBファーストフォーマットを有効にするかどうかを選択します。

公開されているMCP3002のデー タシートでは、

If the MSBF bit is high, then the data will come from the device in MSB first format and any further clocks with CS low, will cause the device to output zeros.
If the MSBF bit is low, then the device will output the converted word LSB first after the word has been transmitted in the MSB first format.

MSBFビットがhighのときは「MSB-First-Format」でデータを出力し、それ以降のクロックではゼロを出力する
MSBFビットがlowのときは「MSB-First-Format」でデータを出力し、それ以降「LSB-First-Format」でデータ を出力する

という解釈をしたのですが、どうも逆の動作で、0x68-0x00-0x00-0x00を指定した時(MSBFビットがHIGHのとき)は、
MSBのデータの後ろにLSBのデータが戻ります。

0x68(MSBF is high) 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 b9 b8 b7 b6 b5 b4 b3 b2 b1 b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 -- -- -- -- -- -- --

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

0x60-0x00-0x00-0x00を指定した時(MSBFビットがLOWのとき)は、MSBのデータだけが戻ります。

0x60(MSBF is low) 0x00 0x00 0x00
出力  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 b9 b8 b7 b6 b5 b4 b3 b2 b1 b0 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

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

SPIでは送信データと受信データの長さは同じです。
2バイトのデータを送信すると、2バイトのデータを受信します。
0x68-0x00を指定した時は、MSBのデータしか転送されません。
だから、0x60-0x00を指定しても、0x68-0x00を指定しても、結果は同じになりますが、
2バイトしか転送しないのであれば、0x60-0x00の方が私はいいと思います。

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

特に0x60-0x00でなくても、0xC0-0x00でも、0x30-0x00-0x00でも動きますが、
戻ってきたデータの扱いが面倒なので、0x60-0x00を指定しています。

0xC0 0x00
出力  1  1  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 --


0x30 0x00 0x00
出力  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 b9 b8 b7 b6 b5 b4 b3 b2 b1 b0 -- -- -- -- -- -- --

次回はic2接続のAD/DAコンバータ(PCF8591)を紹介します。