Head-Fi.org › Forums › Misc.-Category Forums › DIY (Do-It-Yourself) Discussions › What I did next with Texas headamp chip, a digital control desktop / portable.
New Posts  All Forums:Forum Nav:

What I did next with Texas headamp chip, a digital control desktop / portable. - Page 2

post #16 of 21
Thread Starter 

I have PCBs for this build. The previous PCB had a simple error (inverted servo opamp), I was able to work around it, but I wouldn't want to supply them as was. I haven't built one on the new PCB yet, but I have the components.

 

A slight complication is that a programmed PIC 16F887 is required, and I normally program it on the board. I don't have a programming socket for TQFP44s.

 

It's a demanding build; the daughterboard has a tiny clearance, push switches require hand fettling, the pins on the display require to be cut to length, the PSU requires both rails set to within 0.1V lest the batteries over- or under-charge, front and rear panels need drilling and filing and finally a battery-box must be built out of copper-clad board or battery holders bought. Protected lithium cells are needed if battery operation is intended. Cost of components probably exceeds $150, although I haven't figured it out.

 

All that said, it has outstanding performance, it's portable, it has headphone protection and it has independent channel volume (which I've never needed). It's my go-to amp even in the house because it's self-contained.

 

I'm considering supplying a short kit with the difficult-to-obtain parts, or I could try to figure out a price for everything, although this would mean quite a big outlay for, say, 10 kits. What do you think is preferable?

 

w

post #17 of 21

Well, certainly the kit would be great for us the builders, but lots of work for you. The short kit with hard to get parts would be more than ok too. If you decide to go for the kit, round up a couple of fellow builders to help assemble and bear the cost. You could count me in for that - either way you go.

post #18 of 21
Thread Starter 

Misterrogers having expressed an interest and willingness to help, I have given him the first short kit FOC.

 

Here is the schematic.

 

 

 

...in 2 sections

 

 

 

These show insufficient detail, so a .jpg created from a 600 dpi .bmp can be downloaded from here:-

 

http://dl.dropbox.com/u/107775480/tpa6120_pga2320.jpg.

 

Here is the basic BOM, I will do an annotated version tomorrow, I'm tired now.

 

 

Bill Of Materials
=================
Design:   C:\Program Files\Labcenter Electronics\Proteus 7 Professional\proteus_designs\d56233_10x10_2.DSN
Doc. no.: <NONE>
Revision: <NONE>
Author:   <NONE>
Created:  16/05/11
Modified: 02/10/12

QTY  PART-REFS           VALUE               
---  ---------           -----               
Resistors
---------
9    R1-R4,R11,R12,R38,  1k                  
     R45,R46
2    R5,R6               47R                 
12   R7-R9,R15-R19,      10R                 
     R29-R32
2    R10,R14             220R                
6    R13,R28,R39-R41,R49 10k                 
11   R20-R27,R35-R37     470R                
5    R42,R44,R50,R215,   100k                
     R315
1    R57                 1M                  
1    R116                4k7                 
2    R219,R312           120k                
2    R310,R311           390k                

Capacitors
----------
7    C1,C3,C28-C31,C112  470u                
2    C2,C4               1n8                 
10   C5-C8,C16,C17,C21,  47u                 
     C24,C25,C33
11   C9-C12,C15,C18-C20, 100n                
     C22,C23,C32
4    C35,C36,C213,C214   10u                 

Integrated Circuits
-------------------
1    U1                  TPA6120A            
1    U2                  LM337               
1    U4                  LM317L              
2    U5,U9               7805                
1    U6                  PGA2310             
1    U7                  OPA2277             
1    U8                  PIC16F877A-PT       
1    U10                 LM2901              
1    U11                 LM49725             
1    U12                 7-SEG-3-DIG         

Transistors
-----------
4    Q1-Q3,Q5            PNP_SOT23           
2    Q4,Q6               FMMT495             

Diodes
------
5    D1-D5               DIODE               
1    D7                  DIODE-LED           

Miscellaneous
-------------
6    BAT1-BAT6           3.6V                
1    J1                  PIC_ICSP_HDR        
2    J2,J13              CONN-SIL3           
2    J3,J6               CONN-SIL5           
3    J4,J8,J9            PUSH_SW             
2    J10,J15             CONN-SIL8-RTA       
1    J14                 JACK-PWR            
2    L1,L2               1u7                 
2    L5,L6               2773021447          
1    RL3                 AXICOM IM23GR 5V    
2    RV1,RV2             5k                  
1    SW2                 SW-4PDT             

 

w

post #19 of 21
Thread Starter 

Here's the C code:-

 

/*RE2 = SCK*/
/*RE1 = CS*/
/*RE0 = SDI*/
#include <pic.h>
#include <htc.h>
#include <pic16f887.h>

#define DATA_0_ADDR    0
#define DATA_1_ADDR    1
#define DATA_2_ADDR    2
#define DATA_3_ADDR    3
#define DATA_4_ADDR    4
#define DATA_5_ADDR    5
#define DATA_6_ADDR    6
#define DATA_7_ADDR    7

#define AITCH           0b00101001
#define ZERO            0b10001000
#define ONE             0b11101101
#define TWO             0b01001010
#define THREE           0b01001100
#define FOUR            0b00101101
#define FIVE            0b00011100
#define SIX             0b00011000 
#define SEVEN           0b11001101
#define EIGHT           0b00001000
#define NINE            0b00001101
#define DECIMAL         0b11110111
#define BLANK           0b11111111

unsigned char   d_flag;
unsigned char   mode_flag;
unsigned char   d_tmp;
unsigned char   r_un;
unsigned char   r_te;
unsigned char   r_hu;
unsigned char   l_un;
unsigned char   l_te;
unsigned char   l_hu;
unsigned char   l_buf;
unsigned char   r_buf;
unsigned char   p_buf;
unsigned char   q_buf;
unsigned char   d_un;
unsigned char   d_te;
unsigned char   d_hu;
unsigned char   un;
unsigned char   te;
unsigned char   hu;
unsigned char   buf;
unsigned char   ybuf;
unsigned char   x0buf;
unsigned char   x1buf;
unsigned char   x2buf;
unsigned char   x3buf;
unsigned char   x4buf;
unsigned char   x5buf;
unsigned char   x6buf;
unsigned char   x7buf;
unsigned char   x8buf;
unsigned char   x9buf;
unsigned char   xabuf;
unsigned char   xbbuf;
unsigned char   xcbuf;
unsigned char   xdbuf;
unsigned char   xebuf;
unsigned char   xfbuf;
unsigned char   delay_ctr;
unsigned char   delay2ctr;
unsigned char   delay3ctr;
unsigned char   delay_q;
unsigned char   s1leep;
unsigned char   s2leep;
unsigned char   s3leep;
char            l_r;
int i;

void main(void);
void remember(void);
void interrupt mplx (void);
void do_disp(char);
void ddelay(void);
void ldelay(void);
void get_switches(void);
void xmit(void);

void interrupt mplx(void){
    if(mode_flag==2){
        switch(d_flag){
            case 0:
                PORTC=0b11111111;
                d_tmp=d_un;
                d_tmp&=DECIMAL;
                PORTB=d_tmp;
                PORTC=0b11101111;
                d_flag++;
                T0IF=0;
                break;
            case 1:
                PORTA=0b11111111;
                d_tmp=d_te;
                PORTB=d_tmp;
                PORTC=0b10111111;
                d_flag++;
                T0IF=0;
                break;
            case 2:
                PORTC=0b11111111;
                d_tmp=d_hu;
                PORTB=d_tmp;
                PORTC=0b11011111;
                d_flag=0;
                T0IF=0;
                break;
            default:
                break;
        }
    }
    if(mode_flag==1){
        switch(d_flag){
            case 0:
                PORTC=0b11111111;
                d_tmp=d_un;
                PORTB=d_tmp;
                PORTC=0b11101111;
                d_flag++;
                T0IF=0;
                break;
                case 1:
                PORTA=0b11111111;
                d_tmp=d_te;
                d_tmp&=DECIMAL;
                PORTB=d_tmp;
                PORTC=0b10111111;
                d_flag++;
                T0IF=0;
                break;
            case 2:
                PORTC=0b11111111;
                d_tmp=d_hu;
                PORTB=d_tmp;
                PORTC=0b11011111;
                d_flag=0;
                T0IF=0;
                break;
            default:
                break;
        }
    }        
    if(mode_flag==0){
        switch(d_flag){    
            case 0:
                PORTC=0b11111111;
                d_tmp=d_un;
                PORTB=d_tmp;
                PORTC=0b11101111;
                d_flag++;
                T0IF=0;
                break;
            case 1:
                PORTA=0b11111111;
                d_tmp=d_te;
                PORTB=d_tmp;
                PORTC=0b10111111;
                d_flag++;
                T0IF=0;
                break;
            case 2:
                PORTC=0b11111111;
                d_tmp=d_hu;
                PORTB=d_tmp;
                PORTC=0b11011111;
                d_flag=0;
                T0IF=0;
                break;
            default:
                break;
        }
    }
    return;
}

void main(void){

    OSCCON   = 0b01110111;
    TRISA    = 0x00;
    TRISB    = 0x00;
    TRISC    = 0x00;
    TRISD    = 0x00;
    TRISE    = 0x00;
    TRISA0   = 1;
    TRISD5   = 1;
    TRISD6   = 1;
    TRISD7   = 1;

    PORTA    = 0xFF;
    PORTB    = 0xFF;
    PORTC    = 0xFE;
    PORTD    = 0xFF;
    PORTE    = 0xFF;
    s1leep=0;
    s2leep=0;
    s3leep=0;
    buf=0;
    d_flag=0;
    mode_flag=0;
    l_buf=0;
    r_buf=0;
    xmit();
    l_buf=eeprom_read(DATA_0_ADDR);
    r_buf=eeprom_read(DATA_1_ADDR);
    r_un=eeprom_read(DATA_2_ADDR);
    r_te=eeprom_read(DATA_3_ADDR);
    r_hu=eeprom_read(DATA_4_ADDR);
    l_un=eeprom_read(DATA_5_ADDR);
    l_te=eeprom_read(DATA_6_ADDR);
    l_hu=eeprom_read(DATA_7_ADDR);
    d_un=BLANK;
    d_te=BLANK;
    d_hu=BLANK;
    PSA=0;
    PS0=0;
    PS1=0;
    PS2=1;
    T0CS=0;
    T0SE=0;
    T0IE=1;
    GIE=1;
    delay_q=0;
    ldelay();
    d_un=AITCH;
    delay_q=0;
    ldelay();
    d_un=ONE;
    d_te=AITCH;
    delay_q=0;
    ldelay();
    d_un=BLANK;
    d_te=ONE;
    d_hu=AITCH;
    delay_q=0;
    ldelay();
    d_un=BLANK;
    d_te=BLANK;
    d_hu=ONE;
    delay_q=0;
    ldelay();
    d_un=BLANK;
    d_te=BLANK;
    d_hu=BLANK;
    delay_q=0;
    ldelay();
    if(l_buf>r_buf){
        do_disp(0);
    }    
    else{
        do_disp(1);
    }
    delay_q=0;
    ldelay();
    for(i=0;i<10;i++){
    xmit();
    delay_q=0;
    ldelay();
    }
    while (1){
        get_switches();
        s1leep++;
        if(s1leep==255){
            s1leep=0;
            s2leep++;
            if(s2leep==255){
                s2leep=0;
                s3leep++;
                if(s3leep==5){
                    s3leep=0;
                    remember();
                    T0IE=0;
                    GIE=0;
                    PORTA=0b11111111;
                    PORTC=0b11111110;
                    ULPWUIF=0;
                    ULPWUE=1;
                    ULPWUIE=1;
                    PEIE=1;
                    asm("SLEEP");
                    PEIE=0;
                    ULPWUE=0;
                    ULPWUIE=0;
                    T0IE=1;
                    GIE=1;
                    ddelay();
                }
            }
        }
    }
}

void remember(void){
    eeprom_write(DATA_0_ADDR,l_buf);
    eeprom_write(DATA_1_ADDR,r_buf);
    eeprom_write(DATA_2_ADDR,r_un);
    eeprom_write(DATA_3_ADDR,r_te);
    eeprom_write(DATA_4_ADDR,r_hu);
    eeprom_write(DATA_5_ADDR,l_un);
    eeprom_write(DATA_6_ADDR,l_te);
    eeprom_write(DATA_7_ADDR,l_hu);
}

void xmit(void){
/*    p_buf=r_buf;
    q_buf=l_buf;
    r_buf=255;
    l_buf=255;*/
    x0buf=l_buf & 0b10000000;
    x1buf=l_buf & 0b01000000;  
    x2buf=l_buf & 0b00100000;  
    x3buf=l_buf & 0b00010000;
    x4buf=l_buf & 0b00001000;
    x5buf=l_buf & 0b00000100;
    x6buf=l_buf & 0b00000010;
    x7buf=l_buf & 0b00000001;
    x8buf=r_buf & 0b10000000;
    x9buf=r_buf & 0b01000000;
    xabuf=r_buf & 0b00100000;
    xbbuf=r_buf & 0b00010000;
    xcbuf=r_buf & 0b00001000;
    xdbuf=r_buf & 0b00000100;
    xebuf=r_buf & 0b00000010;
    xfbuf=r_buf & 0b00000001;
    T0IE=0;
    GIE=0;
    PORTE=0b11111111;
    PORTE=0b11111101;
    if(x0buf){
        PORTE=0b11111001;
        PORTE=0b11111101;
    }
    else{
        PORTE=0b11111000;
        PORTE=0b11111100;
    }
    if(x1buf){
        PORTE=0b11111001;
        PORTE=0b11111101;
    }
    else{
        PORTE=0b11111000;
        PORTE=0b11111100;
    }
    if(x2buf){
        PORTE=0b11111001;
        PORTE=0b11111101;
    }
    else{
        PORTE=0b11111000;
        PORTE=0b11111100;
    }
    if(x3buf){
        PORTE=0b11111001;
        PORTE=0b11111101;
    }
    else{
        PORTE=0b11111000;
        PORTE=0b11111100;
    }
    if(x4buf){
        PORTE=0b11111001;
        PORTE=0b11111101;
    }
    else{
        PORTE=0b11111000;
        PORTE=0b11111100;
    }
    if(x5buf){
        PORTE=0b11111001;
        PORTE=0b11111101;
    }
    else{
        PORTE=0b11111000;
        PORTE=0b11111100;
    }
    if(x6buf){
        PORTE=0b11111001;
        PORTE=0b11111101;
    }
    else{
        PORTE=0b11111000;
        PORTE=0b11111100;
    }
    if(x7buf){
        PORTE=0b11111001;
        PORTE=0b11111101;
    }
    else{
        PORTE=0b11111000;
        PORTE=0b11111100;
    }
    if(x8buf){
        PORTE=0b11111001;
        PORTE=0b11111101;
    }
    else{
        PORTE=0b11111000;
        PORTE=0b11111100;
    }
    if(x9buf){
        PORTE=0b11111001;
        PORTE=0b11111101;
    }
    else{
        PORTE=0b11111000;
        PORTE=0b11111100;
    }
    if(xabuf){
        PORTE=0b11111001;
        PORTE=0b11111101;
    }
    else{
        PORTE=0b11111000;
        PORTE=0b11111100;
    }
    if(xbbuf){
        PORTE=0b11111001;
        PORTE=0b11111101;
    }
    else{
        PORTE=0b11111000;
        PORTE=0b11111100;
    }
    if(xcbuf){
        PORTE=0b11111001;
        PORTE=0b11111101;
    }
    else{
        PORTE=0b11111000;
        PORTE=0b11111100;
    }
    if(xdbuf){
        PORTE=0b11111001;
        PORTE=0b11111101;
    }
    else{
        PORTE=0b11111000;
        PORTE=0b11111100;
    }
    if(xebuf){
        PORTE=0b11111001;
        PORTE=0b11111101;
    }
    else{
        PORTE=0b11111000;
        PORTE=0b11111100;
    }
    if(xfbuf){
        PORTE=0b11111001;
        PORTE=0b11111101;
        PORTE=0b11111111;
        PORTE=0b11111111;
    }
    else{
        PORTE=0b11111000;
        PORTE=0b11111100;
        PORTE=0b11111110;
        PORTE=0b11111111;
    }
    T0IE=1;
    GIE=1;
    s1leep=0;
    s2leep=0;
    s3leep=0;
/*    r_buf=p_buf;
    l_buf=q_buf;*/
}

void get_switches(void){
    if((RD5)&&(RD7)){
        delay_q=0;
    }
    if(!(RD5)){
        if(mode_flag==2){
            if(l_buf<255){
                l_buf++;
                do_disp(0);
                xmit();
            }
        }
        if(mode_flag==1){
            if(r_buf<255){
                r_buf++;
                do_disp(1);
                xmit();
            }
        }
        if(mode_flag==0){
            if((r_buf<255)&&(l_buf<255)){
                l_buf++;
                r_buf++;
                if(l_buf>r_buf){
                    do_disp(0); 
                }
                else{
                    do_disp(1); 
                }
                xmit();
            }
        } 
        ldelay();
    }
    if(!(RD6)){
        switch(mode_flag){
            case 0:
                mode_flag=1;
                do_disp(1); 
            break;
            case 1:
                mode_flag=2;
                do_disp(0); 
            break;
            case 2:
                mode_flag=0;
                if(l_buf>r_buf){
                    do_disp(0); 
                }
                else{
                    do_disp(1); 
                }
            break;
            default:
            break;
        }
        ddelay();
    }
    if(!(RD7)){
        if(mode_flag==2){
            if(l_buf>0){
                l_buf--;
                do_disp(0);
                xmit();
            }
        }
        if(mode_flag==1){
            if(r_buf>0){
                r_buf--;
                do_disp(1);
                xmit();
            }
        }
        if(mode_flag==0){
            if((r_buf>0)&&(l_buf>0)){
                l_buf--;
                r_buf--;
                if(l_buf>r_buf){
                    do_disp(0); 
                }
                else{
                    do_disp(1); 
                }
                xmit();
            }
        } 
        ldelay();
    }
}

void do_disp(char l_r){
    if(l_r==0){
        buf=l_buf;
    }
    else{
        buf=r_buf;
    }
    hu=ZERO;
    te=ZERO;
    un=ZERO;
    if (buf>199){
        buf-=200;
        hu=TWO;
    }
    if(buf>99){
        buf-=100;
        hu=ONE;
    }
    if(buf>89){
        buf-=90;
        te=NINE;
    }
    if(buf>79){
        buf-=80;
        te=EIGHT;
    }
    if(buf>69){
        buf-=70;
        te=SEVEN;
    }
    if(buf>59){
        buf-=60;
        te=SIX;
    }
    if(buf>49){
        buf-=50;
        te=FIVE;
    }
    if(buf>39){
        buf-=40;
        te=FOUR;
    }
    if(buf>29){
        buf-=30;
        te=THREE;
    }
    if(buf>19){
        buf-=20;
        te=TWO;
    }
    if(buf>9){
        buf-=10;
        te=ONE;
    }
    if(buf==9){
        buf-=9;
        un=NINE;
    }
    if(buf==8){
        buf-=8;
        un=EIGHT;
    }
    if(buf==7){
        buf-=7;
        un=SEVEN;
    }
    if(buf==6){
        buf-=6;
        un=SIX;
    }
    if(buf==5){
        buf-=5;
        un=FIVE;
    }
    if(buf==4){
        buf-=4;
        un=FOUR;
    }
    if(buf==3){
        buf-=3;
        un=THREE;
    }
    if(buf==2){
        buf-=2;
        un=TWO;
    }
    if(buf==1){
        buf-=1;
        un=ONE;
    }
    d_un=un;
    d_te=te;
    d_hu=hu;
}

void ldelay(void){
    if(delay_q<6){
        delay_q++;
    }
    delay2ctr--;
    while(delay2ctr){
        delay_ctr--;
        while(delay_ctr){
            delay_ctr--;
            if(delay_q==6){
                if(delay_ctr>=4){
                    delay_ctr--;
                    delay_ctr--;
                    delay_ctr--;
                    delay_ctr--;
                }
            }
        }
        delay2ctr--;
    }
    delay2ctr=0x88;
}

void ddelay(void){
    delay3ctr--;
    while(delay3ctr){
        delay3ctr--;
        delay_ctr--;
        while(delay_ctr){
            delay_ctr--;
        }
    }
}

 

w

post #20 of 21
Thread Starter 

So what does all that stuff do?

 

It reads the switches, shows the values on the display, updates the Left and Right volume registers in the volume chip and finally goes to sleep when nothing happens for ~20 seconds. Nothing in the way of button presses that is.

 

If you want to wake the system up, you press the right hand button.

 

The system has 3 operating modes. You can adjust the left, right or both volumes simultaneously. Righthand button is up, lefthand button is down. Default is both channels locked, the display shows the higher channel.

 

The display uses the 7-segment units upside down. Consequently 2 red dots are available on either side of the centre digit, these are used to indicate when left or right channel is controlled. The centre button cycles between modes.

 

This code works. It's a simple continuous loop that polls the switches and responds accordingly. The data words are all assembled explicitly and obviously and communications to the volume control bit-banged out of 3 pins. The display is multiplexed common anode, updated at every button press.

 

A simple hardware arrangement means that the righthand switch can pull up an unused pin on the uProc which is available for the wake-from-sleep function. Ultimately it proved necessary to embed the sleep instruction in the C code as assembler. If the settings are left for some seconds undisturbed, then they are written to the PIC's EEPROM, to be retrieved when the machine reboots.

 

I built 3 of these. One, without batteries or case, was taped to the back of a TV as a preamp. The cats knocked everything over and destroyed it. The 2nd killed all its batteries (or the batteries died). The 3rd is still working fine after ~2.5 years, batteries still accept charge.

 

w

post #21 of 21
Thread Starter 

 

w

New Posts  All Forums:Forum Nav:
  Return Home
Head-Fi.org › Forums › Misc.-Category Forums › DIY (Do-It-Yourself) Discussions › What I did next with Texas headamp chip, a digital control desktop / portable.