Yes! You don't need switches, you can just take the signals out before the glue logic and leave it unpopulated.
I am just about to make a Mouser order and thought while I was at it I would get the parts for the schematic in post #122. What is the part number for 74LVC74 on the schematics, I assume it is an eight pin part, as a mouser search for 74LVC74 only shows 14 pin parts with VCC as pin 14.
BTW: check post #1 for the latest schematic. Earlier versions could do without the programming mode of the PMD100, but the latest sounds best and uses customizable dithering settings for the PMD100.
Correct: it's only needed in case you omit the glue logic and connect the output of the PMD100 to a "normal" DAC and still want WCKO to be reclocked. But for the TDA1541 it's not needed.
I tried 4x oversampling and found out that there is no different timing: all frequencies stay same from the PMD100, output happens only half as often compared to 8x, so we can simplify the circuit and simulation and use DG of PMD100 to generate LE for the TDA1541A as it's reclocked in any case. The updated code:
Updated schematics attached:
Java:
// for ATtiny84
// pin mapping clockwise
// set clock to 4MHz internal
// works with DIR9001 -> PMD100 -> TDA1541A digital interface board
// change these settings to configure the PMD100:
byte oversampling_rate = 3; // 1 = 2x oversampling, 2 = 4x oversampling, 3 = 8x oversampling
byte dither_mode = 2; // 0~7 = dither mode 0 to 7
byte input_data_justification = 0; // 0 = left justified, 1 = right justified (16bit)
byte input_bit_clock_polarity = 0; // 0 = rising edge, 1 = falling edge
byte input_frame_sync_polarity = 0; // 0 = LRCI high means left channel, 1 = LRCI low means left channel
byte output_word_length = 0; // 0 = 16bit, 1 = 18bit, 2 = 20bit, 3 = 24bit
byte output_format = 1; // 0 = 2s compliment, 1 = COB
byte output_word_clock_polarity = 1; // 0 = high to low at the end of the output word, 1 = low to high at the end of the output word
byte deglitch_low = 31; // set falling edge of DG to 0~31st interval
byte deglitch_high = 25; // set rising edge of DG to 0~31st interval
// end of settings
#include <avr/sleep.h>
#include <debouncetm.h>
#define MUTE 0 // MUTE (HIGH = muted)
#define MS1 2
#define MS2 3
#define MS3 4
#define MDT 5
#define MEN 6
#define LED 7 // LED (active HIGH)
#define TOSL 10 // TOSLINK (active LOW with 74LVC125, active HIGH with 74LVC126)
#define COAX 9 // COAX (active LOW)
#define BTN 8 // button pin (HIGH = TOSLINK)
#define samplerate 0.75 // poll interval for update() in msec (a safe starting point would be samplerate = 0.1 * bounce-duration in msec)
#define longpress 0.90 // longpress duration in sec
#define doubleclick 0.50 // doubleclick window in sec
#define history 8 // internal history length: 8, 16 or 32 bit
Button button(BTN, INPUT, HIGH, samplerate, longpress, doubleclick, history); // specify pin, pinMode, polarity, samplerate, longpress duration, doubleclick window
elapsedMillis sleep_timer;
unsigned int sleep_interval = 500; // mute ramp down takes 260ms, so 300 is a good value here
void setup() {
delay(1000);
pinMode(COAX, OUTPUT);
pinMode(TOSL, OUTPUT);
pinMode(MUTE, OUTPUT);
pinMode(LED, OUTPUT);
pinMode(MS1, OUTPUT);
pinMode(MS2, OUTPUT);
pinMode(MS3, OUTPUT);
pinMode(MDT, OUTPUT);
pinMode(MEN, OUTPUT);
digitalWrite(LED, LOW);
digitalWrite(MS1, LOW);
digitalWrite(MS2, LOW);
digitalWrite(MS3, LOW);
digitalWrite(MDT, LOW);
digitalWrite(MEN, HIGH);
delay(100);
digitalWrite(MUTE, HIGH);
digitalWrite(COAX, HIGH);
digitalWrite(TOSL, LOW);
delay(100);
configurePMD100();
delay(100);
zeroAttenuationPMD100();
delay(3000);
if (!digitalRead(BTN)) {
digitalWrite(COAX, LOW);
delay(50);
digitalWrite(LED, HIGH);
delay(300);
digitalWrite(MUTE, LOW);
delay(300);
}
sleep_timer = 0;
}
void loop() {
button.update();
if (button.pressed()) {select_TOSL();}
if (button.released()) {select_coax();}
if (sleep_timer > sleep_interval) {gotoSleep();}
}
void zeroAttenuationPMD100() {
digitalWrite(MS1, HIGH);
digitalWrite(MS2, HIGH);
delayMicroseconds(1);
digitalWrite(MEN, LOW);
delayMicroseconds(1);
digitalWrite(MEN, HIGH);
delayMicroseconds(1);
digitalWrite(MS1, LOW);
digitalWrite(MS2, LOW);
}
uint32_t value = 0;
void configurePMD100() {
value = 0;
value |= uint32_t(dither_mode) << 19;
value |= uint32_t(output_word_length) << 17;
value |= uint32_t(input_frame_sync_polarity) << 16;
value |= uint32_t(deglitch_high) << 11;
value |= uint32_t(deglitch_low) << 6;
value |= uint32_t(output_format) << 5;
value |= uint32_t(output_word_clock_polarity) << 4;
value |= uint32_t(input_data_justification) << 3;
value |= uint32_t(input_bit_clock_polarity) << 2;
value |= uint32_t(oversampling_rate);
for (int i = 0; i < 24; i++) {
digitalWrite(MEN, LOW);
digitalWrite(MDT, bitRead(value, i));
delayMicroseconds(1);
digitalWrite(MEN, HIGH);
delayMicroseconds(1);
}
digitalWrite(MDT, LOW);
delayMicroseconds(4);
digitalWrite(MS2, HIGH);
digitalWrite(MS3, HIGH);
delayMicroseconds(1);
digitalWrite(MEN, LOW);
delayMicroseconds(1);
digitalWrite(MEN, HIGH);
delayMicroseconds(2);
digitalWrite(MS2, LOW);
digitalWrite(MS3, LOW);
}
void select_TOSL() {
digitalWrite(MUTE, HIGH);
delay(300);
digitalWrite(LED, LOW);
delay(200);
digitalWrite(COAX, HIGH);
delay(50);
digitalWrite(TOSL, HIGH);
delay(50);
digitalWrite(LED, HIGH);
delay(300);
digitalWrite(MUTE, LOW);
delay(300);
sleep_timer = 0;
}
void select_coax() {
digitalWrite(MUTE, HIGH);
delay(300);
digitalWrite(LED, LOW);
delay(200);
digitalWrite(TOSL, LOW);
delay(50);
digitalWrite(COAX, LOW);
delay(50);
digitalWrite(LED, HIGH);
delay(300);
digitalWrite(MUTE, LOW);
delay(300);
sleep_timer = 0;
}
void gotoSleep() {
GIMSK |= _BV(PCIE0);
GIMSK |= _BV(PCIE1);
PCMSK1 |= _BV(PCINT10); // use PB2 as interrupt pin
// PCMSK0 |= _BV(PCINT4); // use PA4 as interrupt pin
ADCSRA &= ~_BV(ADEN); // ADC off
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // replaces above statement
sleep_enable(); // sets the sleep enable bit in the MCUCR register (SE BIT)
sleep_cpu(); // sleep
sleep_disable(); // clear SE bit
PCMSK1 &= ~_BV(PCINT10); // turn off PB2 as interrupt pin
// PCMSK0 &= ~_BV(PCINT4); // turn off PA4 as interrupt pin
ADCSRA |= _BV(ADEN); // ADC on
sleep_timer = 0;
}
// ISR(PCINT0_vect) {sleep_timer = 0;}
ISR(PCINT1_vect) {sleep_timer = 0;}
Updated schematics attached:
Attachments
I played around with dither settings and found out that best is to disable dither, so here updated schematics and code:
Java:
// for ATtiny84
// pin mapping clockwise
// set clock to 4MHz internal
// works with DIR9001 -> PMD100 -> TDA1541A digital interface board for Arcam Delta Black Box v1
// change these settings to configure the PMD100:
byte oversampling_rate = 3; // 1 = 2x oversampling, 2 = 4x oversampling, 3 = 8x oversampling
byte dither_mode = 3; // 0~7 = dither mode 0 to 7
byte input_data_justification = 0; // 0 = left justified, 1 = right justified (16bit)
byte input_bit_clock_polarity = 0; // 0 = rising edge, 1 = falling edge
byte input_frame_sync_polarity = 0; // 0 = LRCI high means left channel, 1 = LRCI low means left channel
byte output_word_length = 0; // 0 = 16bit, 1 = 18bit, 2 = 20bit, 3 = 24bit
byte output_format = 1; // 0 = 2s compliment, 1 = COB
byte output_word_clock_polarity = 1; // 0 = high to low at the end of the output word, 1 = low to high at the end of the output word
byte deglitch_low = 31; // set falling edge of DG to 0~31st interval
byte deglitch_high = 25; // set rising edge of DG to 0~31st interval
// end of settings
#include <avr/sleep.h>
#include <debouncetm.h>
#define MUTE 0 // MUTE (HIGH = muted)
#define DITH 1 // DITHER (HIGH = on)
#define MS1 2
#define MS2 3
#define MS3 4
#define MDT 5
#define MEN 6
#define LED 7 // LED (active HIGH)
#define TOSL 10 // TOSLINK (active LOW with 74LVC125, active HIGH with 74LVC126)
#define COAX 9 // COAX (active LOW)
#define BTN 8 // button pin (HIGH = TOSLINK)
#define samplerate 0.75 // poll interval for update() in msec (a safe starting point would be samplerate = 0.1 * bounce-duration in msec)
#define longpress 0.90 // longpress duration in sec
#define doubleclick 0.50 // doubleclick window in sec
#define history 8 // internal history length: 8, 16 or 32 bit
Button button(BTN, INPUT, HIGH, samplerate, longpress, doubleclick, history); // specify pin, pinMode, polarity, samplerate, longpress duration, doubleclick window
elapsedMillis sleep_timer;
unsigned int sleep_interval = 500; // mute ramp down takes 260ms, so 300 is a good value here
void setup() {
delay(1000);
pinMode(COAX, OUTPUT);
pinMode(TOSL, OUTPUT);
pinMode(MUTE, OUTPUT);
pinMode(LED, OUTPUT);
pinMode(DITH, OUTPUT);
pinMode(MS1, OUTPUT);
pinMode(MS2, OUTPUT);
pinMode(MS3, OUTPUT);
pinMode(MDT, OUTPUT);
pinMode(MEN, OUTPUT);
digitalWrite(LED, LOW);
digitalWrite(MS1, LOW);
digitalWrite(MS2, LOW);
digitalWrite(MS3, LOW);
digitalWrite(MDT, LOW);
digitalWrite(MEN, HIGH);
delay(100);
digitalWrite(DITH, LOW);
digitalWrite(MUTE, HIGH);
digitalWrite(COAX, HIGH);
digitalWrite(TOSL, LOW);
delay(100);
configurePMD100();
delay(100);
zeroAttenuationPMD100();
delay(3000);
if (!digitalRead(BTN)) {
digitalWrite(COAX, LOW);
delay(50);
digitalWrite(LED, HIGH);
delay(300);
digitalWrite(MUTE, LOW);
delay(300);
}
sleep_timer = 0;
}
void loop() {
button.update();
if (button.pressed()) {select_TOSL();}
if (button.released()) {select_coax();}
if (sleep_timer > sleep_interval) {gotoSleep();}
}
void zeroAttenuationPMD100() {
digitalWrite(MS1, HIGH);
digitalWrite(MS2, HIGH);
delayMicroseconds(1);
digitalWrite(MEN, LOW);
delayMicroseconds(1);
digitalWrite(MEN, HIGH);
delayMicroseconds(1);
digitalWrite(MS1, LOW);
digitalWrite(MS2, LOW);
}
uint32_t value = 0;
void configurePMD100() {
value = 0;
value |= uint32_t(dither_mode) << 19;
value |= uint32_t(output_word_length) << 17;
value |= uint32_t(input_frame_sync_polarity) << 16;
value |= uint32_t(deglitch_high) << 11;
value |= uint32_t(deglitch_low) << 6;
value |= uint32_t(output_format) << 5;
value |= uint32_t(output_word_clock_polarity) << 4;
value |= uint32_t(input_data_justification) << 3;
value |= uint32_t(input_bit_clock_polarity) << 2;
value |= uint32_t(oversampling_rate);
for (int i = 0; i < 24; i++) {
digitalWrite(MEN, LOW);
digitalWrite(MDT, bitRead(value, i));
delayMicroseconds(1);
digitalWrite(MEN, HIGH);
delayMicroseconds(1);
}
digitalWrite(MDT, LOW);
delayMicroseconds(4);
digitalWrite(MS2, HIGH);
digitalWrite(MS3, HIGH);
delayMicroseconds(1);
digitalWrite(MEN, LOW);
delayMicroseconds(1);
digitalWrite(MEN, HIGH);
delayMicroseconds(2);
digitalWrite(MS2, LOW);
digitalWrite(MS3, LOW);
}
void select_TOSL() {
digitalWrite(MUTE, HIGH);
delay(300);
digitalWrite(LED, LOW);
delay(200);
digitalWrite(COAX, HIGH);
delay(50);
digitalWrite(TOSL, HIGH);
delay(50);
digitalWrite(LED, HIGH);
delay(300);
digitalWrite(MUTE, LOW);
delay(300);
sleep_timer = 0;
}
void select_coax() {
digitalWrite(MUTE, HIGH);
delay(300);
digitalWrite(LED, LOW);
delay(200);
digitalWrite(TOSL, LOW);
delay(50);
digitalWrite(COAX, LOW);
delay(50);
digitalWrite(LED, HIGH);
delay(300);
digitalWrite(MUTE, LOW);
delay(300);
sleep_timer = 0;
}
void gotoSleep() {
GIMSK |= _BV(PCIE0);
GIMSK |= _BV(PCIE1);
PCMSK1 |= _BV(PCINT10); // use PB2 as interrupt pin
// PCMSK0 |= _BV(PCINT4); // use PA4 as interrupt pin
ADCSRA &= ~_BV(ADEN); // ADC off
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // replaces above statement
sleep_enable(); // sets the sleep enable bit in the MCUCR register (SE BIT)
sleep_cpu(); // sleep
sleep_disable(); // clear SE bit
PCMSK1 &= ~_BV(PCINT10); // turn off PB2 as interrupt pin
// PCMSK0 &= ~_BV(PCINT4); // turn off PA4 as interrupt pin
ADCSRA |= _BV(ADEN); // ADC on
sleep_timer = 0;
}
// ISR(PCINT0_vect) {sleep_timer = 0;}
ISR(PCINT1_vect) {sleep_timer = 0;}
Attachments
Added CRC supplys to both transformers with Qspeed rectifiers:
Project finished.
Project finished.
Congratulations! And how about the sound improvement? More detailed and more clarity? BTW I think it's not a bad idea to improve the 1K I/V resistors for something more fancy than a regular metal film resistor (and also the 2 last 22 ohm resistors in the signal path).
At least, I mean:
I/V resistors: R24 and R124 (I've tried here with nice results, Vishay Z-Foil, or less expensive, non-magnetic Dale RN60D);
Last two resistors: R23 and R123 (I have here Riken or Allen Bradley 2W).
I/V resistors: R24 and R124 (I've tried here with nice results, Vishay Z-Foil, or less expensive, non-magnetic Dale RN60D);
Last two resistors: R23 and R123 (I have here Riken or Allen Bradley 2W).
Ok thanks! And what about these ones:
Do we also need to upgrade resistors in the DEEM section?
Do we also need to upgrade resistors in the DEEM section?
Last edited:
I've changed every stock resistor you've marked in red for PRP or Takman metal film - it's the signal path.
But, in my humble opinion, the most relevant ones are the I/V resistors and maybe the last ones.
Until now, I've done nothing at all in the DEEM section.
But, in my humble opinion, the most relevant ones are the I/V resistors and maybe the last ones.
Until now, I've done nothing at all in the DEEM section.
I changed the IV resistors for RN60, a noticeably improvement. The analog transformer buzzed: I don't like that in a quiet room, so I changed it for a toroidal. The sound is again much better, didn't expect that to make such a difference!
i am from vietnam. sorry for my bad english. i admire your work on pmd100 and tda1541. but can help me with the schematic between df1706 and tda1543. thank you very much
- Home
- Source & Line
- Digital Line Level
- PMD100 to TDA1541 in smultaneous mode