MCP4728 は4ch出力、I2C IFのDA コンバータである。DAの出力CHを増やしたいときにはDACデバイスを追加すればいいのですが、同じI2Cバスに接続されているMCP4728はI2Cアドレスをユニークに設定する必要がある。一般的にEEPROMなどで同種のデバイスを同じI2C上に配置しているときにはアドレス設定用に設けられているデバイスピンを組み合わせることでI2Cアドレスを変更することができる。MCP4728も自分のデバイスI2Cアドレスを8通りのユニークアドレスに設定できるのですがデバイスピンの組み合わせで設定するのではなく、EEPROMにアドレスを書き込む仕組みを用いている。この手法はかなり稀であり、特殊なやり方。
その手順は以下の通り。(MCP4728 datasheet抜粋)

上記仕様書にもあるようにI2Cデータ書き込み時、2byte目のACKの直前CLKの”low”の期間でLDACをLOWにする必要がある。これが一番の課題!
一般的なI2CのCLK 周波数を400kHzとしたとき、このlow期間は約1.25usecとなる。
この時間は立下り割り込みを検出したとしても小規模マイコンでは割り込み処理のレジスタ退避などのオーバーヘッドを考慮するとかなりクリティカルなタイミングとなる。
ここではとりあえずPSoCマイコンを使ってMCP4728の動作テストしていたので、ついでにこのマイコン上でI2Cアドレス変更するためのLDACタイミグ信号を作ってみることにする。



初期検討段階ではI2C writeと同時にある一定のDelayをかけてLDACにつながるGPIOポートをHigh→lowに制御させようとしていたが、あまりにもタイミグのばらつきと、調整分解能が悪かったため、この手法はボツになった。
そのほか使えそうな2種類のやり方について述べる。
割込み方式
① Counterを用いてI2CのCLKの立下りエッジを18個カウントして、割り込みを発生させる
② 割り込みハンドラの中でGPIOに接続されたLDACをHIGH→LOWにする。
DFFを使用した全H/Wロジックによるタイミグ生成方式
① I2Cの転送API関数をCALLする前にControl_regを用いてDFFのqの出力レベルを”HIGH”し、次のDFFへのclk入力でqの出力が”LOW”になるように準備をしておく。
② Counterを用いてI2CのCLKの立下りエッジを18個カウントして、tcトリガ(パルス)を発生させる
③ tcはDFFのclk入力に接続されているので、tcトリガ信号が入力されると当時にDFFのq出力(LDAC相当の信号)を”LOW”にする。
今回MCP4728のI2Cアドレスを変更する関数を作成。mcp4728_chaddr()
CY_ISR(IsrCounter)
{
// 割り込みハンドラ
// 21回目のdown edgeで割込み発生!(本当は18回目検出)
LDAC_Write(0);
}
// =====================================
/** @ingroup mcp4728_chaddr
@brief Change mcp4728 Device address
@param [in] currentaddr:(0-7)
newadder:(0-7)
You will need to manipulate the LDAC pin.
@param [out] none
@return none
*/
// ======================================
extern uint8 mcp4728_chaddr(BYTE currentaddr, BYTE newadder)
{
BYTE dev, data[3];
LDAC_Write(1); //initial value is LDAC=High
Control_Reg_Write(0x05); // reset Counter & D(DFF)=high
Control_Reg_Write(0x07); // Clock set Q=high
Control_Reg_Write(0x00); // Clock set D(DFF)=low, Counter Active
dev = 0x60|(currentaddr & 0x07);
data[0] = CHANGE_ADDER | ((currentaddr & 0x07) << 2) | 0x01;
data[1] = CHANGE_ADDER | ((newadder & 0x07) << 2) | 0x02;
data[2] = CHANGE_ADDER | ((newadder & 0x07) << 2) | 0x03;
#ifndef INVALIDI2C
I2C_1_MasterClearStatus();
I2C_1_MasterWriteBuf(dev, data, 3, I2C_1_MODE_COMPLETE_XFER);
int i = 0;
while (!(I2C_1_MasterStatus() & I2C_1_MSTAT_WR_CMPLT)){
stat[i++] = I2C_1_MasterStatus();
/*if(I2C_1_MSTAT_ERR_MASK & I2C_1_MasterStatus() > 0) {
return I2C_1_MasterStatus();
}*/
}
#endif
Control_Reg_Write(1); // Stop the LDAC timing counter(reset asart)
LDAC_Write(1); // LDAC=High
}
動作タイミグ評価
下記2種類で生成したLDACのタイミグ生成を測定したロジアナ波形を示す。
赤色で示している範囲が今回目標としているタイミグ範囲。この中でhigh→lowに変化するタイミグ信号が必要。

割込みでGPIO 操作しても対象となるCLKのlowの区間でLDACをhigh→lowできなかったケース(3.575usec)。一方、FFを使ってタイミグ生成をする方法では問題ない。(155nsec)


割込みでもCLKのlowの区間でGPIOによりLDACをhigh→lowに制御できた場合。(1.345usec)
FFを使ってタイミグ生成をする方法では操作タイミングは安定している。(155nsec)
上記の結果からLDACを所望のタイミングで制御する方式は割込み方式では不安定になることが判った。


上記はDevice address変更操作が正常に終了した場合のロジック波形であるが、もし、LDACを正しいタイミングで制御しないと、この後のACKはすべてNAKになって失敗する。
PSoC3でもDFF方式であれば問題なくLDACタイミング生成できることもわかった。
逆にPSoC3では割り込み形式ではI2C CLKタイミグで1CLOCK安定してずれてしまう。

