MCP4726の使い方

MCP4726はI2Cで通信制御するD/A変換です。 MCP4726のコマンド覚書▽マニュアルはこちら を参照して下さい。秋月電子の該当ページはこちらにあります。

わかりにくいですが、下の写真の赤矢印で示した白丸が1番ピンです。



回路図は以下の通りです。D/A変換は、VSSからVDDの範囲で行われます。VREFは使いませんでした。 VREFを使う場合は、VSSからVREFの範囲でD/A変換が行われます。ただし、VREF <= VDD でなければなりません。



揮発性 DAC レジスタ書き込み

基本的にはこのモードで書き込めば欲しい電圧を得る事ができます。 出力電圧は12ビット0から4095 (0x000 - 0xFFF)で指定します。 最小限のパラメータ変更によってアナログ出力を手早く更新する時に使います

1: 0 1 1 0 0 0 0 0
2: 0 0 PD1 PD0 B11 B10 B9 B8
3: B7 B6 B5 B4 B3 B2 B1 B0

下のプログラムの場合、書き込んだ2byteで0x800を表しています。
5v × (0x800/0xFFF) ≒ 2.5v が出力されます。

PD0, PD1についてはのコンフィグレーションを参照して下さい。

Wire.setClockは、I2C通信のクロックスピードを設定しています。 このデバイスはファーストモード400kHzにも対応しています。この行がない場合は100kHzの標準モードで動作します。

// include the I2C library:
#include <Wire.h>
    
void setup() {
  // デバイスアドレス(スレーブ)
  uint8_t DEVICE_ADDRESS=0x60;

  // マスタとしてI2Cバスに接続する
  Wire.begin();
  Wire.setClock(400000);  // I2C First Mode
  delay(100);
  
  Wire.beginTransmission(DEVICE_ADDRESS);
  Wire.write(B00001000);  //0x08  PD==0/PD1=0
  Wire.write(B00000000);  //0x00
  Wire.endTransmission();
}
揮発性メモリ書き込み

揮発性の DAC レジスタの値とコンフィグレーション ビットの更新に使います。EEPROM はこのコマンドの影響を受けません。

1: 0 1 1 0 0 0 0 0
2: 0 1 0 VREF1 VREF0 PD1 PD0 G
3: B11 B10 B9 B8 B7 B6 B5 B4
4: B3 B2 B1 B0

全メモリ書き込み

揮発性と不揮発性(EEPROM)のDACレジスタの値とコンフィグレーションビットの更新に使います。 不揮発性レジスタは、電源を入れた瞬間に所定の電圧を出したい時に使います。

1: 0 1 1 0 0 0 0 0
2: 0 1 1 VREF1 VREF0 PD1 PD0 G
3: B11 B10 B9 B8 B7 B6 B5 B4
4: B3 B2 B1 B0

以下のプログラムは電源投入時にVDDと同じ電圧を出力する設定です。

// include the I2C library:
#include <Wire.h>

void setup() {
  // デバイスアドレス(スレーブ)
  uint8_t DEVICE_ADDRESS = 0x60;  // B01100000

  // マスタとしてI2Cバスに接続する
  Wire.begin();
  Wire.setClock(400000);  // I2C First Mode
  delay(100);

  Wire.beginTransmission(DEVICE_ADDRESS);
  Wire.write(B01100000); //全メモリ書き込み, VREF1/0=0 PD1/0=0 G=0
  Wire.write(B11111111); //FFH
  Wire.write(B11110000); //F0H
  Wire.endTransmission();
}

揮発性コンフィギュレーションの書き込み

揮発性コンフィグレーションレジスタビットだけを更新する場合に使います。

1: 0 1 1 0 0 0 0 0
2: 1 0 0 VREF1 VREF0 PD1 PD0 G

読み出しコマンド

このコマンドは、デバイスの全メモリを読み出します。読み出されるデータは、揮発性と不揮発性 (EEPROM)のDACレジスタの値とコンフィグレーション ビット、揮発性のステータスビットです。

1: 0 1 1 0 0 0 0 0

  Wire.requestFrom(DEVICE_ADDRESS, 8);
  while(Wire.available())  {
    unsigned char c = Wire.read();      // 1バイトを受信
    Serial.print(c,HEX);
    Serial.print(" ");
  }
  Serial.println(" ");

受信結果

1: 1 1 0 VREF1 VREF0 PD1 PD0 G
2: RAM B11-B08
3: RAM B7-B0 00
4: E0H
5: ROM B11-B08
6: ROM B7-B0 00

コンフィギュレーションビット

パワーダウン・ビットと出力抵抗性負荷

PD1 PD0 動作
0 0 通常動作
0 1 1kΩ抵抗を介してグランドに接続
1 0 125kΩ抵抗を介してグランドに接続
1 1 640kΩ抵抗を介してグランドに接続

ゲイン選択ビット

G 動作
0 x1 ( ゲイン 1)
1 2x ( ゲイン 2)。VRL として VDD を使う場合は適用されません。
VREF = VDD とした場合、デバイスはゲイン選択ビット (G) の設定に関係なくゲイン =x1 のみを使用します。




抵抗ラダー参照電圧 (VRL) 選択ビット

VREF0 VREF1 動作
0 x VDD ( バッファなし )
0 1 VREF ピン ( バッファなし )
1 0


サンプルプログラム

ノコギリ波を発生するサンプルプログラムです。 loopが回る度にregの値をインクリメントしD/A変換に設定しています。

#include <Wire.h>   // include the I2C library:
uint8_t DEVICE_ADDRESS = 0x60;  // B01100000

void setup() {
  Wire.begin();           //Connect I2C bus
  Wire.setClock(400000);  // I2C First Mode
  delay(100);
}

uint16_t reg=0;

void loop() {
  Wire.beginTransmission(DEVICE_ADDRESS);
  Wire.write((reg>>8)&0x0F);
  Wire.write(reg&0xFF);
  Wire.endTransmission();
  reg++;
  reg&=0xFFF;
}

出力波形は以下のようになりました。だいたい0.47secが1周期になります。 0.47secで4096点インクリメントしていますので、だいたい100usecごとにloopが処理されていることがわかります。 ただし、この結果は16MHzで動作しているArduino Microでの結果です。



Arduino Due(84MHz)で同じプログラムを動作させてみました。1周期は0.3secでした。思ったほどは早くなりませんでした。 I2Cという通信方法が遅いためと思われます。