- 积分
- 574
- 在线时间
- 414 小时
- 最后登录
- 2025-5-17
- 阅读权限
- 50
- 精华
- 0
 
- UID
- 34308
- 帖子
- 568
- 精华
- 0
- 经验
- 574 点
- 金钱
- 558 ¥
- 注册时间
- 2008-1-19
|
我也想找
/****************************************************
* Code for headphone DAC
* 2005, gmarsh
*
* when programming, be sure to set chip flags
* for a 4MHz internal RC oscillator.
*
* PIN CONNECTIONS:
*
* PC0/ADC0 = volume control
* PC2 = PCM1792 reset
* PC3 = SRC419x/AD189x reset
* PC4/PC5 = TWI interface
* PD5 = CS8416 reset
*
****************************************************/
// core frequency
#define F_CPU 4000000
// includes
#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <compat/twi.h>
#include <avr/delay.h>
// defines
#define CS8416_ADDR 0x20
#define PCM1792_ADDR 0x98
#define LOCKTIMEOUT 1202 // 250ms input timeout
// global variables
unsigned char ATTEN; // PCM1792 attenuation value
unsigned char last_atten; // last attenuation value
unsigned long adc_average; // filtered volume knob position
unsigned long adc_upper_limit; // upper hysteresis point
unsigned long adc_lower_limit; // lower hysteresis point
unsigned long input_timeout; // input-switch timeout
enum {COAX_LOCKED, COAX_UNLOCKED, TOSLINK_LOCKED, TOSLINK_UNLOCKED} lockstate;
// function prototypes
void send_1792(unsigned char address, unsigned char data);
void send_8416(unsigned char address, unsigned char data);
// code begins
int main(void) {
// init globals
ATTEN = 0;
last_atten = 0;
adc_average = 0;
adc_upper_limit = 0;
adc_lower_limit = 0;
lockstate = TOSLINK_UNLOCKED;
input_timeout = LOCKTIMEOUT;
// init I/O ports
PORTB = 0xFF;
DDRB = 0x80; // B7=test output
PORTC = 0x72;
DDRC = 0x0C;
PORTD = 0xDB; // PD2 should not have a pullup, or else 8416 gets angry
DDRD = 0x20;
// init ADC
ADMUX = 0; // select ADC0, external AREF
ADCSRA = 0xAE; // ADC enabled, free running mode, interrupt enabled, prescaler=64 (62.5KHz conv rate)
// init TWI
TWSR = 0x00; // TWPS=0 (prescaler=1)
//TWBR = 0x20; // 50KHz SPI baud rate
TWBR = 0x48; // 25KHz baud rate
TWCR = (1<<TWEN); // enable TWI
// reset devices
_delay_ms(5);
PORTC = 0x7B; // enable SRC first
_delay_ms(5);
PORTC = 0x7F; // enable DAC second
_delay_ms(5);
PORTD = 0xFB; // enable CS8416 third
_delay_ms(5);
// init PCM1792
send_1792(0x10,ATTEN);
send_1792(0x11,ATTEN);
send_1792(0x12,0xB1); // attenuation load enable, LJ, no de-emph, muted for now
send_1792(0x13,0x00); // sharp DF rolloff
// init CS8416
send_8416(0x00,0x08); // more wideband jitter, less inband
send_8416(0x01,0x04); // INT active high, zero SDOUT on Rx error, RMCK=128Fs
send_8416(0x02,0x40); // automatic de-emphasis enabled
//send_8416(0x03,0x02); // GPO2 = INT output
send_8416(0x03,0x05); // GPO2 = RERR output
send_8416(0x04,0x18); // RUN=0, optical selected
send_8416(0x05,0x80); // LJ master mode; SOJUST=0, SODEL=0, SOSPOL=0, SOLRPOL=0
send_8416(0x06,0x10); // UNLOCK unmasked in RERR register
send_8416(0x07,0x04); // RERR register unmasked for interrupt
send_8416(0x08,0x7F); // all interrupts level-active
send_8416(0x09,0x00); // all interrupts level-active
send_8416(0x04,0x98); // RUN=1 / optical
// unmute PCM1792
send_1792(0x12,0xB0);
// enable SLEEP instruction
MCUCR = 0x80;
// enable interrupts
sei();
// start ADC conversion
ADCSRA = 0xEE;
// main loop
while(1) {
// update PCM1792 attenuation if volume pot moved
if (last_atten != ATTEN) {
last_atten = ATTEN;
send_1792(0x10,last_atten);
send_1792(0x11,last_atten);
}
// handle input detection
switch(lockstate) {
case COAX_LOCKED:
if (PIND & 0x04) {
input_timeout = LOCKTIMEOUT;
lockstate = COAX_UNLOCKED;
}
break;
case TOSLINK_LOCKED:
if (PIND & 0x04) {
input_timeout = LOCKTIMEOUT;
lockstate = TOSLINK_UNLOCKED;
}
break;
case COAX_UNLOCKED:
if (--input_timeout == 0) {
send_8416(0x04,0x98); // switch to toslink input
input_timeout = LOCKTIMEOUT;
lockstate = TOSLINK_UNLOCKED;
}
if ((PIND & 0x04) == 0) {
lockstate = COAX_LOCKED;
}
break;
case TOSLINK_UNLOCKED:
if (--input_timeout == 0) {
send_8416(0x04,0x90); // switch to coax input
input_timeout = LOCKTIMEOUT;
lockstate = COAX_UNLOCKED;
}
if ((PIND & 0x04) == 0) {
lockstate = TOSLINK_LOCKED;
}
break;
}
asm("sleep;"); // enter sleep mode, wait for next ADC interrupt
}
}
// ADC (volume pot) handler
INTERRUPT(SIG_ADC) {
signed long error;
error = (signed long) (ADCW - (adc_average >> 6));
adc_average += error;
if ( (adc_average > adc_upper_limit) || (adc_average < adc_lower_limit) ) {
ATTEN = ((adc_average & 0xFF00) >> 8);
if ((adc_average & 0xFF00) == 0xFF00) {
adc_upper_limit = 0xFFFF;
} else {
adc_upper_limit = (adc_average & 0xFF00) + 0x180;
}
if ((adc_average & 0xFF00) == 0x0000) {
adc_lower_limit = 0x0000;
} else {
adc_lower_limit = (adc_average & 0xFF00) - 0x80;
}
}
}
// TWI routines
void send_8416(unsigned char address, unsigned char data) {
// send start
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while(!(TWCR & (1<<TWINT)));
// send slave address
TWDR = CS8416_ADDR;
TWCR = (1<<TWINT)|(1<<TWEN);
while(!(TWCR & (1<<TWINT)));
// send register address
TWDR = address;
TWCR = (1<<TWINT)|(1<<TWEN);
while(!(TWCR & (1<<TWINT)));
// send data
TWDR = data;
TWCR = (1<<TWINT)|(1<<TWEN);
while(!(TWCR & (1<<TWINT)));
// send stop condition
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
}
void send_1792(unsigned char address, unsigned char data) {
// send start
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while(!(TWCR & (1<<TWINT)));
// send slave address
TWDR = PCM1792_ADDR;
TWCR = (1<<TWINT)|(1<<TWEN);
while(!(TWCR & (1<<TWINT)));
// send register address
TWDR = address;
TWCR = (1<<TWINT)|(1<<TWEN);
while(!(TWCR & (1<<TWINT)));
// send data
TWDR = data;
TWCR = (1<<TWINT)|(1<<TWEN);
while(!(TWCR & (1<<TWINT)));
// send stop condition
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
} |
|