ワンチップマイコンの簡易開発環境を備えたArduinoを使ってDSD1794AのI2Cによるレジスタコントローラを作成したので紹介する。(Arduinoの使い方についてはHPなどを参照のこと。開発言語はCがベースなのでその基礎知識は必要)
コントローラ仕様
使用部品
マイコンArduino Pro-mini 5V
LCD SC1602BBWB-XA-GB-G(白抜き液晶)
外部入出力(Arduinoのピン番号:接続先内容)
A0:VR (減衰量0dB〜-62dB,MUTE)
A1:Serial Format(RJ16,RJ20,RJ24,LJ24,I2S24,I2S16)
A2:Over Sampling Rate(x32H,x32L,x64H,x64L,x128H,x128L)
A2:Digital Filter(H:Sharp roll off, L:Slow roll off)
A4:SDA(I2C,TWI)
A5:SCL(I2C,TWI)
D6:E (LCD)
D7:R/W (LCD)
D8:RS (LCD)
D9:DB4 (LCD)
D10:DB5(LCD)
D11:DB6 (LCD)
D12:DB7 (LCD)
1. プログラムの概要
Arduinoプログラムは基本的にsetup()とloop()関数からなる。
setup()は主に初期設定をする関数
loop()関数が動作のメインになる。これが自動的に繰り返される。
2. レジスタ書込み方法
I2C規格のDACレジスタの書込みの基本は次の様なセットで行う。
Wire.beginTransmission(DACのI2Cアドレス)
Wire.send(レジスタ番号)
Wire.send(書込むデータ)
Wire.endTransmission()
レジスタ、データ値はbyteサイズだが、LCD表示がbyte変数ではうまくいかないのでint宣言にしたほうが良い。
連続したレジスタはデータsendの所を繰り返して、最後にWire.endTransmission()
一括で送れる。
void registerSet()参照
3. レジスタ読込み方法
I2C規格のDACレジスタの読込みの基本は次のようなセットになる。
Wire.beginTransmission(DACのI2Cアドレス)
Wire.send(レジスタ番号)
Wire.endTransmission()で読み込みアドレスの先頭番号をセット
Wire.requestFrom(レジスタ番号、読取レジスタ数);
Wire.available()が0の間待つ
Wire.receive()の実行で返す値がレジスタ値なのでこれを読込む(変数に代入する)
連続読取の場合はWire.requestFrom()の読取レジスタ数分Wire.receive()を繰り返す。
void loop()参照
4. VR値の変換
アナログの読取値は0〜1023なのでこれをVRレジスタ値の0〜255に割り当てる。ビット落ちを避ける上でもあまり絞り込んだ状態は使いたくないので、0〜-20dBを広く割り当てて、127以下は使っていない。
0〜20:mute、23〜530:-62〜-21dB、531〜1010:-20dB〜0dB、1011〜1023:0dBと割り当てている。
ちなみに-9〜0dBの間は表示がずれるので補正している。
void calcurateVR(int vr)参照
5. ロータリースイッチ
Serial Format, Sampling Rate, Digital Filterの設定はアナログ入力のレベルで行った。ロータリースイッチは同一抵抗をVDDからVSSにシリアルに(選択数-2)本並べてその間を切り替える。
Ex. 6選択の場合
VSS--R--+--R--+--R--+--R--+--R--VDD
↑ ↑ ↑ ↑ ↑ ↑
1 2 3 4 5 6
6.LCD表示内容
レジスター値の表示はデバック用。17〜20までを表示。下段はVR値、フォーマット、
オーバーサンプリングレート、デジタルフィルターを表す。
プログラム詳細(デバック版)
/*
* Controler for DSD1794A
* LCD+VR,2R-SW with register Monitor
* 2010/04/07
* V1.0
*/
// include the library code:
#include <LiquidCrystal.h>
#include <Wire.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(8, 7, 6, 9, 10, 11, 12);
//TWI address of DSD1794A
#define DSD1794AR 0x9c >> 1
#define DSD1794AL 0x9E >> 1
#define registerTop 18
#define registerVrNumber 16
// analog input Pin number
#define vrPin 0 // 音量
#define dataFormatPin 1 //データフォーマット
#define overSamplingPin 2 //オーバーサンプリング
#define ledPin 13 // DIGITALの13番にオンボードのLED
#define mutePin 5
// register data
int setregisterR[3] = {168,0,12}; //RJ24 ,Sharp rolloff,x64
int setregisterL[3] = {168,0,8};
int registerM[4]; //Monitor
int count=0;
int VR ; //VR data
int VRlast = -1; //VR last dat
void setup() {
//LEDモニター、mute出力モード設定
pinMode(ledPin,OUTPUT);
digitalWrite(ledPin,LOW);
pinMode(mutePin,OUTPUT);
digitalWrite(mutePin,LOW);
// set up the LCD's
lcd.begin(16, 2);
//初期表示設定
lcd.home();
lcd.print("reg=");
lcd.setCursor(6,1);
lcd.print("RJ24");
lcd.setCursor(12,1);
lcd.print("x64H");
//I2C/WTI intialize
Wire.begin();
//DAC register initialize
registerSet();
//VR set
calcurateVR(analogRead(vrPin));
// Mute off
digitalWrite(mutePin,HIGH);
}
void loop() {
int e1,e2;
byte r1,r2,r3;
if (count >9){
digitalWrite(ledPin,HIGH);
count = 0;
r1 = (analogRead(dataFormatPin)+102) / 204;
r1 = r1 << 4;
// register の dataFormat mask
r2 = setregisterR[0] & 0x70;
if(r1 != r2){
setregisterR[0] = (setregisterR[0] & 0x8f) | r1;
setregisterL[0] = setregisterR[0];
registerSet();
registerFormatDisp(r1);
}
//overSampling Rate OS1,0 check 20-B0,B1
r1 = (analogRead(overSamplingPin)+102) / 204;
r3 = r1 / 2;
r2 = setregisterR[2] & 0x03;
if (r3 != r2){
setregisterR[2] = (setregisterR[2] & 0xfc) | r3;
setregisterL[2] = setregisterR[2];
registerSet();
registerRateDisp(r1);
}
// FLT register check 19-B1
r3 = (r1 & 0x01) << 1;
r2 = setregisterR[1] & 0x02;
if (r3 != r2){
setregisterR[1] = (setregisterR[1] & 0xfd) | r3;
setregisterL[1] = setregisterR[1];
registerSet();
registerRateDisp(r1);
}
digitalWrite(ledPin,LOW);
}else {
delay(100);
}
count = count + 1;
VR = analogRead(vrPin);
if (VRlast != VR){
VRlast = VR;
calcurateVR(VR);
}
//test
Wire.beginTransmission(DSD1794AR);
Wire.send(17);
Wire.endTransmission();
Wire.requestFrom(DSD1794AR,4);
for(int i=0 ; i<4 ;i++){
while (Wire.available() == 0){}
registerM[i] = Wire.receive();
}
lcd.setCursor(4,0);
lcd.print(registerM[0]);
lcd.print(",");
lcd.print(registerM[1]);
lcd.print(",");
lcd.print(registerM[2]);
lcd.print(",");
lcd.print(registerM[3]);
lcd.print(" ");
}
void registerSet(){
int e1,e2;
//Rch register set
Wire.beginTransmission(DSD1794AR);
Wire.send(registerTop);
for (int i; i<3 ;i++){
Wire.send(setregisterR[i]);
}
e1 = Wire.endTransmission();
//Lch register set
Wire.beginTransmission(DSD1794AL);
Wire.send(registerTop);
for (int i; i<3 ;i++){
Wire.send(setregisterL[i]);
}
e2 = Wire.endTransmission();
if ( e1 | e2 ){
lcd.setCursor(0,1);
lcd.print("R-error!");
}
}
void registerFormatDisp(byte r){
lcd.setCursor(6,1);
r = r >> 4;
switch (r){
case 0:
lcd.print("RJ16 ");
break;
case 1:
lcd.print("RJ20 ");
break;
case 2:
lcd.print("RJ24 ");
break;
case 3:
lcd.print("LJ24 ");
break;
case 4:
lcd.print("I2S16");
break;
case 5:
lcd.print("I2S24");
break;
default:
lcd.print("Ferr!");
}
}
void registerRateDisp(byte r){
lcd.setCursor(11,1);
switch(r){
case 0:
lcd.print(" x64H");
break;
case 1:
lcd.print(" x64L");
break;
case 2:
lcd.print(" x32H");
break;
case 3:
lcd.print(" x32L");
break;
case 4:
lcd.print("x128H");
break;
case 5:
lcd.print("x128L");
break;
default:
lcd.print("err!");
}
}
void calcurateVR(int vr){
int e1,e2;
int VRdisp ; //VR dB value
int registerVR;
lcd.setCursor(0,1);
//lcd.print(" ");
// calucurate vr data
vr = vr / 3 ;
if (vr < 7){
lcd.setCursor(0,1);
lcd.print(" MUTE");
registerVR = 0;
}
else if(vr <177){
VRdisp = -20-(176-vr)/4;
lcd.print(VRdisp);
lcd.print("dB");
registerVR = 215-(176-vr)/2;
}
else if (vr <257){
VRdisp = -10-(256-vr)/8;
lcd.print(VRdisp);
lcd.print("dB");
registerVR = 235-(256-vr)/4;
}
else if (vr <337){
VRdisp = -(336-vr)/8;
lcd.print(" ");
lcd.print(VRdisp);
lcd.print("dB");
registerVR = 255-(336-vr)/4;
}
else {
lcd.print(" 0dB");
registerVR = 255;
}
// Rch VR set
Wire.beginTransmission(DSD1794AR);
Wire.send(registerVrNumber);
Wire.send(registerVR);
Wire.send(registerVR);
e1 = Wire.endTransmission();
// Lch VR set
Wire.beginTransmission(DSD1794AL);
Wire.send(registerVrNumber);
Wire.send(registerVR);
Wire.send(registerVR);
e2 = Wire.endTransmission();
if ( e1 | e2){
lcd.setCursor(0,1);
lcd.print("V-err!");
}
}