MAD7991は4チャンネルのADコンバータ(AD7991)を搭載したモジュールです。 I2Cシリアルインターフェースでコントロールすることができます。 4チャンネルの入力として使うか、3チャンネル入力とリファレンス入力として使うかを選択できます。

ADコンバータAD7991のデータシートはアナログデバイスの こちらのページからダウンロードできます。
ArduinoとMAD7991との接続は次の回路図の通りです。 SCL, SDAはボード内で既にプルアップされています。

Raspberry Piを使う場合の接続は次の通りです。

AD7991を直接使う場合は、ピン番号が異なります。 また、I2Cの信号線、SCL, SDAは2.2kΩの抵抗でプルアップが必要です。
setup()でI2Cの動作周波数は3.4MHz(ハイスピードモード)に設定します。 I2Cのアドレスはボードの取り扱い説明書右下の「仕様」にある通り0x28です。 A/D変換のデータを読み込むだめには、AD7991のレジスタ、上位4ビットで設定します。

#include <Wire.h>
#define AD7991_ADDRESS 0x28 // AD7991のI2Cアドレス (データシート参照)
#define MAX_CLOCK 3400000 // I2Cの動作周波数 340kHz
#define REG_CH0 0x10 // チャンネル0
#define REG_CH1 0x20 // チャンネル1
#define REG_CH2 0x40 // チャンネル2
#define REG_CH3 0x80 // チャンネル3
void setup() {
// put your setup code here, to run once:
Wire.begin(); // 接続の初期化
Wire.setClock(MAX_CLOCK); // I2Cの動作周波数
Serial.begin(115200);
}
uint16_t readADC(uint8_t channel) {
Wire.beginTransmission(AD7991_ADDRESS);
Wire.write(channel); // チャンネル選択
Wire.endTransmission();
delay(10); // データ準備の待機
Wire.requestFrom(AD7991_ADDRESS, 2); // 2バイトのデータを要求
if (Wire.available() == 2) {
uint8_t msb = Wire.read();
uint8_t lsb = Wire.read();
return ((uint16_t)(msb&0x07) << 8)+lsb; // 12ビットデータの取得
}
return 0; // エラー時
}
void loop() {
char chr[256];
// put your main code here, to run repeatedly:
uint16_t adcValue = readADC(REG_CH0);// チャンネル0からデータを取得
sprintf(chr,"%04x ",adcValue);
Serial.print(chr);
adcValue = readADC(REG_CH1); // チャンネル1からデータを取得
sprintf(chr,"%04x ",adcValue);
Serial.print(chr);
adcValue = readADC(REG_CH2); // チャンネル2からデータを取得
sprintf(chr,"%04x ",adcValue);
Serial.print(chr);
adcValue = readADC(REG_CH3); // チャンネル3からデータを取得
sprintf(chr,"%04x\n",adcValue);
Serial.print(chr);
delay(50); // 50ms待つ
}
#include <wiringPiI2C.h>
#include <stdio.h>
#include <unistd.h> // usleep() のため
#define I2C_ADDR 0x28 // I2Cデバイスのアドレス
#define REG_CH0 0x10
#define REG_CH1 0x20
#define REG_CH2 0x40
#define REG_CH3 0x80
uint8_t mChSel[4]={REG_CH0, REG_CH1, REG_CH2, REG_CH3};
uint16_t readAD(int fd, uint8_t channel)
{
wiringPiI2CWrite(fd, channel);
usleep(1000); // 1ms 待機
// 2バイトのデータを取得
char data[2];
if (read(fd, data, 2) != 2) {
return 0;
}
// 12ビットデータに変換(MSBの下位4ビットとLSBを結合)
uint16_t adc_value = ((data[0] & 0x0F) << 8) | data[1];
return(adc_value);
}
int main() {
int fd;
uint16_t adc[4];
// I2Cデバイスを開く
fd = wiringPiI2CSetup(I2C_ADDR);
if (fd == -1) {
printf("I2Cデバイスを開けませんでした\n");
return 1;
}
while(1){
for(int i=0; i<4; i++){
adc[i]=readAD(fd,mChSel[i]);
}
for(int i=0; i<4; i++){
printf("%04x ",adc[i]);
}
printf("\n");
usleep(50000); // 50ms 待機
}
return 0;
}
上のプログラムではレジスターの読み込みにread(fd, data, 2)という関数を使っています。 最初は以下のwiringPiI2CRead()関数を使っていました。 しかし、下のプログラムではdata[0]とdata[1]が同じ値 、lsb側のdata[1]がmsb側のdata[0]と同じ、になってしまいました。
data[0] = wiringPiI2CRead(fd); data[1] = wiringPiI2CRead(fd);
I2Cの動作クロックを設定するには、WiringPiには関数が準備されていません。 /boot/firmware/config.txtを編集します。編集の後でrebootします。
dtparam=i2c_arm=on dtparam=i2c_arm_baudrate=340000
