DAC PCM1796 + WM8804 (Arduino)

Ранее на странице DAC PCM1796 + CS8416 (Arduino) рассматривался пример создания внешнего ЦАПа на базе PCM1796 с ресивером CS8416, на этой странице будет рассмотрен аналогичный пример, но с использованием ресивера на базе WM8804.

Входной цифровой сигнал для внешнего ЦАПа имеет формат S/PDIF (цифровой аудио интерфейс разработанный фирмами SONY/PHILIPS, предназначен для передачи цифрового сигнала между аудио устройствами), ресивер на WM8804 преобразует его в формат I2S 24 бит с частотой дискретизации 192 кГц. Цифровой сигнала I2S поступает на ЦАП PCM1796, далее с выхода PCM1796 звуковой сигнал поступает на фильтр-сумматор собранный на ОУ NE5532.

Для нормальной работы ресивер и ЦАП должный иметь одинаковый формат передачи цифровых данных, в данном случае это I2S 24 бит с частотой дискретизации 192 кГц.

Параметры ресивера WM8804:

  • Напряжение питания:
    • +3.3 V DVDD
    • +3.3 V PVDD
  • Входной формат данных: S/PDIF
  • Выходной формат данных:
    • I2S (аппаратно настроен)
    • Left Justified
    • Right Justified
  • Разрядность 16/20/24 бит (аппаратно настроен на 24 бит)
  • Частота дискредитации 32 to 192 кГц (аппаратно настроен на 192 кГц)
  • MCLK rate of 512fs, 256fs, 128fs и 64fs

Параметры ЦАП на PCM1796

  • Напряжение питания
    • 5-V Analog
    • 3.3-V Digital
  • Входной формат данных:
    • Left-Justified
    • Right-Justified
    • I2S (программно настроен)
  • Частота дискредитации: 10 кГц to 200 кГц
  • System Clock: 128, 192, 256, 384, 512, or 768 fS With Autodetect
  • Коэффициент гармоник с учетом шума (THD+N): 0.0005%
  • Динамический диапазон 123 дБ
  • Отношение сигнал.шум 123 дБ
  • Разделение каналов 117 дБ
  • Диапазон регулировки громкости от -120 до 0 дБ (программно ограничен от -50 до 0 дБ)
  • Фильтры:
    • Digital De-Emphasis (OFF, 32,0 44,1 48,0 кГц ) (программно поддерживается)
    • Digital Filter Rolloff: Sharp or Slow (программно поддерживается)
  • Soft Mute (программно поддерживается)
  • Zero Flag for Each Output (программно поддерживается)
  • Управление: SPI

Внешний ЦАП состоит из нескольких компонентов:

  • Ресивер на WM8804
  • ЦАП на PCM1796
  • ФНЧ на NE5532
  • Источник питания
  • Плата Arduino Nano
  • Индикатор LCD1602 с модулем I2C
  • Энкодер KY-040
  • Кнопка — MUTE

Схема ресивера на WM8804

Схема ресивера содержит выход ERROR, который меняет свое логические состояние при отключении и подключении коаксиального кабеля ко входу внешнего ЦАПа. Состояние выхода ERROR выводится на LCD1602 в виде сообщения «No sound».

Схема ЦАП на PCM1796

Схема ФНЧ на NE5532

Блок управления на Arduino Nano

Регулировка громкости в диапазоне от -50 до 0 дБ осуществляется при помощи энкодера KY-040, нажатие кнопки энкодера переключает пункты меню, в первом меню находятся настройка уровня громкости, а так же выводятся данные о состоянии фильтров, второе меню отвечает за фильтр De-Emphasis, третье за фильтр Rolloff. Дополнительно в блоке управления используется кнопка для активации режима MUTE.

Схема стабилизаторов питания

Для питания внешнего ЦАПа рекомендуется использовать три независимых источника питания (для питания ресивера, ЦАП и ФНЧ), который состоит из одного трансформатора с тремя независимыми вторичными обмотками, одна из которых имеет отвод от середины для двух полярного источника питания. Каждый источник питания имеет свой диодный мост. При этом аналоговая и цифровая земля объединяются через дроссель. Дополнительно как можно ближе к микросхемам по цепи питания устанавливаются фильтрующие конденсаторы.

Упрощенная схема стабилизаторов

#define MS      6   //  PCM1796
#define MDI     5   //  PCM1796
#define MC      4   //  PCM1796  
#define RST     2   //  PCM1796
#define CLK     9   //  ENCODER 
#define DT      8   //  ENCODER 
#define SW     10   //  ENCODER 
#define MUTE    7   //  BUTTON MUTE
#define ERR    11   //  PIN 5 WM8804 
// LCD1602 - I2C | A4=SDA A5=SCL
 
#include <EEPROM.h>
#include <MsTimer2.h>                    // http://rcl-radio.ru/wp-content/uploads/2018/11/MsTimer2.zip
#include <Encoder.h>                     // http://rcl-radio.ru/wp-content/uploads/2019/05/Encoder.zip
#include <LiquidCrystal_I2C.h>           // http://forum.rcl-radio.ru/misc.php?action=pan_download&item=45&download=1 
 Encoder myEnc(CLK, DT);
 LiquidCrystal_I2C lcd(0x27,16,2);  // Устанавливаем дисплей 
 
    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;
    int menu,w,w2,vol,mute,a[3],dem,roll,err;
    byte i,d1,d2,d3,d4,d5,d6,e1,e2,e3;
 
void setup() {
  Serial.begin(9600);MsTimer2::set(1, to_Timer);MsTimer2::start();
  pinMode(RST,OUTPUT);
  pinMode(MDI,OUTPUT);
  pinMode(MC,OUTPUT);
  pinMode(MS,OUTPUT);
  pinMode(SW,INPUT);
  pinMode(ERR,INPUT);
  pinMode(MUTE,INPUT_PULLUP);
  digitalWrite(RST,LOW);digitalWrite(MC,LOW);digitalWrite(MS,HIGH);
  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);
  lcd.setCursor(5,0);lcd.print("CS 8416");
  lcd.setCursor(5,1);lcd.print("PCM1796");
  delay(1000);lcd.clear(); 
  if(EEPROM.read(100)!=0){for(int i=0;i<101;i++){EEPROM.update(i,0);}}// очистка памяти при первом включении 
  vol = EEPROM.read(0);dem = EEPROM.read(1);roll = EEPROM.read(2); 
  digitalWrite(RST,HIGH);                
  audio();
}
 
void loop() {
 if(digitalRead(ERR)==HIGH){err=1;}else{err=0;} 
 /// MENU //////////////////////////////
 if(digitalRead(SW)==LOW){menu++;if(menu>2){menu=0;};delay(200);lcd.clear();w=1;times=millis();w2=1;}
 /// MUTE ///////////////////
 if(digitalRead(MUTE)==LOW&&mute==0){mute=1;audio();delay(200);}
 if(digitalRead(MUTE)==LOW&&mute==1){mute=0;audio();delay(200);}  
 
 /// VOLUME ///////////////////////////////////////////////////
 if(menu==0){
   if (newPosition != oldPosition){oldPosition = newPosition;
     vol=vol+newPosition;myEnc.write(0);newPosition=0;w=1;times=millis();w2=1;
     if(vol>99){vol=99;}if(vol<0){vol=0;}
     audio();}
 
     lcd.setCursor(0,0);
       if(mute==1){lcd.print("MUTE    ");}
       if(mute==0&&err==1){lcd.print("No Sound");}
       if(mute==0&&err==0){lcd.print("VOLUME  ");}  
     lcd.setCursor(0,1);
      switch(roll){
        case 0: lcd.print("SH ");break;
        case 1: lcd.print("SL ");break;
  }
      switch(dem){
        case 0: lcd.print("OFF ");break;
        case 1: lcd.print("48.0");break;
        case 2: lcd.print("44.1");break;
        case 3: lcd.print("32.0");break;
  }
 
if(w2==1){w2=0;
     a[0]=vol/10;a[1]=vol%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);
 }} 
 }
 
 /// DE-EMPHASIS //////////////////////////////////
  if(menu==1){
     if (newPosition != oldPosition){oldPosition = newPosition;
     dem=dem+newPosition;myEnc.write(0);newPosition=0;w=1;times=millis();w2=1;
      if(dem<0){dem=3;}if(dem>3){dem=0;}
      audio();}
 
  if(w2==1){w2=0;
  lcd.setCursor(0,0);lcd.print("DE-EMPHASIS SEL");  
  lcd.setCursor(0,1);
  switch(dem){
    case 0: lcd.print("No De-emphasis");break;
    case 1: lcd.print("48.0 kHz      ");break;
    case 2: lcd.print("44.1 kHz      ");break;
    case 3: lcd.print("32.0 kHz      ");break;
  }}} 
 
 /// Roll-off Filter //////////////////////////////////
  if(menu==2){
     if (newPosition != oldPosition){oldPosition = newPosition;
     roll=roll+newPosition;myEnc.write(0);newPosition=0;w=1;times=millis();w2=1;
     if(roll<0){roll=1;}if(roll>1){roll=0;}
     audio();}
 
  if(w2==1){w2=0;
  lcd.setCursor(0,0);lcd.print("Roll-off Filter");  
  lcd.setCursor(0,1);
  switch(roll){
    case 0: lcd.print("Sharp");break;
    case 1: lcd.print("Slow ");break;
  }}}   
 
 //// EEPROM ///////////////////////////////////////
 if(millis()-times>5000 && w==1){w=0;EEPROM.update(0,vol);EEPROM.update(1,dem);EEPROM.update(2,roll);menu=0;lcd.clear();w2=1;}
 delay(100);
}
 
void to_Timer(){newPosition = myEnc.read()/4;}
void audio(){
  WritePCM1796(0b00010000, vol+156);                        // REG_16
  WritePCM1796(0b00010001, vol+156);                        // REG_17
  WritePCM1796(0b00010010, 0b11010010 + mute + (dem << 2)); // REG_18
  WritePCM1796(0b00010011, 0b00000000 + (roll << 1));       // REG_19
  WritePCM1796(0b00010100, 0b00000000);                     // REG_20
  WritePCM1796(0b00010101, 0b00000001);                     // REG_21
  }
void WritePCM1796(byte reg, byte mdi){  // WRITE_REG 
   digitalWrite(MC,LOW);digitalWrite(MS,LOW);
     for(int i = 7; i >= 0; i--){
        digitalWrite(MC,LOW);
        digitalWrite(MDI, (reg >> i) & 0x01);
        digitalWrite(MC,HIGH);
        }
     for(int i = 7; i >= 0; i--){
        digitalWrite(MC,LOW);
        digitalWrite(MDI, (mdi >> i) & 0x01);
        digitalWrite(MC,HIGH);
        }
    digitalWrite(MC,LOW);digitalWrite(MS,HIGH);delay(1);
  }     

Comments

  1. Добрый день! Я правильно понимаю, что если замкнуть 10,11,12 ноги PCM на землю, а 14 через резистор 1k на +3.3В, выкинуть ардуино, то мы получаем простой конвертер spdif в аудио? Это будет самая простая схема такого конвертера? Надо ли будет произвести еще какие-то изменения, кроме вышеописанных, чтобы схема работала на 192Khz?

Добавить комментарий

Войти с помощью: