電圧計を作る ② ADS8699のスケッチ その1 レンジの読み書き

  ADS869x 18 ビット、高速、単一電源、SAR ADC データ・アクイジション・システム、プログラム可能なバイポーラ入力範囲

 上記のデータシートをもとにスケッチを作ります。

レジスタ類の読み書き

 インターフェースは、とても一般的なSPIです。一度に32ビットを扱います。一度に32ビットのコマンド/データを送るのを1フレームと呼びます。レジスタの読み出しをするコマンドが含まれていると、次のフレームでデータが現れます。

 レジスタは32ビット長で、九つ用意されています。

 データシートの「表 7-5. List of Input Commands」に読み書きするフォーマットが書かれていますが、読み出しは16ビット単位がREAD_HWORD、8ビット単位がREADの二つのコマンドがあります。

 レジスタへの書き込みは、2バイトの書き込み、32ビットのうち上位16ビットのエリアに書き込む、32ビットのうち下位16ビットのエリアに書き込むの3種類のコマンドがあります。

 32ビットを読み書きする方法は用意されていません。

 32ビットの内訳です。SPIバスは8ビット単位で行うのが一般的です。しかし、このデバイスでは、次のような一般的でない、ビット数で構成されています。

  7ビットのコマンド + 9ビットのレジスタのアドレス + 8ビットのデータ + 8ビットのデータ

18ビットのA-D変換データ

 「7.6.1.5 DATAOUT_CTL_REG Register (address = 10h)」は設定レジスタですが、設定した次のフレームでデータがMSBからA-D変換された18ビットが入っていて読み出せます。18ビットなので、32ビットを読み出します。つまり、16ビットの上位、16ビットの下位を読んで合成し、18ビット分を取り出します。

 「図 7-15. Device Transfer Function (Straight-Binary Format) 」に書かれているように、マイナス側の最大値は0x00、0は0x2000、最大値は0x3fffです。実際の電圧は、設定したレンジによってスケールが異なります。どのレンジでも、入力をGNDにつないだ時は、0x2000付近のデータが読めるはずです。

レンジの読み書き

 このデバイスは、パワー・オン・リセットもしくはRSTをLOWにしてリセットをかけると、ほとんどのレジスタの内容は0になっています。

 つねにアクティブ(ACQ)状態で、SPIバスのCS端子がHIGHからLOWに変化したらCONV状態になり、32ビット分の読み書きが終わってCS端子をHIGHに戻すとACQ状態になります。

  「7.6.1.6 RANGE_SEL_REG Register (address = 14h)」のLSBから4ビットがレンジの設定です。

0000b = ±3 × Vref
0001b = ±2.5 × Vref
0010b = ±1.5 × Vref
0011b = ±1.25 × Vref
0100b = ±0.625 × Vref
1000b = 3 × Vref
1001b = 2.5 × Vref
1010b = 1.5 × Vref
1011b = 1.25 × Vref

 何も設定変更しなければ、0000b = ±3 × Vrefになっています。Vrefは、デフォルトでは内蔵の4.096 Vが使われるので、12.288 ~–12.288Vが入力範囲になります。

 ここでは、0010bに変更して、6.144~–6.144V、LSBは46.875 µVに設定を変更します。

スケッチ

 setup()内の、

Serial.println("\write DATAOUT_CTL_REG Register---- ");

は、デフォルト値を書き込んでいるだけですが、この処理がないと、レンジの書き込みが行われませんでした。

 4バイトの書き込みの最初は7ビットですが、7ビットのまま書き込める時とそうでないときがあります。最後に0(9ビットのアドレスの最初の0)を追加して8ビットにしたほうが良いように思えます。ただ、TI社のQ&Aを見ると、7ビットのまま書き込んでいる事例があります。その時の質問ではMCUはSTM32でした。

 つづくのは9ビットのアドレスです。データシートには、アドレスは8ビットしか書かれていません。データシートには、最後の0は常に無視されると説明があります。

 TI社のQ&Aでは、7ビット 9ビット 8ビット 8ビットになっています。

  <11010_xx> <0_0010_0000><00000000><00000000>

これを、ずらして、全部8ビットにしてみました。

 読み出しは、16ビットの事例と8ビットの2通りを記述しています。どちらも二度目の読み出しの値を表示しています。

 ADS8699_0a.ino


#include  <SPI.h> 
#define CS  9
#define RST 8
const float LSB = 46.875;  // 1.5VxVref 0010b
//ADS8699
SPISettings settings(10000000, MSBFIRST, SPI_MODE0);

void setup() {
  pinMode(RST, OUTPUT);
  digitalWrite(RST, HIGH);  // reset
  delay(0.1);
  digitalWrite(RST, LOW);
  delay(0.1);
  digitalWrite(RST, HIGH);
  pinMode(CS, OUTPUT);
  digitalWrite(CS, HIGH);
  Serial.begin(9600);
  while(!Serial);
  Serial.println("\nADS8699 test");
  SPI.begin();
    Serial.println("\write DATAOUT_CTL_REG Register---- ");
      SPI.beginTransaction(settings);
        digitalWrite(CS, LOW);
            uint8_t  highByte = SPI.transfer(0b11010000); // 
            uint8_t  midByte  = SPI.transfer(0b00100000); // 0x10 _0
            uint8_t  lowByte = SPI.transfer(0x00);  // 
            uint8_t  lowlowByte= SPI.transfer(0b00000000);  // real data
        digitalWrite(CS, HIGH);
      SPI.endTransaction();
        delay(0.2);

  Serial.println("\nwrite range ");
      SPI.beginTransaction(settings);
        digitalWrite(CS, LOW);
            highByte = SPI.transfer(0b11010100); // 11010_10_ LS
            midByte =  SPI.transfer(0b00101000); // 0x14 _0
            lowByte = SPI.transfer(0x00);  // 
            lowlowByte = SPI.transfer(0b00000010);  // 2
        digitalWrite(CS, HIGH);
      SPI.endTransaction();
      delay(0.2);
}

int read_range(){
  Serial.print("\nread range ------ ");
      SPI.beginTransaction(settings);
        digitalWrite(CS, LOW);
            uint8_t  highByte = SPI.transfer(0b11001000); // 11001_xx_ read range1
            uint8_t  midByte =  SPI.transfer(0b00101000); // 14
            uint8_t  lowByte =  SPI.transfer(0x00);  // 
            uint8_t  lowlowByte = SPI.transfer(0x00);  // 
        digitalWrite(CS, HIGH);
    SPI.endTransaction();
    delay(0.2);
      SPI.beginTransaction(settings);
        digitalWrite(CS, LOW);
            highByte = SPI.transfer(0b11001000); // 11001_xx_ read range2
            midByte =  SPI.transfer(0b00101000); // 14
            lowByte = SPI.transfer(0x00);  // 
            lowlowByte = SPI.transfer(0x00);  // 
        digitalWrite(CS, HIGH);
      SPI.endTransaction();
    Serial.print(highByte,BIN);Serial.println(midByte,BIN);
    Serial.print(highByte,HEX);Serial.print("," );
    Serial.print(midByte,HEX); 

    //  Serial.print("\nread range 1byte------ ");
      SPI.beginTransaction(settings);
        digitalWrite(CS, LOW);
            highByte = SPI.transfer(0b01001000); // 11001_xx_ read range1
            midByte =  SPI.transfer(0b00101000); // 14
            lowByte =  SPI.transfer(0x00);  // 
            lowlowByte = SPI.transfer(0x00);  // 
        digitalWrite(CS, HIGH);
      SPI.endTransaction();
      delay(0.2);
      Serial.print("\nread range 1byte------ ");
      SPI.beginTransaction(settings);
        digitalWrite(CS, LOW);
            highByte = SPI.transfer(0b01001000); // 11001_xx_ read range1
            midByte =  SPI.transfer(0b00101000); // 14
            lowByte =  SPI.transfer(0x00);  // 
            lowlowByte = SPI.transfer(0x00);  // 
        digitalWrite(CS, HIGH);
      SPI.endTransaction();
      Serial.println(highByte,BIN);
      Serial.print(highByte,HEX);Serial.print("," );
      Serial.println(midByte,HEX); //Serial.print("," );
    delay(0.2);
}

void loop() {
  read_range();

  delay(3000);
}

 実行例です。設定したレンジ0010bが読み出せています。

前へ

電圧計を作る ① ADS8699のスペック

次へ

電圧計を作る ③ ADS8699のスケッチ その2 アナログ電圧の読み出し