Skip to content

Instantly share code, notes, and snippets.

@hidsh
Created November 20, 2011 17:49
Show Gist options
  • Save hidsh/1380569 to your computer and use it in GitHub Desktop.
Save hidsh/1380569 to your computer and use it in GitHub Desktop.
audio selector with digital volume(PGA2311) using ATmega88P
/*
* avr_vol.c
*
* Created: 2011/11/10 8:02:23
* Author: g
*
* desc. : audio selector with digital volume
* schem.:
* device: ATMEGA88P
* PGA2311PA
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include "mystd.h"
/*=========*/
/* define */
/*=========*/
/*=========*/
/* const */
/*=========*/
/*=========*/
/* globals */
/*=========*/
u4 gtime;
u1 select_sw;
u1 mute_sw;
u2 vol_ad;
/*===========*/
/* utilities */
/*===========*/
/*===============*/
/* sub functions */
/*===============*/
static inline void dbg(u1 num, bool state)
{
u1 mask, now;
/* debug out: PC3..5, PC7 */
switch(num) {
case 3:
case 4:
case 5:
case 7:
mask = (0x01 << num);
now = (PORTC & mask)? ON : OFF;
if(state == now) return;
if(state == ON) PORTC |= mask;
else PORTC &= ~mask;
default: return;
}
}
static inline void led_out(bool state)
{
const u1 mask = 0x01; /* 0000_0001 */
u1 now;
now = (PORTB & mask)? ON : OFF;
if(state == now) return;
if(state == ON) PORTB |= mask;
else PORTB &= ~mask;
}
static inline void mute_out(bool state)
{
const u1 mask = 0x02; /* 0000_0010 */
u1 now;
now = (PORTB & mask)? ON : OFF;
if(state == now) return;
if(state == ON) PORTB |= mask;
else PORTB &= ~mask;
}
static inline void relay(bool state)
{
const u1 mask = 0x80; /* 1000_0000 */
u1 now;
now = (PORTD & mask)? ON : OFF;
if(state == now) return;
if(state == ON) PORTD |= mask;
else PORTD &= ~mask;
}
static inline void inc_gtime()
{
static u1 i = 0;
i = (i + 1) % 49; /* 0..49 --> T= 1sec */
if((i==0) && (gtime < 0xFFFFFFFF)) gtime++;
}
static inline void select_sw_input(void)
{
static u1 cnt = 0;
cnt = (cnt + 1) % 5; /* 0..4 */
PORTD = (0xE0 & PORTD) | (0x01 << cnt); /* 1110_0000 */
if(0x20 & PIND) select_sw = cnt; /* 0010_0000 */
}
static inline void select_sw_out(void)
{
u1 sel_out;
switch(select_sw) {
case 0: /* phone input */
relay(ON);
break;
case 1: /* PC1: USB IF */
case 2: /* PC2: opt1 */
case 3: /* PC3: opt2 */
case 4: /* PC4: opt3 */
sel_out = ((select_sw - 1) << 1) & 0x06; /* xxxx_x11x */
PORTC = (PORTC & 0xF9) | sel_out; /* dai-out */
relay(OFF);
break;
default:
relay(OFF);
}
}
static inline void mute_ctrl(void)
{
if(PIND & 0x40) {
mute_out(ON); led_out(ON);
} else {
mute_out(OFF); led_out(OFF);
}
}
static inline void adc_start(void)
{
disable_interrupt();
ADCSRA |= 0x40; /* 0100_0000 */
enable_interrupt();
}
static inline void spi_send_byte(u1 byte)
{
SPDR = byte;
while((SPSR & 0x80) == 0); /* wait for transmission */
}
u1 get_volume_data(u2 ad)
{
u1 out;
out = (u1)(ad >> 2);
return out;
}
static inline void spi_ss_out(bool level)
{
const u1 mask = 0x04; /* 0000_0100 */
if(level)
PORTB |= mask;
else
PORTB &= ~mask;
}
static inline void volume_out(void)
{
u1 vol_left, vol_right;
vol_left = get_volume_data(vol_ad);
vol_right = vol_left;
disable_interrupt();
spi_ss_out(LO);
spi_send_byte(vol_right);
spi_send_byte(vol_left);
spi_ss_out(HI);
enable_interrupt();
}
/*============================*/
/* interrupt service routines */
/*============================*/
/* timer0 compare A: volume input */
ISR(TIMER0_COMPA_vect)
{
/* dbg(5, ON); */
disable_interrupt();
TCNT0 = 0;
enable_interrupt();
/* dbg(5, OFF); */
}
/* timer1 compare A: */
ISR(TIMER1_COMPA_vect)
{
/* dbg(3, ON); */
disable_interrupt();
enable_interrupt();
/* dbg(3, OFF); */
}
/* timer2 compare A: select sw, gtime */
ISR(TIMER2_COMPA_vect)
{
/* dbg(4, ON); */
disable_interrupt();
select_sw_input();
TCNT2 = 0;
inc_gtime();
enable_interrupt();
/* dbg(4, OFF); */
}
/* adc conversion complete: volume */
ISR(ADC_vect)
{
/* dbg(5, ON); */
disable_interrupt();
vol_ad = (ADC >> 6); /* 10 bits, left adjusted */
enable_interrupt();
/* dbg(5, OFF); */
}
/*============*/
/* initialize */
/*============*/
void init_device(void)
{
/* ------------------------------ */
/* unlock peripheral restrictions */
/* ------------------------------ */
PRR = 0x00;
/* clock: external xtal 10MHz */
/* ------------- */
/* wdt */
/* ------------- */
WDTCSR = 0x00; /* disable wdt */
/* ------------- */
/* gpio */
/* ------------- */
/* port B */
PORTB = 0xFF;
DDRB = 0xEF;
/* 7 4 3 0 */
/* o o o i___o o o o */
/* | | | | | | | | */
/* | | | | | | | | */
/* | | | | | | | +-- PB0 : LED */
/* | | | | | | +---- PB1 : MUTE-OUT */
/* | | | | | +------ PB2 : ~SS (SPI) */
/* | | | | +-------- PB3 : MOSI(SPI) */
/* | | | +------------ PB4 : MISO(SPI) not use */
/* | | +-------------- PB5 : SCK(SPI) */
/* | +---------------- PB6 : XTAL */
/* +------------------ PB7 : XTAL */
/* port C */
PORTC = 0x00;
DDRC = 0xBE;
/* 7 4 3 0 */
/* o i o o___o o o i */
/* | | | | | | | */
/* | | +-----+ +-+ | */
/* | | | | +-- PC0 : VOL(ADIN) */
/* | | | +----- PC2-1: DAI-OUT */
/* | | +---------- PC5-3: debug */
/* | +---------------- PC6 : RESET */
/* +------------------ PC7 : debug */
/* port D */
PORTD = 0x00;
DDRD = 0x9F;
/* 7 4 3 0 */
/* o i i o___o o o o */
/* | | | | | */
/* | | | +---------+ */
/* | | | | */
/* | | | +------ PD4-0: SEL-OUT */
/* | | +-------------- PD5 : SEL-IN */
/* | +---------------- PD6 : MUTE-SW */
/* +------------------ PD7 : RELAY-OUT */
/* ------------- */
/* timer */
/* ------------- */
/* timer0: volume --> adc */
TCCR0A = 0x00;
TCCR0B = 0x05; /* Tck= 102.4us (= 10MHz / 1024) */
OCR0A = 90; /* T=10ms (=102.4us * 98) */
TCNT0 = 0;
TIMSK0 = 0x02; /* enable comapre A */
#if 0
/* timer1: - */
TCCR1A = 0x00;
TCCR1B = 0x05; /* Tck= 102.4us (= 10MHz / 1024) */
OCR1A = 9766; /* T= 1s (= 102.4us * 9766) */
TCNT1 = 0;
TIMSK1 = 0x02; /* enable compare A */
#endif
/* timer2: select sw */
TCCR2A = 0x00;
TCCR2B = 0x07; /* Tck=102.4us (= 10MHz / 1024) */
OCR2A = 195; /* T=20ms select sw */
TCNT2 = 0;
TIMSK2 = 0x02; /* enable compare A */
/* ------------- */
/* adc: volume */
/* ------------- */
ADMUX = 0x60; /* AREF, PC0, left adjust */
DIDR0 = 0x01; /* PC0 as adc input */
ADCSRB = 0x03; /* auto start adc (by timer 0 compare A) */
ADCSRA = 0xAF; /* 1010_1111 */
/* ------------- */
/* spi: PGA2311 */
/* ------------- */
/* DDR_SPI = EF; */
SPCR = 0x5E;
/* 7 4 3 0 */
/* 0 1 0 1___1 1 1 0 */
/* | | | | | | | | */
/* | | | | | | +-+ */
/* | | | | | | | */
/* | | | | | | +-- SPR : ck/64 */
/* | | | | | +------ CPHA : 1 */
/* | | | | +-------- CPOL : 1 */
/* | | | +------------ MSTR : MASTER */
/* | | +-------------- DORD : MSB First */
/* | +---------------- SPE : ENABLE */
/* +------------------ SPIE : - */
#if 0
SPSR = 0x00; /* 156.25kHz (= ck/64) */
#endif
/* 7 4 3 0 */
/* 0 0 x x___x x x 0 */
/* | | | */
/* | | +-- SPI2X: OFF */
/* | +---------------- WCOL : - */
/* +------------------ SPIF : - */
enable_interrupt();
}
void init_rams(void)
{
gtime = 0;
mute_sw = 0;
select_sw = 1; /* USB IF */
vol_ad = 0;
}
/*===========*/
/* main */
/*===========*/
int main(void)
{
init_device();
init_rams();
adc_start();
while(1) {
if(gtime < 5) { led_out(ON); continue; }
else { led_out(OFF); }
select_sw_out();
volume_out();
mute_ctrl();
}
return 0;
}
/* this program ends here */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment