What I did next with Texas headamp chip, a digital control desktop / portable.
Sep 16, 2012 at 9:49 PM Post #16 of 22
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
 
Sep 16, 2012 at 10:28 PM Post #17 of 22
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.
 
Oct 1, 2012 at 8:48 PM Post #18 of 22
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.
 
 
Code:
 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
 
Mar 20, 2014 at 8:46 PM Post #19 of 22
Here's the C code:-
 
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
 
Mar 20, 2014 at 9:51 PM Post #20 of 22
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
 

Users who are viewing this thread

Back
Top