電圧計を作る ② 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が読み出せています。