// 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;}
// 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;}