1

Тема: DAC WM8805 + WM8740 (Arduino)

Основная тема - http://rcl-radio.ru/?p=90769

#define CS    2  // ML    WM8740
#define CLK   3  // MC    WM8740
#define DATA  4  // MD    WM8740
#define CSB   5  // CSB   WM8805
#define SCLK  6  // SCLK  WM8805
#define SDIN  7  // SDIN  WM8805
#define SDOUT 11 // SDOUT WM8805
          //  9  // CLK   ENCODER
          //  8  // DT    ENCODER
          // 10  // SW    ENCODER
          // 12  // MUTE  BUTTON

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include <Encoder.h>  // http://rcl-radio.ru/wp-content/uploads/2019/05/Encoder.zip
#include <MsTimer2.h> // http://rcl-radio.ru/wp-content/uploads/2018/11/MsTimer2.zip
LiquidCrystal_I2C lcd(0x27,16,2);  // Устанавливаем дисплей
Encoder myEnc(9, 8);//CLK, DT
      byte v1[8] = {0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07};
      byte v2[8] = {0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00};      
      byte v3[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x1F};
      byte v4[8] = {0x1F,0x1F,0x00,0x00,0x00,0x00,0x1F,0x1F};
      byte v5[8] = {0x1C,0x1C,0x00,0x00,0x00,0x00,0x1C,0x1C};
      byte v6[8] = {0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C};
      byte v7[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07};
      byte v8[8] = {0x1F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00};
      unsigned long times,times1,oldPosition  = -999,newPosition;
      byte menu,w,w1,www=1,mute;
      int vol,vol_d,ball,err,err_old,a[3],in;
      byte i,d1,d2,d3,d4,d5,d6,e1,e2,e3;

void setup(){
   lcd.init();lcd.backlight();
   lcd.createChar(1, v1);lcd.createChar(2, v2);lcd.createChar(3, v3);lcd.createChar(4, v4);lcd.createChar(5, v5);lcd.createChar(6, v6);lcd.createChar(7, v7);lcd.createChar(8, v8);
   MsTimer2::set(1, to_Timer);MsTimer2::start();
   Serial.begin(9600);
   lcd.setCursor(0,0);lcd.print(" WM8805  WM8740 ");
   lcd.setCursor(0,1);lcd.print("2IS-24bit-192kHz");
  if(EEPROM.read(100)!=0){for(int i=0;i<101;i++){EEPROM.update(i,0);}}// очистка памяти при первом включении
   pinMode(10,INPUT);   // SW энкодер  
   pinMode(12,INPUT_PULLUP); // кнопка MUTE    
   pinMode(CS,OUTPUT);  // ML WM8740
   pinMode(CLK,OUTPUT); // MC WM8740
   pinMode(DATA,OUTPUT);// MD WM8740
//////////////////////////////////////////
   pinMode(CSB,OUTPUT);  // CSB   WM8805
   pinMode(SCLK,OUTPUT); // SCLK  WM8805
   pinMode(SDIN,OUTPUT); // SDIN  WM8805
   pinMode(SDOUT,INPUT); // SDOUT WM8805
   delay(100);
   vol = EEPROM.read(0);in = EEPROM.read(1);ball = EEPROM.read(9)-10;
// Write WM8740 SPI
  WM8740Write(0b000100000000 + vol + ball);//reg0
  WM8740Write(0b001100000000 + vol - ball);//reg1
  WM8740Write(0b010000001000);//reg2
  WM8740Write(0b011000000001);//reg3
  WM8740Write(0b110000000000);//reg4
  delay(100);
// Write WM8805 SPI
  WM8805Write(0x00, 0x01); // RESET
  WM8805Write(0x03, 0xBA); // PPL_K 0xBA
  WM8805Write(0x04, 0x49); // PPL_K 0x49
  WM8805Write(0x05, 0x0C); // PPL_K 0x0C
  WM8805Write(0x06, 0x08); // PLL_N 0x08
  WM8805Write(0x07, 0b00101000);// 00 CLKOUTDIV[1:0] MCLKDIV FRACEN>!!! FREQMODE[1:0]
  WM8805Write(0x08, 0b01110000 + in);// MCLKSRC ALWAYSVALID FILLMODE CLKOUTDIS CLKOUTSRC RXINSEL[2:0]>000:PX0
  WM8805Write(0x09, 0b11111111);// SPDIFINMODE[7:0]>gain
  WM8805Write(0x0A, 0b00000000);// MASK[7:0]
  WM8805Write(0x12, 0b00000000);// CHSTMODE[1:0] DEEMPH[2:0] CPY_N AUDIO_N CON/PRO
  WM8805Write(0x13, 0b00000000);// CATCODE[7:0]
  WM8805Write(0x14, 0b00000000);// CHNUM2[1:0] CHNUM1[1:0] SRCNUM[3:0]
  WM8805Write(0x15, 0b00110001);// TXSTATSRC TXSRC CLKACU[1:0] FREQ[3:0] // default
  WM8805Write(0x16, 0b00001011);// ORGSAMP[3:0] TXWL[2:0]>101:24bit MAXWL>1:24bit_max
  WM8805Write(0x1B, 0b00001010);// 00 AIFTX_LRP AIFTX_BCP AIFTX_WL[1:0] AIFTX_FMT[1:0]
  WM8805Write(0x1C, 0b01001110);// SYNC_OFF>0:no_sound AIF_MS>1:master AIFRX_LRP AIFRX_BCP AIFRX_WL[1:0]>11:24bit AIFRX_FMT[1:0]>10:I2S
  WM8805Write(0x1D, 0b01000000);// SPD_192K_EN WL_MASK SPDGPO WITHFLAG CONT READMUX[2:0]
  WM8805Write(0x1E, 0b00000100);// 00 TRIOP AIFPD OSCPD SPDIFTXPD SPDIFRXPD PLLPD
  delay(1000);lcd.clear();
  }

void loop(){ 
 /// MENU //////////////////////////////
  if(digitalRead(10)==LOW){menu++;if(menu>2){menu=0;};delay(200);lcd.clear();times=millis();w=1;w1=1;www=1;}

 /// MUTE /////////////////////////////
 if(digitalRead(12)==LOW && mute==0){mute=1; WM8740Write(0b010000001001);delay(300);www=1;} 
 if(digitalRead(12)==LOW && mute==1){mute=0; WM8740Write(0b010000001000);delay(300);www=1;}  

 /// VOLUME /////////////////////////////////// 
   if(menu==0){
  if (newPosition != oldPosition){oldPosition = newPosition;www=0;
     vol=vol-newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w1=1;
      if(vol<145){vol=145;}if(vol>245){vol=245;}
    WM8740Write(0b000100000000 + vol + ball);//reg0
    WM8740Write(0b001100000000 + vol - ball);//reg1
    Serial.print("VOLUME ");Serial.println(vol);// vol = 145...245 step 0.5 dB + 10 balance
  }
  if(www==1||w==1){www=0;w=0;
      if(mute==1){        lcd.setCursor(0,0);lcd.print("MUTE    ");}
      if(err==0&&mute==0){lcd.setCursor(0,0);lcd.print("VOLUME  ");}
      if(err>0&&mute==0){ lcd.setCursor(0,0);lcd.print("NO SOUND");}
 
      lcd.setCursor(0,1);lcd.print("COAX ");lcd.print(in);
     vol_d=vol-146;a[0]=vol_d/10;a[1]=vol_d%10;
      for(i=0;i<2;i++){
      switch(i){
        case 0: e1=9,e2=10,e3=11;break;
        case 1: e1=12,e2=13,e3=14;break;
        }
      switch(a[i]){
        case 0: d1=1,d2=8,d3=6,d4=1,d5=3,d6=6;break;
        case 1: d1=32,d2=2,d3=6,d4=32,d5=32,d6=6;break;
        case 2: d1=2,d2=8,d3=6,d4=1,d5=4,d6=5;break;
        case 3: d1=2,d2=4,d3=6,d4=7,d5=3,d6=6;break;
        case 4: d1=1,d2=3,d3=6,d4=32,d5=32,d6=6;break;
        case 5: d1=1,d2=4,d3=5,d4=7,d5=3,d6=6;break;
        case 6: d1=1,d2=4,d3=5,d4=1,d5=3,d6=6;break;
        case 7: d1=1,d2=8,d3=6,d4=32,d5=32,d6=6;break;
        case 8: d1=1,d2=4,d3=6,d4=1,d5=3,d6=6;break;
        case 9: d1=1,d2=4,d3=6,d4=7,d5=3,d6=6;break;
    }
      lcd.setCursor(e1,0);lcd.write((uint8_t)d1);lcd.setCursor(e2,0);lcd.write((uint8_t)d2);lcd.setCursor(e3,0);lcd.write((uint8_t)d3);
      lcd.setCursor(e1,1);lcd.write((uint8_t)d4);lcd.setCursor(e2,1);lcd.write((uint8_t)d5);lcd.setCursor(e3,1);lcd.write((uint8_t)d6);
 }}}
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 /// BALANCE ////////////////////////////
   if(menu==1){
  if (newPosition != oldPosition){oldPosition = newPosition;www=0;
     ball=ball-newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w1=1;
      if(ball<-10){ball=-10;}if(ball>10){ball=10;}
    WM8740Write(0b000100000000 + vol + ball);//reg0
    WM8740Write(0b001100000000 + vol - ball);//reg1
     Serial.print("BALANCE ");Serial.println(ball);
  }
  if(www==1||w==1){www=0;w=0;
      if(ball<0){lcd.setCursor(8,1);lcd.write((uint8_t)0);
                 lcd.setCursor(0,1);lcd.print("L > R");}                
      if(ball>0){lcd.setCursor(8,1);lcd.print(" ");
                 lcd.setCursor(0,1);lcd.print("L < R");}
     if(ball==0){lcd.setCursor(8,1);lcd.print(" ");
                 lcd.setCursor(0,1);lcd.print("L = R");}
      lcd.setCursor(0,0);lcd.print("BALANCE ");

      a[0]=abs(ball)/10;a[1]=abs(ball)%10;
      for(i=0;i<2;i++){
      switch(i){
        case 0: e1=9,e2=10,e3=11;break;
        case 1: e1=12,e2=13,e3=14;break;
        }
      switch(a[i]){
        case 0: d1=1,d2=8,d3=6,d4=1,d5=3,d6=6;break;
        case 1: d1=32,d2=2,d3=6,d4=32,d5=32,d6=6;break;
        case 2: d1=2,d2=8,d3=6,d4=1,d5=4,d6=5;break;
        case 3: d1=2,d2=4,d3=6,d4=7,d5=3,d6=6;break;
        case 4: d1=1,d2=3,d3=6,d4=32,d5=32,d6=6;break;
        case 5: d1=1,d2=4,d3=5,d4=7,d5=3,d6=6;break;
        case 6: d1=1,d2=4,d3=5,d4=1,d5=3,d6=6;break;
        case 7: d1=1,d2=8,d3=6,d4=32,d5=32,d6=6;break;
        case 8: d1=1,d2=4,d3=6,d4=1,d5=3,d6=6;break;
        case 9: d1=1,d2=4,d3=6,d4=7,d5=3,d6=6;break;
    }
      lcd.setCursor(e1,0);lcd.write((uint8_t)d1);lcd.setCursor(e2,0);lcd.write((uint8_t)d2);lcd.setCursor(e3,0);lcd.write((uint8_t)d3);
      lcd.setCursor(e1,1);lcd.write((uint8_t)d4);lcd.setCursor(e2,1);lcd.write((uint8_t)d5);lcd.setCursor(e3,1);lcd.write((uint8_t)d6);
 }}}
 //////////////////////////////////////////////////////////////////////////////////////////////////////

 //////// INPUT ////////////////////////////////////  
  if(menu==2){
    if (newPosition != oldPosition){oldPosition = newPosition;
     in=in-newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w1=1;
      if(in<0){in=0;}if(in>3){in=3;}
      WM8805Write(0x08, 0b01110000 + in);
  }
  delay(10);
  if(www==1||w==1){www=0;w=0;
  lcd.setCursor(0,0);lcd.print("INPUT SELECTOR");  
  lcd.setCursor(0,1);lcd.print("COAXIAL "); lcd.print(in);lcd.print(" ");
  }}
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 /// NO SOUND /////////////////////
  if(millis()-times1>500){times1=millis();err = WM8805Read(0x0B);
  Serial.print("0x0b ");Serial.println(WM8805Read(0x0b),BIN);
  Serial.print("0x0c ");Serial.println(WM8805Read(0x0c),BIN);
  Serial.print("0x0d ");Serial.println(WM8805Read(0x0d),BIN);
  Serial.print("0x0e ");Serial.println(WM8805Read(0x0e),BIN);
  Serial.print("0x0f ");Serial.println(WM8805Read(0x0f),BIN);
  Serial.print("0x10 ");Serial.println(WM8805Read(0x10),BIN);
  Serial.print("0x11 ");Serial.println(WM8805Read(0x11),BIN);
  Serial.println();}
  if(err!=err_old){err_old = err;www=1;} 

 /// EEPROM write /////////////////
  if(millis()-times>10000 && w1==1){w1=0;EEPROM.update(0,vol);EEPROM.update(1,in);EEPROM.update(9,ball+10);
  www=1;if(menu!=0){lcd.clear();}menu=0;}  
 
  }// loop  

void WM8740Write(int data){       
  digitalWrite(CLK,HIGH);digitalWrite(CS,HIGH);delay(1);
     for(int i = 15; i >= 0; i--){
        digitalWrite(CLK,LOW);
        digitalWrite(DATA, (data >> i) & 0x01);delay(1);
        digitalWrite(CLK,HIGH);delay(1);}
  digitalWrite(CS,LOW);delay(1);digitalWrite(CS,HIGH);
  }

void WM8805Write(byte reg, byte dout){  // WRITE_REG 
  digitalWrite(SCLK,LOW);digitalWrite(CSB,LOW);
     for(int i = 7; i >= 0; i--){
        digitalWrite(SCLK,LOW);
        digitalWrite(SDIN, (reg >> i) & 0x01);
        digitalWrite(SCLK,HIGH);
        }
     for(int i = 7; i >= 0; i--){
        digitalWrite(SCLK,LOW); 
        digitalWrite(SDIN, (dout >> i) & 0x01);
        digitalWrite(SCLK,HIGH);
        }
        digitalWrite(SCLK,LOW);digitalWrite(CSB,HIGH);  
  }  

byte WM8805Read(byte reg){   // READ_REG  
  byte dat[8],data = 0;
  reg = reg + (1 << 7);
   digitalWrite(SCLK,LOW);digitalWrite(CSB,LOW);
     for(int i = 7; i >= 0; i--){
        digitalWrite(SCLK,LOW);
        digitalWrite(SDIN, (reg >> i) & 0x01);
        digitalWrite(SCLK,HIGH);
        }
     for(int i = 7; i >= 0; i--){
        digitalWrite(SCLK,LOW);
        dat[i] = digitalRead(SDOUT);
        data = data + (dat[i] << i);
        digitalWrite(SCLK,HIGH);
        } 
        digitalWrite(SCLK,LOW);digitalWrite(CSB,HIGH);
    return data;
  }    

void to_Timer(){newPosition = myEnc.read()/4;}