ЦАП — цифро-аналоговый преобразователь — это устройство, которое преобразует информацию из цифрового вида в аналоговые сигналы, при этом максимально точно и без искажений.
Собрать внешний ЦАП на компонентах предложных в статье не сложно, он содержит несколько недорогих компонентов и в настройке практически не нуждается.
Входной цифровой сигнал имеет формат S/PDIF (цифровой аудио интерфейс разработанный фирмами SONY/PHILIPS, предназначен для передачи цифрового сигнала между аудио устройствами), ЦАП PCM1753 не поддерживает такой формат, для преобразования S/PDIF необходим ресивер на WM8805 который преобразует S/PDIF в цифровой сигнал в формат I2S. С выхода ЦАП звуковой сигнал поступает на фильтр-сумматор собранный на ОУ NE5532, а с выхода фильтра звуковой сигнал можно подавать на наушники с минимальным сопротивлением 32 Ом .
Внешний звуковой ЦАП содержит несколько основных компонента:
- Плата Arduino Nano
- Ресивер на WM8805 (24 бит 196 кГц)
- ЦАП на PCM (24 бит 196 кГц)
- Фильтр-сумматор на NE5532
- LCD1602
- Энкодер KY-040
Характеристики основных компонентов внешнего ЦАПа:
- WM8805
- Входной формат — S/PDIF
- Кол-во входов … 8 (программно ограничено до 4-х)
- Выходной формат:
- 16-bit, MSB-first, right-justified
- 24-bit, MSB-first, right-justified
- 24-bit, MSB-first, left-justified
- 24-bit, MSB-first, I2S
- Напряжение питания
- Digital power supply … 3,3 В
- Digital power supply … 3,3 В
- Диапазон частот дискретизации входного сигнала 32 — 196 кГц
Управление ресивером WM8805 программное, ресивер настроен на выходной сигнал формата 24 bit / I2S / 196 kHz.
- PCM1753
- Входные форматы:
- I2S, left-justified / 16-, 18-, 20-, 24-bit
- De-emphasis filter
- 38 кГц
- 44,1 кГц
- 48 кГц
- Digital Filter Rolloff
- Sharp rolloff
- Slow rolloff
- Напряжение питания … 5 В
- Коэффициент гармоник от 0.002% до 0,004% на уровне 0 дБ
- Динамический диапазон 102 …106 дБ (192 … 44,1 кГц)
- Отношение сигнал/шум 102 …106 дБ (192 … 44,1 кГц)
- Частота дискретизации до 192 кГц
- Работает совместно с фильтром-сумматоров на NE5532
- Входные форматы:
Управление ЦАП PCM1753 программное, настроен на входной сигнал формата 24 bit / I2S / 196 kHz.
Схема стабилизаторов питания
Рекомендуется как можно ближе к микросхемам по цепи питания устанавливаются фильтрующие конденсаторы 0,1 и 22 мкФ.
Подключение к плате Arduino
Во внешнем ЦАПе использован энкодер KY-040 для управления громкостью, коммутатором входов, фильтрами De-emphasis и Digital Filter Rolloff, дополнительно используется кнопка для активации режима MUTE. Информация о режимах работы внешнего ЦАП выводится на LCD дисплея LCD1602 на базе контроллера HD44780 совместно с модулем I2C. I2C модуль на базе микросхемы PCF8574 позволяют подключить символьный дисплей 1602 к плате Arduino всего по двум проводам SDA и SCL (А4 и А5), что дает возможность не использовать цифровые выходы Arduino при подключении дисплея.
Меню внешнего ЦАПа состоит из 4-х пунктов:
- Регулятор громкости от -78 до 0 дБ
- Коммутатор входов SPDIF
- De-emphasis filter — 38 кГц | 44,1 кГц | 48 кГц
- Digital Filter Rolloff Control
На главное меню помимо громкости выводится выводится дополнительная информация:
- Номер входа SPDIF
- De-emphasis filter — 38 кГц | 44,1 кГц | 48 кГц | 192 кГц (фильтр отключен)
- Digital Filter Rolloff Control, режимы Sharp rolloff и Slow rolloff
- Уровень громкости от 0 до 99 значений (шаг 0,5 дБ)
- Индикатор отображает режимы VOLUME, MUTE, NO SOUND — если на входе SPDIF нет сигнала или кабель не подключен
#define ML 2 #define MC 3 #define MD 4 #define CLK A0 // CLK ENCODER #define DT A1 // DT ENCODER #define SW A2 // SW ENCODER #define CSB 11 // CSB WM8805 #define SCLK 8 // SCLK WM8805 #define SDIN 9 // SDIN WM8805 #define SDOUT 10 // SDOUT WM8805 #define MUTE 5 // LCD1602 I2C A4 = SDA, A5 = SCL #include <Wire.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 #include <LiquidCrystal_I2C.h> //Библиотека - http://forum.rcl-radio.ru/misc.php?action=pan_download&item=45&download=1 LiquidCrystal_I2C lcd(0x27,16,2); // Устанавливаем дисплей Encoder myEnc(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,oldPosition = -999,newPosition,times1; byte i,d1,d2,d3,d4,d5,d6,e1,e2,e3; int vol,w,w1,w2=1,menu,mute,dem,a[3],dem_on,roll,in,err; void setup(){ pinMode(ML,OUTPUT); pinMode(MC,OUTPUT); pinMode(MD,OUTPUT); pinMode(SW,INPUT); pinMode(MUTE,INPUT_PULLUP); pinMode(CSB,OUTPUT); // CSB WM8805 pinMode(SCLK,OUTPUT); // SCLK WM8805 pinMode(SDIN,OUTPUT); // SDIN WM8805 pinMode(SDOUT,INPUT); // SDOUT WM8805 Wire.begin();Serial.begin(9600); lcd.init();lcd.backlight(); MsTimer2::set(1, to_Timer);MsTimer2::start(); 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); delay(100); 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);in = EEPROM.read(3); if(dem<3){dem_on=1;}else{dem_on=0;} // 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, 0b01110001);// 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, 0b01001010);// 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, 0b11000000);// SPD_192K_EN WL_MASK SPDGPO WITHFLAG CONT READMUX[2:0] WM8805Write(0x1E, 0b00000100);// 00 TRIOP AIFPD OSCPD SPDIFTXPD SPDIFRXPD PLLPD delay(1000); audio(); } void loop(){ /// MENU ////////////////////////////// if(digitalRead(SW)==LOW){menu++;if(menu>3){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;vol_func(); Serial.println(vol); audio();} lcd.setCursor(0,0); if(mute==1){lcd.print("MUTE ");} if(err==0&&mute==0){lcd.print("VOLUME ");lcd.print("C");lcd.print(in);} if(err>0&& mute==0){lcd.print("NO SOUND ");} lcd.setCursor(0,1); switch(dem){ case 0: lcd.print("44.1k");break; case 1: lcd.print("48.0k");break; case 2: lcd.print("32.0k");break; case 3: lcd.print("192 k");break; } switch(roll){ case 0: lcd.print(" SH ");break; case 1: lcd.print(" SL ");break; } if(w2==1){w2=0; a[0]=(vol-156)/10;a[1]=(vol-156)%10; for(i=0;i<2;i++){ switch(i){ case 0: e1=10,e2=11,e3=12;break; case 1: e1=13,e2=14,e3=15;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==1){ 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);} lcd.setCursor(0,0);lcd.print("INPUT SELECTOR"); lcd.setCursor(0,1);lcd.print("COAXIAL "); lcd.print(in);lcd.print(" "); } /// DE-EMPHASIS ////////////////////////////////// if(menu==2){ 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;} if(dem<3){dem_on=1;}else{dem_on=0;} audio();} if(w2==1){w2=0; lcd.setCursor(0,0);lcd.print("DE-EMPHASIS FILT"); lcd.setCursor(0,1); switch(dem){ case 0: lcd.print(" 44.1 kHz");break; case 1: lcd.print(" 48.0 kHz");break; case 2: lcd.print(" 32.0 kHz");break; case 3: lcd.print(" 192 kHz");break; }}} /// Roll-off Filter ////////////////////////////////// if(menu==3){ 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(1,1); switch(roll){ case 0: lcd.print("Sharp");break; case 1: lcd.print("Slow ");break; }}} /// NO SOUND ///////////////////// if(millis()-times1>500){times1=millis();err = WM8805Read(0x0B);} //////// EEPROM ////////////////////////////////////////////////// if(millis()-times>10000 && w==1 && mute == 0){EEPROM.update(0,vol);EEPROM.update(1,dem);EEPROM.update(2,roll);EEPROM.update(3,in);w=0;w2=1;menu=0;lcd.clear();} }// loop void WritePCM(byte reg, byte data){ // WRITE_REG SPI digitalWrite(MC,HIGH);digitalWrite(ML,LOW); for(int i = 7; i >= 0; i--){ digitalWrite(MC,LOW); digitalWrite(MD, (reg >> i) & 0x01); digitalWrite(MC,HIGH); } for(int i = 7; i >= 0; i--){ digitalWrite(MC,LOW); digitalWrite(MD, (data >> i) & 0x01); digitalWrite(MC,HIGH); } digitalWrite(MC,HIGH);digitalWrite(ML,HIGH);delay(1); } 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 audio(){ WritePCM(0x10, vol);//r16 [7:0]att 0-min 255-max WritePCM(0x11, vol);//r17 [7:0]att 0-min 255-max WritePCM(0x12, 0b01000000 + (mute << 1) + mute);//r18 [6]x128 [1:0]mute WritePCM(0x13, 0b00000000 + (dem_on << 4) + (dem << 5));//r19 [1:0]dac_on [4]De-Emphasis [6:5] De-Emphasis Sample Rate Selection WritePCM(0x14, 0b00000100 + (roll << 5));//r20 [2:0]100=I2S_24 [5]Filter Rolloff WritePCM(0x16, 0B00000001);//r22 } void to_Timer(){newPosition = myEnc.read()/4;} void vol_func(){if(vol<156){vol=156;}if(vol>255){vol=255;}}
how to i conver spdif to 5.1 dolby dts?
PMC
How to i convert spdif to dolby dts?
Tried the sketch and worked fine. Now waiting for some components to arrive to start this! Thanks
Is there anyway to add a balance control and a format selection? Thanks
The project is finished, no changes are expected.