; Preamp_06_07.asm - Andreas W. Schilloff ; Triple 5.1 channel input preamp with IR remote control. ; ; NOTE: The code entered as comments after MemRead is used to display the Data Byte ; read from the NEC6121 IR transmission format.This may be used to adapt different ; remotes or functions. ; ; Modify to add offsets back in for all 3 inputs (DD surround installed). 7/31/07 ; Modify to bypass offsets for input 1 (TV surround). 5/16/07 ; Modify to allow 0dB-60dB step range with different channel levels. 5/16/07 ; Complete original program version. 4/21/07 ; Implement different level settings for REAR, SUB, and CENTER channels. 4/21/07 ; Add mute function (remote). 4/19/07 ; Begin adding remote control functions. 4/18/07 ; Implement dec/inc attn subroutines with lookup tables. 4/17/07 ; Create framework of Inc/Dec Attn routines. 4/15/07 ; Add attenuator chip subroutines. 4/13/07 ; Begin preamp testing: add source selection code. 4/1/07 ; Test cycling Update loop while waiting for IR signal. 2/26/07 ; Imported IR read code from IR Dev2 6121.asm. 1/27/07 ; Program started to test display routines/ function. 1/27/07 LIST P=pic16f57 INCLUDE __CONFIG _XT_OSC& _WDT_OFF& _CP_OFF ; Port definitions here ***************************************************** ; ; RA3 - IR DETECTOR ; RA2 - SW3 ; RA1 - SW2 ; RA0 - SW1 ; ; RB7 - DISP1 (TRANSISTOR) ; RB6 - G (DISPLAY SEGMENT) ; RB5 - F ; RB4 - E ; RB3 - D ; RB2 - C ; RB1 - B ; RB0 - A ; ; RC7 - SEL_0 ; RC6 - SEL_1 ; RC5 - CLOCK ; RC4 - !SHIFT_0 ; RC3 - !SHIFT_1 ; RC2 - DATA ; RC1 - DISP2 (TRANSISTOR) ; RC0 - DISP3 ; *************************************************************************** ; Variables here. DIGIT1 equ 0x08 DIGIT2 equ 0x09 DIGIT3 equ 0x0a DIGITPOINT equ 0x0b COUNT1 equ 0x0c COUNT2 equ 0x0d TMP equ 0x0e DISPLAYVAL equ 0x0f IRBYTE0 equ 0x10 IRBYTE1 equ 0x11 IRBYTE2 equ 0x12 IRBYTE3 equ 0x13 READCNT equ 0x14 SOURCE equ 0x15 BYTESND equ 0x16 ATTNSTEP equ 0x17 FRONT equ 0x18 REAR equ 0x19 CENTER equ 0x1a SUB equ 0x1b ; Constants here. MSEC8 equ d'131' ;TMR0 value to time out in 8 msec TRAN1 equ 7 TRAN2 equ 0 TRAN3 equ 1 SW1 equ 0 SW2 equ 1 SW3 equ 2 IRDET equ 3 SEL0 equ 7 SEL1 equ 6 CLOCK equ 5 SHIFT0 equ 4 SHIFT1 equ 3 DAT equ 2 ; *************************************************************************** ; Subroutines here. org 0 goto Main ; Delay subroutine ; Provides a nominal delay while continuing to update the display. Delay movlw 0x30 ;display selection delay loop movwf COUNT2 clrf COUNT1 Dloop call Update incfsz COUNT1 goto Dloop decfsz COUNT2 goto Dloop return ; Update subroutine ; Each time this routine is called, the next DIGIT (1,2,3) is displayed on the multiplexed ; LED display. Update btfsc DIGITPOINT,0 ;display 1st digit? (bit 0=1) goto disp1 btfsc DIGITPOINT,1 ;display 2nd digit? (bit 1=1) goto disp2 disp3 bcf PORTC,TRAN2 ;turn off 2nd transistor movf DIGIT3,W ;display 3rd digit movwf PORTB bsf PORTC,TRAN3 ;turn on 3rd transistor movlw 0x01 ;next will be the first digit movwf DIGITPOINT return disp2 bcf PORTB,TRAN1 ;turn off 1st transistor movf DIGIT2,W ;display 2nd digit movwf PORTB bsf PORTC,TRAN2 ;turn on 2nd transistor rlf DIGITPOINT,1 ;next will be the 3rd digit return disp1 bcf PORTC,TRAN3 ;turn off 3rd transistor movf DIGIT1,W ;display 1st digit movwf PORTB bsf PORTB,TRAN1 ;turn on 1st transistor rlf DIGITPOINT,1 ;next will be the 2nd digit return ; ToHex subroutine ; The 7-segment display value is returned for the 4 LSB's in W using a look-up table. ToHex addwf PCL retlw b'00111111' ;0 retlw b'00000110' ;1 retlw b'01011011' ;2 retlw b'01001111' ;3 retlw b'01100110' ;4 retlw b'01101101' ;5 retlw b'01111101' ;6 retlw b'00000111' ;7 retlw b'01111111' ;8 retlw b'01101111' ;9 retlw b'01110111' ;A retlw b'01111100' ;b retlw b'00111001' ;C retlw b'01011110' ;d retlw b'01111001' ;E retlw b'01110001' ;F ; SendAttn ; This sends the byte in BYTESND to the attn. chips (via serial interface). SendAttn movlw 8 ;8 bits to clock movwf COUNT1 Snd1 bcf PORTC,CLOCK ;prepare clock line bcf PORTC,DAT ;default is to clock a low rlf BYTESND,F ;rotate left through carry byte to send btfsc STATUS,C ;if zero, skip bsf PORTC,DAT ;if not, send a high bsf PORTC,CLOCK ;clock to high decfsz COUNT1 goto Snd1 bcf PORTC,CLOCK return ; Attn subroutine ; This sends the address and attenuation step data to the LM1973 attn. chips. ; FRONT reg contains the attenuation data. Attn movf ATTNSTEP,W movwf FRONT ;copy current attn step to all attn variables movwf REAR movwf SUB movwf CENTER movlw 3 ;set SUB 3 steps (6dB) higher than FRONT subwf SUB,F btfsc STATUS,C ;if (!borrow), then overshot 0dB step. goto a1 clrf SUB ;overshot 0dB step, set to 0. a1 movlw 1 ;set REAR one step higher (+2dB) relative to FRONT subwf REAR,F btfsc STATUS,C ;if (!borrow), then overshot 0dB step. goto a2 clrf REAR ;overshot 0dB step, set to 0. a2 incf CENTER,F ;set CENTER one step (-2dB) relative to FRONT movf FRONT,W bsf STATUS,PA0 ;get ready to call from page 1 call GetAttn ;grab LM1973 step data bcf STATUS,PA0 ;back to page 0 movwf FRONT ;replace FRONT attn step with LM1973 step data movf REAR,W bsf STATUS,PA0 ;get ready to call from page 1 call GetAttn ;grab LM1973 step data bcf STATUS,PA0 ;back to page 0 movwf REAR ;replace REAR attn step with LM1973 step data movf SUB,W bsf STATUS,PA0 ;get ready to call from page 1 call GetAttn ;grab LM1973 step data bcf STATUS,PA0 ;back to page 0 movwf SUB ;replace SUB attn step with LM1973 step data movf CENTER,W bsf STATUS,PA0 ;get ready to call from page 1 call GetAttn ;grab LM1973 step data bcf STATUS,PA0 ;back to page 0 movwf CENTER ;replace CENTER attn step with LM1973 step data bcf PORTC,SHIFT0 ;LM1973 chip 1 enable clrf BYTESND ;address front right channel call SendAttn movf FRONT,W ;load attn data movwf BYTESND call SendAttn bsf PORTC,SHIFT0 ;load channel 1 info bcf PORTC,SHIFT0 ;LM1973 chip 1 enable movlw 1 movwf BYTESND ;address front left channel call SendAttn movf FRONT,W ;load attn data movwf BYTESND call SendAttn bsf PORTC,SHIFT0 ;load channel 2 info bcf PORTC,SHIFT0 ;LM1973 chip 1 enable movlw 2 ;address sub channel movwf BYTESND call SendAttn movf SUB,W ;load attn data movwf BYTESND call SendAttn bsf PORTC,SHIFT0 ;load channel 3 info bcf PORTC,SHIFT1 ;LM1973 chip 2 enable clrf BYTESND ;address center channel call SendAttn movf CENTER,W ;load attn data movwf BYTESND call SendAttn bsf PORTC,SHIFT1 ;load channel 1 info bcf PORTC,SHIFT1 ;LM1973 chip 2 enable movlw 1 ;address rear right channel movwf BYTESND call SendAttn movf REAR,W ;load attn data movwf BYTESND call SendAttn bsf PORTC,SHIFT1 ;load channel 2 info bcf PORTC,SHIFT1 ;LM1973 chip 2 enable movlw 2 ;address rear left channel movwf BYTESND call SendAttn movf REAR,W ;load attn data movwf BYTESND call SendAttn bsf PORTC,SHIFT1 ;load channel 3 info return ; Mute subroutine ; Send ffh to all LM1973 registers (mute) without changing the ATTNSTEP variable. Mute bcf PORTC,SHIFT0 ;chip enable bcf PORTC,SHIFT1 clrf BYTESND ;address channel 1 (LM1973) call SendAttn movlw 0xff movwf BYTESND ;mute channel 1 call SendAttn bsf PORTC,SHIFT0 ;load channel 1 info bsf PORTC,SHIFT1 bcf PORTC,SHIFT0 ;chip enable bcf PORTC,SHIFT1 movlw 1 ;address channel 2 movwf BYTESND call SendAttn movlw 0xff movwf BYTESND ;mute channel 2 call SendAttn bsf PORTC,SHIFT0 ;load channel 2 info bsf PORTC,SHIFT1 bcf PORTC,SHIFT0 ;chip enable bcf PORTC,SHIFT1 movlw 2 ;address channel 3 movwf BYTESND call SendAttn movlw 0xff ;mute channel 3 movwf BYTESND call SendAttn bsf PORTC,SHIFT0 ;load channel 3 info bsf PORTC,SHIFT1 return ; *************************************************************************** ; Code starts here. Main movlw b'00000101' ;TMR0, prescaler set to 1:64 option movlw 0xff ;port A is set to inputs tris PORTA clrw tris PORTB ;port B and C are set as outputs tris PORTC clrf PORTB ;init ports movlw b'00011000' ;attn chips not selected movwf PORTC clrf SOURCE ;init source movlw d'18' movwf ATTNSTEP ;init attenuator chips at -36dB call Attn movlw 1 movwf DIGITPOINT ;init digit pointer reg and digit values movlw b'01111111' movwf DIGIT1 movwf DIGIT2 movwf DIGIT3 movlw 0xff ;initial IR detector "settling" loop movwf COUNT2 clrf COUNT1 Wloop call Update incfsz COUNT1 goto Wloop decfsz COUNT2 goto Wloop movlw b'00000100' ;display source selection "in" n movwf DIGIT1 movlw b'01010100' movwf DIGIT2 incf SOURCE,W ;inc source value and load into W call ToHex movwf DIGIT3 Start clrf IRBYTE0 ;init IR byte readings clrf IRBYTE1 clrf IRBYTE2 clrf IRBYTE3 movlw d'32' ;init IR readings counter movwf READCNT StartIR call Update ;update display btfss PORTA,SW1 ;check if SW1(source) is pressed goto Select btfss PORTA,SW2 ;check if vol up is pressed goto DecAttn btfss PORTA,SW3 ;check if vol down is pressed goto IncAttn btfsc PORTA,IRDET ;check for an IR high pulse (active low) goto StartIR ;if low, loop ChkIRlo btfss PORTA,IRDET ;check for a low transition goto ChkIRlo movlw MSEC8 ;init real time counter movwf TMR0 ChkIRhi btfsc PORTA,IRDET ;check for a high transition goto ChkTime ;if not, check for a time out movf TMR0,W ;high transition, save TMR0 val movwf TMP movlw MSEC8 subwf TMP,F ;remove initial TMR0 value; f= f- MSEC8 movlw 0x10 ;is the pulse length < 10h? subwf TMP,W ;W=f- W btfsc STATUS,C ;if !borrow (carry=0) then pulse <10h goto Chk2 ;pulse > 10h; check for a "1" bcf STATUS,C rrf IRBYTE0,F rrf IRBYTE1,F rrf IRBYTE2,F rrf IRBYTE3,F goto Readcmp ;32 bits complete? Chk2 movlw 0x20 ;is 10h < pulse < 20h? subwf TMP,W ;W=f- W btfsc STATUS,C ;if !borrow then pulse < 20h goto ChkIRlo ;if pulse >20h then ignore bsf STATUS,C ;set carry and rotate rrf IRBYTE0,F rrf IRBYTE1,F rrf IRBYTE2,F rrf IRBYTE3,F Readcmp decfsz READCNT,F ;are 32 readings complete? goto ChkIRlo goto MemRead ChkTime movlw MSEC8 subwf TMR0,W ;W= f- W btfsc STATUS,C ;if 255> key was pressed btfsc STATUS,Z ;if yes, jump to DecAttn goto DecAttn movf IRBYTE1,W xorlw 0x10 ;see if rem 1 key was pressed btfsc STATUS,Z ;if yes, jump to Select1 goto Select1 movf IRBYTE1,W xorlw 0x11 ;see if rem 2 key was pressed btfsc STATUS,Z ;if yes, jump to Select1 goto Select2 movf IRBYTE1,W xorlw 0x12 ;see if rem 3 key was pressed btfsc STATUS,Z ;if yes, jump to Select1 goto Select3 movf IRBYTE1,W xorlw 0x13 ;see if rem 4 key was pressed btfsc STATUS,Z ;if yes, jump to Select1 goto Select4 movf IRBYTE1,W xorlw 0x1a ;see if rem 0 key was pressed btfsc STATUS,Z ;if yes, jump to Mute goto Mute1 goto Start Select1 clrf SOURCE ;set SOURCE variable for source 1 goto S5 Select2 movlw 1 movwf SOURCE ;set SOURCE variable for source 2 goto S5 Select3 movlw 2 movwf SOURCE ;set SOURCE variable for source 3 goto S5 Select4 movlw 3 movwf SOURCE ;set SOURCE variable for source 4 goto S5 Select incf SOURCE,F ;increment source selection movlw 4 subwf SOURCE,W ;is source= 4? btfsc STATUS,Z clrf SOURCE ;if so, set source=0 S5 btfsc SOURCE,0 ;translate SOURCE bits to SEL_0 and SEL_1 goto S1 bcf PORTC,SEL0 goto S2 S1 bsf PORTC,SEL0 S2 btfsc SOURCE,1 goto S3 bcf PORTC,SEL1 goto S4 S3 bsf PORTC,SEL1 S4 incf SOURCE,W ;inc source value and load into W call ToHex movwf DIGIT3 movlw b'00000100' ;display "in" prior to source# movwf DIGIT1 movlw b'01010100' movwf DIGIT2 call Delay goto Start DecAttn movf ATTNSTEP,W ;check if attn step is lowest (0dB) andlw 0xff btfsc STATUS,Z ;lowest attn step, do nothing goto Dec1 decf ATTNSTEP,F call Attn ;update LM1973 step value Dec1 movf ATTNSTEP,W bsf STATUS,PA0 ;get ready to call from page 1 call DispAttn ;grab display value for present attn step bcf STATUS,PA0 ;back to page 0 movwf TMP swapf TMP,W ;get ready to display attn step andlw 0x0f ;drop upper bits of attn step call ToHex ;grab DIGIT2 value movwf DIGIT2 movf TMP,W andlw 0x0f ;drop upper bits call ToHex ;grab DIGIT3 value movwf DIGIT3 movlw b'01000000' ;display "-" sign movwf DIGIT1 call Delay goto Start IncAttn movlw 0x1e subwf ATTNSTEP,W ;check if attn step is lowest (-60dB) btfsc STATUS,Z ;lowest attn step, do nothing goto Inc1 incf ATTNSTEP,F call Attn ;update LM1973 step value Inc1 movf ATTNSTEP,W bsf STATUS,PA0 ;get ready to call from page 1 call DispAttn ;grab display value for present attn step bcf STATUS,PA0 ;back to page 0 movwf TMP swapf TMP,W ;get ready to display attn step andlw 0x0f ;drop upper bits of attn step call ToHex ;grab DIGIT2 value movwf DIGIT2 movf TMP,W andlw 0x0f ;drop upper bits call ToHex ;grab DIGIT3 value movwf DIGIT3 movlw b'01000000' ;display "-" sign movwf DIGIT1 call Delay goto Start Mute1 call Mute ;mute both LM1973's movlw b'01000110' ;change display to "-100" movwf DIGIT1 clrw call ToHex movwf DIGIT2 movwf DIGIT3 goto Start org 0x200 ;memory location starting on Page 1 ; DispAttn subroutine ; Post: The decimal equivalent of the attenuation value is returned. DispAttn addwf PCL,F retlw 0x00 retlw 0x02 retlw 0x04 retlw 0x06 retlw 0x08 retlw 0x10 retlw 0x12 retlw 0x14 retlw 0x16 retlw 0x18 retlw 0x20 retlw 0x22 retlw 0x24 retlw 0x26 retlw 0x28 retlw 0x30 retlw 0x32 retlw 0x34 retlw 0x36 retlw 0x38 retlw 0x40 retlw 0x42 retlw 0x44 retlw 0x46 retlw 0x48 retlw 0x50 retlw 0x52 retlw 0x54 retlw 0x56 retlw 0x58 retlw 0x60 retlw 0x62 ; GetAttn subroutine ; Post: The attn step data for the relevant attn step is returned. GetAttn addwf PCL,F retlw 0x00 retlw 0x04 retlw 0x08 retlw 0x0C retlw 0x10 retlw 0x14 retlw 0x18 retlw 0x1C retlw 0x20 retlw 0x22 retlw 0x24 retlw 0x26 retlw 0x28 retlw 0x2A retlw 0x2C retlw 0x2E retlw 0x30 retlw 0x32 retlw 0x34 retlw 0x36 retlw 0x38 retlw 0x3A retlw 0x3C retlw 0x3E retlw 0x40 retlw 0x41 retlw 0x42 retlw 0x43 retlw 0x44 retlw 0x45 retlw 0x46 retlw 0x47 end