The
software was assembled using Metalink’s ASM51 assembler, which is freely
available for download.The
software was assembled using Metalink’s ASM51 assembler, which is freely
available for download.
;**************************************************************************
;PROGRAM FOR A DIGITALLY CONTROLLED AUDIO PROCESSING SYSTEM
;AUTHOR - KULAJIT SARMA, SEPTEMBER 2002
;ASSEMBLER - METALINK ASSEMBLER ASM51
;**************************************************************************
;CLOCK - 12 MHz CRYSTAL.
;AUDIO PROCESSOR - TDA7439. EEPROM - 24C02
;INPUT FROM A NEC FORMAT REMOTE OR FROM KEYPAD.
;DISPLAY - 2 DIGIT LED DISPLAY & 8-LED PORT.
;**************************************************************************
;
$MOD51 ;include predefined constants
;$NOPRINT
;
;**************************************************************************
; Variable & Constant Definitions
;**************************************************************************
;
STACKBASE EQU 034H ;stack starts at 35H
;
EEPROM_ADDR EQU 0A0H ;address of 24CXX on I2C bus
AUDIOPROC_ADDR EQU 088H ;address of TDA7439 on I2C bus
;
C_CODE1 EQU 084H ;CUSTOM CODE for Creative Remote
C_CODE2 EQU 035H ;CUSTOM CODE' for Creative Remote
;
; keypad/remote command codes
VOL_UP EQU 010H ;REMOTE- VOL +
VOL_DN EQU 014H ;REMOTE- VOL -
SEL EQU 004H ;REMOTE- MENU
SOURCE EQU 008H ;REMOTE- MOUSE
INGAIN EQU 018H ;REMOTE- ZOOM
MUT EQU 00CH ;REMOTE- MUTE
STDBY EQU 016H ;REMOTE- CANCEL
;
ZDATA EQU R1 ;data register for 24C01/02 functions
ADDR EQU R2 ;address register for 24C01/02 functions
AUDIODATA EQU R3 ;Audio parameter values for audio processor
SUBADDR EQU R4 ;Audio processor function selection byte
;
SDA BIT P3.0 ;i2c serial data
SCL BIT P3.1 ;i2c serial clock
IR_IN BIT P3.2 ;IR sensor input line, inverted output from sensor
INDICATOR BIT P3.4 ;Status indicator LED
POWER BIT P3.5 ;STANDBY relay control
DISP_LATCH BIT P3.6 ;Latch control of Display port (CD4543B)
MONITOR BIT P2.7 ;Power monitor input
;BIT Variables
; Max bit variables available is 16, as general user RAM starts from 022H
;
STOP BIT 00H ;stop bit in IR code
RX_BIT BIT 01H ;next received bit in IR stream
NEW_COM BIT 02H ;new IR command available
NEW_KEY BIT 03H ;new key input available
REPEAT BIT 04H ;Repeated Remote command (contineous key press)
STANDBY BIT 05H ;Standby status
MUTE BIT 06H ;Mute status
GAIN_ON BIT 07H ;Bit set if gain function selected
; BYTE Variables
; Max byte variables available is 18, as stack starts at 35H
;
COMMAND DATA 022H ;Received IR command
KEY DATA 023H ;Keyboard command
CHANNEL DATA 024H ;TDA7439 input channel
VOLUME DATA 025H ;TDA7439 input attenuation
BASS DATA 026H ;TDA7439 bass adj
MIDDLE DATA 027H ;TDA7439 voice adj
TREBLE DATA 028H ;TDA7439 treble adj
R_ATTN DATA 029H ;TDA7439 Right attenuation (volume)
L_ATTN DATA 02AH ;TDA7439 Left attenuation (volume)
GAIN1 DATA 02BH ;TDA7439 input gain of IN1
GAIN2 DATA 02CH ;TDA7439 input gain of IN2
GAIN3 DATA 02DH ;TDA7439 input gain of IN3
GAIN4 DATA 02EH ;TDA7439 input gain of IN4
GAIN DATA 02FH ;TDA7439 input gain of active channel
LED_STATUS DATA 030H ;currently loaded value in LED port
;LED_STATUS BITS 0-1-2-3-4-5-6-7 = BASS-MIDDLE-TREBLE-ATTN-IN1-IN2-IN3-IN4
T1_COUNT DATA 031H ;TIMER1 Counter
;
;**************************************************************************
;
;//////////////////////////////////////////////////////////////////////////
; PROGRAM STARTS HERE
;//////////////////////////////////////////////////////////////////////////
; RESET VECTOR
;
ORG 00H ;locate routine at 00H
RESET:
JMP START ;jump to START
;
;**************************************************************************
;
; INTERRUPTS ( place interrupt routines at appropriate memory locations )
ORG 03H ;external interrupt 0, used by IR Sensor
JMP INTR_EX0
ORG 0BH ;timer 0 interrupt
RETI
ORG 13H ;External interrupt 1
RETI
ORG 1BH ;timer 1 interrupt
JMP INTR_T1
ORG 23H ;serial port interrupt
RETI
ORG 25H ;locate beginning of rest of program
;
;**************************************************************************
;
;//////////////////////////////////////////////////////////////////////////
; DELAY ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;**************************************************************************
; Delay routine to introduce 6 microSec Delay with 12MHz crystal
;**************************************************************************
BITDLY: ;2cyl (CALL)
NOP ;1 Cyl
NOP ;1 Cyl
RET ;2 Cyl
;
;**************************************************************************
; Delay routine in miliSecond. (Approximate)
; Entry: R6 = (Delay in mS -0.004)/0.501 OR R6 = Delay in mS * 2
; assuming 12MHz clock, 1 Cyl=1 microSec
; delay in inner loop= R7*2 microSec
; delay in outer loop= R6*(3+R7*2) microSec
; delay in call & ret= 4 microSec
; Total delay = R6*(3+R7*2)+4 microSec
; R7=249(F9H)=>Min delay=0.507 miliSec, Max delay = 127.759 mS
; Destroys R6, R7
;*************************************************************************
DELAYMS: ;2-Cyl
x95: MOV R7,#0F9H ;1-Cyl
DJNZ R7,$ ;2-Cyl
DJNZ R6,x95 ;2-Cyl
RET ;2-Cyl
;
;*************************************************************************
; Delay routine in Seconds. (Approximate)
; Entry: R5 = Delay in Sec * 10
; Destroys R5, R6, R7
;*************************************************************************
DELAYSEC:
x96: MOV R6,#200
ACALL DELAYMS
DJNZ R5,x96
RET
;*************************************************************************
;
;//////////////////////////////////////////////////////////////////////////
; END OF DELAY ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; IR DECODING ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;**************************************************************************
; Receives one bit from IR_IN. The received bit is returned in RX_BIT,
; or STOP is set if it is a stop bit. IR_IN should be LOW while calling
; this function. Uses TIMER 0 already set in Mode1, TR0=1 & GATE0=1. EA=0
; DESTROYS PSW->CARRY AND R0
;**************************************************************************
RECEIVE_BIT:
MOV TH0,#0F4H ;TIMER0 RELOAD VALUE, MAX COUNT=65535-62464(F400H)=3071
;BIT WILL BE RECOGNISED AS STOP BIT IF TIMER0 OVERFLOWS
;SINCE TL0 IS IGNORED, OVERFLOW WILL BE ANYWHERE BETWEEN 2816 & 3071
CLR TF0
CLR C
CLR STOP
CLR RX_BIT ;ASSUME BIT=0
JNB IR_IN,$ ;LOOP UNTIL IR_IN GOES HIGH, TIMER0 STARTS AFTER THIS
x60: JB TF0,x62 ;STOP BIT IF TIMER OVERFLOWS
JB IR_IN,x60 ;LOOP TILL TIMER0 IS RUNNING
;TIMER0 STOPS HERE, CHECK PULSE LENGTH
MOV R0,TH0
CJNE R0,#0F8H,x61 ;BIT =0 IF COUNT LESS THAN 1024
x61: JC x63 ;RX_BIT=0
SETB RX_BIT ;RX_BIT=1
AJMP x63
x62: SETB STOP
x63:
RET
;
;******************************************************************************************
;External interrupt 0 handler -> DECODES A NEC FORMAT IR STREAM
;SETS NEW_COM(02H) IF A NEW COMMAND IS AVAILABLE. SHOULD BE CLEARED IF THE COMMAND IS PROCESSED
;THE COMMAND IS STORED IN THE COMMAND(021H) LOCATION IN INTERNAL RAM
;USES TIMER0
;DESTROYS R0,R2,TMOD0
;*****************************************************************************************
INTR_EX0:
CLR EX0 ;Disable Int0
PUSH ACC
PUSH PSW
;EVERY KEYCODE IS TRANSMITTED TWICE. THE FIRST TIME IS REJECTED
;
JNB TF0,IRDECODE ;SECOND & SUBSEQUENT CONTINEOUS TRANSMISSION
MOV R2,#0AAH ;DELAY 85mS TO REJECT THE FIRST TRANSMISSION
DLY85:
MOV R0,#0F9H ;1-Cyl
DJNZ R0,$ ;2-Cyl
DJNZ R2,DLY85 ;2-Cyl
AJMP x72
;
IRDECODE: ;DECODE INCOMING IR COMMAND
ORL TMOD,#01H ;SET MODE1 FOR TIMER0 (16-BIT TIMER )
ANL TMOD,#0F1H ;GATE0=0, CT=0
MOV TH0,#00H ;<-CHECK NECESSATY????????????????????????????????
MOV TL0,#00H ;<-CHECK NECESSATY????????????????????????????????
SETB TR0 ;START TIMER0
JNB IR_IN,$ ;LOOP UNTIL IR_IN GOES HIGH, END OF START PULSE
CLR TR0 ;STOP TIMER0
;
;*****check length of start pulse**********************************************************
;
MOV A,TH0
CJNE A,#020H,x64 ;MIN TIMER0 COUNT = 20OOH = 8192D i.e. 8.1ms START PULSE
AJMP x66
x64: JC x72
CJNE A,#025H,x65 ;MAX TIMER0 COUNT = 25FFH = 9727D i.e. 9.7ms START PULSE
AJMP x66
x65: JNC x72 ;START PULSE LENGTH INVALID
;
x66: ;START PULSE IDENTIFIED, CONTINUE
JB IR_IN,$ ;LOOP UNTIL IR_IN GOES LOW, SKIP 4.5mS SILENCE
;TODO->AVOID INFINITE LOOP IF ONLY A NOISE START SIGNAL RECEIVED BUT NO STOP BIT
;
ORL TMOD,#08H ;GATE0=1
SETB TR0 ;START TIMER0
ACALL RECEIVE_BIT ;RECEIVE THE INCOMING 0,1 OR STOP BIT
JB STOP,STOPBIT ;STOP BIT RECEIVED, REPEAT LAST COMMAND
MOV C,RX_BIT
RLC A
MOV R2,#07H ;NUMBER OF BITS IN A BYTE, 7 + 1 ALREADY RECEIVED
x67: ;RECEIVE CUSTOM CODE
ACALL RECEIVE_BIT ;RECEIVE THE INCOMING 0,1 OR STOP BIT
JB STOP,x72 ;STOP BIT RECEIVED, ERROR
MOV C,RX_BIT
RLC A
DJNZ R2,x67
CJNE A,#C_CODE1,x72 ;CHECK CUSTOM CODE
MOV R2,#08H ;NUMBER OF BITS IN A BYTE
x68: ;RECEIVE CUSTOM CODE'
ACALL RECEIVE_BIT ;RECEIVE THE INCOMING 0,1 OR STOP BIT
JB STOP,x72 ;STOP BIT RECEIVED, ERROR
MOV C,RX_BIT
RLC A
DJNZ R2,x68
CJNE A,#C_CODE2,x72 ;CHECK CUSTOM CODE'
MOV R2,#08H ;NUMBER OF BITS IN A BYTE
x69: ;RECEIVE COMMAND BYTE
ACALL RECEIVE_BIT ;RECEIVE THE INCOMING 0,1 OR STOP BIT
JB STOP,x72 ;STOP BIT RECEIVED, ERROR
MOV C,RX_BIT
RLC A
DJNZ R2,x69
MOV COMMAND,A ;MOVE VALUE TO COMMAND BYTE
MOV R2,#08H ;NUMBER OF BITS IN A BYTE
x70: ;RECEIVE INVERTED COMMAND BYTE
ACALL RECEIVE_BIT ;RECEIVE THE INCOMING 0,1 OR STOP BIT
JB STOP,x72 ;STOP BIT RECEIVED, ERROR
MOV C,RX_BIT
RLC A
DJNZ R2,x70
CPL A
CJNE A,COMMAND,x72 ;CHECK INVERTED COMMAND BYTE
ACALL RECEIVE_BIT ;RECEIVE STOP BIT
JNB STOP,x72 ;ERROR
AJMP x71 ;VALID COMMAND
STOPBIT:
SETB NEW_COM ;SHOULD BE CLEARED IF THE COMMAND IS PROCESSED
SETB REPEAT ;Repeated command<- contionous key press
MOV R2,#0AAH
AJMP DLY85
x71: ;NEW VALID COMMAND
SETB NEW_COM ;SHOULD BE CLEARED IF THE COMMAND IS PROCESSED
CLR REPEAT
x72: CLR TR0 ;STOP TIMER0
ANL TMOD,#0F7H ;GATE0=0
CLR A
MOV TH0,A
MOV TL0,A
CLR TF0 ;TIMER0 WILL OVERFLOW EXCEPT FOR SECOND TIME OR
SETB TR0 ;CONTINOUS TRANSMISSION
POP PSW
POP ACC
SETB EX0 ;Enable Int0
RETI ;INT0 Return
;
;//////////////////////////////////////////////////////////////////////////
; END OF IR DECODING ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; KEY INPUT PROCESSING ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;**************************************************************************
; Checks for keypress, sets NEW_KEY & code in KEY if key pressed
; No mulltiple key press, no continous key press
;**************************************************************************
CHECK_KEY:
MOV A,P2
SETB ACC.7
CJNE A,#0FFH,NE_FF_KEY
RET ;no keys pressed
NE_FF_KEY:
PUSH IE
CLR EA ;disable interrupts
PUSH B
MOV B,A
MOV R6,#064H ;50mS delay for key debounce
MOV A,P2
SETB ACC.7
CJNE A,B,END_CHECK_KEY
;key debounced, check for keys one by one, multiple key press not allowed
KEY1:
CJNE A,#0FEH,KEY2
MOV KEY,#VOL_UP
AJMP SET_NEW_KEY
KEY2:
CJNE A,#0FDH,KEY3
MOV KEY,#VOL_DN
AJMP SET_NEW_KEY
KEY3:
CJNE A,#0FBH,KEY4
MOV KEY,#SEL
AJMP SET_NEW_KEY
KEY4:
CJNE A,#0F7H,KEY5
MOV KEY,#SOURCE
AJMP SET_NEW_KEY
KEY5:
CJNE A,#0EFH,KEY6
MOV KEY,#INGAIN
AJMP SET_NEW_KEY
KEY6:
CJNE A,#0DFH,KEY7
MOV KEY,#MUT
AJMP SET_NEW_KEY
KEY7:
CJNE A,#0BFH,CONT_KEYPRESS
MOV KEY,#STDBY
SET_NEW_KEY: ;set flag as new key available
SETB NEW_KEY ;cleared by the key processing routine
CONT_KEYPRESS: ;Wait in a loop till key is released
MOV A,P2
SETB ACC.7
CJNE A,#0FFH,CONT_KEYPRESS
MOV R6,#064H ;Key must be released for at least 50mS
CALL DELAYMS
MOV A,P2
SETB ACC.7
CJNE A,#0FFH,CONT_KEYPRESS
END_CHECK_KEY:
POP B
POP IE
RET
;
;//////////////////////////////////////////////////////////////////////////
; END OF KEY INPUT PROCESSING ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; TDA7439 AUDIO PROCESSOR COMMUNICATION ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;**************************************************************************
; TDA7439 communication routine with no incremental bus.
; Called with function select byte in SUBADDR(R4) & data in AUDIODATA(R3).
; Returns CY set to indicate that the bus is not available
; or that the addressed device failed to acknowledge.
; Destroys A, R3, R4
;**************************************************************************
SET_AUDIO:
CLR C
CALL I2C_START
JC x56 ; abort if bus not available
;
MOV A,#AUDIOPROC_ADDR ; setup Device address
CALL I2C_SHOUT ; send device address
JC x55 ; abort if no acknowledge
;
MOV A,SUBADDR ; send address
CLR ACC.4 ; No Incremental Bus
CALL I2C_SHOUT
JC x55 ; abort if no acknowledge
;
MOV A,AUDIODATA ; get data
CALL I2C_SHOUT ; send data
JC x55 ; abort if no acknowledge
;
CLR C ; clear error flag
x55:
CALL I2C_STOP
x56:
RET
;
;*************************************************************************
; Initialize TDA7439.
; Send audio parameter values except R_ATTN & L_ATTN to audio processor
; with incremental bus.
; Destroys ACC, CY, B, R0
;*************************************************************************
INIT_AUDIO:
CLR C
MOV B,#05H ; byte count (6-1=5), leave out R_ATTN & L_ATTN
MOV R0,#024H ; RAM pointer
CALL I2C_START
JC INIT_AUDIO ; loop till bus available
MOV A,#AUDIOPROC_ADDR ; setup Device address
CALL I2C_SHOUT ; send device address
JC INITAUDEND ; abort if no acknowledge
;
MOV A,#00H ; send subaddress(function select)
SETB ACC.4 ; Incremental Bus
CALL I2C_SHOUT
JC INITAUDEND ; abort if no acknowledge
INCBUS:
MOV A,@R0 ; get audio parameter value
CALL I2C_SHOUT ; send data
JC INITAUDEND ; abort if no acknowledge
INC R0 ; increment RAM pointer, subaddress autoincrease
DJNZ B,INCBUS ; setup next audio parameter
CLR C ; clear error flag
INITAUDEND:
CALL I2C_STOP
RET
;
;//////////////////////////////////////////////////////////////////////////
; END OF TDA7439 AUDIO PROCESSOR COMMUNICATION ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; 24C01/02 COMMUNICATION ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;**************************************************************************
; 24Cxx Current Address Read function.
; Returns data in A.
; Returns CY set to indicate that the bus is not available
; or that the addressed device failed to acknowledge.
; Destroys A
;**************************************************************************
READ_CURRENT:
CALL I2C_START
JC x43 ; abort if bus not available
;
MOV A,#EEPROM_addr ; setup address
SETB ACC.0 ; specify read operation
CALL I2C_SHOUT ; send device address
JC x42 ; abort if no acknowledge
;
CALL I2C_SHIN ; receive data byte
CALL I2C_NAK ; do not acknowledge byte
CLR C ; clear error flag
x42:
CALL I2C_STOP
x43:
RET
;
;**************************************************************************
; 24C01/02 Random Read function.
; Called with byte address in ADDR
; Returns data in A.
; Returns CY set to indicate that the bus is not available
; or that the addressed device failed to acknowledge.
; Destroys A, R1
;**************************************************************************
READ_RANDOM:
CALL I2C_START
JC x45 ; abort if bus not available
;
MOV A,#EEPROM_addr ; setup address
CLR ACC.0 ; dummy write command to set internal address
CALL I2C_SHOUT ; send device address
JC x44 ; abort if no acknowledge
;
MOV A,ADDR ; send address
CALL I2C_SHOUT
JC x44 ; abort if no acknowledge
;
CALL READ_CURRENT ; Call Current Address Read function.
AJMP x45 ; exit
x44:
CALL I2C_STOP
x45:
RET
;
;*************************************************************************
; 24C01/02 Sequential Read function. Initializes audio parameters in RAM
; Read 11 bytes (01H to 0CH) sequentially from 24Cxx and move to
; internal RAM locations 024H to 02FH. Assumes address counter already
; set to 01H on entry (should be precedeed by read at 00H)
; destroys ACC, B, CY, R0
;*************************************************************************
INIT_MEM:
CALL I2C_START
JC INITMERR ; abort if bus not available
;
MOV B,#0BH ; byte count (11 bytes)
MOV R0,#024H ; RAM pointer
MOV A,#EEPROM_ADDR ; setup address
SETB ACC.0 ; specify read operation
CALL I2C_SHOUT ; send device address
JC INITMERR ; abort if no acknowledge
SEQREAD:
CALL I2C_SHIN ; receive data byte
MOV @R0,A ; move byte to internal RAM
INC R0 ; increment RAM pointer
DJNZ B,CONTRX
CALL I2C_NAK ; do not acknowledge byte to end transmission
AJMP ENDRX
CONTRX:
CALL I2C_ACK ; acknowledge byte to receive more bytes
AJMP SEQREAD
ENDRX:
CLR C ; clear error flag
CALL I2C_STOP
INITMERR:
CALL BITDLY
RET
;
;**************************************************************************
; 24C01/02 Byte Write function.
; Called with byte address in register ADDR(R2) & data in register ZDATA(R1)
; Does ACK polling till device responds.
; Does not wait for write cycle to complete.
; Returns CY set to indicate that the addressed device failed to acknowledge.
; Destroys A, R1, R2
;**************************************************************************
BYTEWRITE:
CLR C
CALL BITDLY ; wait min time between Stop & Start on I2C bus
CALL I2C_START
JC BYTEWRITE ; loop until bus available
MOV A,#EEPROM_ADDR ; setup device address & write operation
CALL I2C_SHOUT ; send device address
JC NACKBWR ; loop till device acknowledges (ACK Polling)
MOV A,ADDR ; send address
CALL I2C_SHOUT
JC ENDBWR
MOV A,ZDATA
CALL I2C_SHOUT ; send data
AJMP ENDBWR
NACKBWR:
CALL I2C_STOP
CALL BITDLY ; wait some time
AJMP BYTEWRITE ;retry
ENDBWR:
CALL I2C_STOP
RET
;
;*************************************************************************
;save standby status & audio parameters to EEPROM
;Writes 12 Bytes from RAM locations 24H to 2FH & one byte for standby + mute bits
;to EEPROM addresses 00H to 0CH using byte write with ack polling.
;Returns CY set to indicate error.
;Destroys ACC, CY, B, R0, R1, R2
;*************************************************************************
SAVE_STATE:
mov l_attn,r_attn ;REMOVE WHEN BALANCE ADJUSTEMENT IS ADDED???????????
CLR A
MOV C,MUTE
RLC A ; move standby bit into ACC.0
MOV C,STANDBY
RLC A ; move standby bit into ACC.0, MUTE to ACC.1
MOV ZDATA,A ; load data byte
MOV ADDR,#00H ; load address
CALL BYTEWRITE ; write byte
JC END_SAVE_STATE
MOV B,#0BH ; BYTE COUNT
MOV R0,#024H ; RAM Pointer
BWRLOOP:
INC ADDR ; increment address
MOV A,@R0 ; load data
MOV ZDATA,A ; load data
CALL BYTEWRITE ; write byte
JC END_SAVE_STATE
INC R0 ; increment RAM pointer
DJNZ B,BWRLOOP ; decrement byte counter & loop
END_SAVE_STATE:
RET ;END SAVE_STATE
;
;//////////////////////////////////////////////////////////////////////////
; END OF 24C01/02 COMMUNICATION FUNCTIONS
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; I2C BUS FUNCTIONS
;//////////////////////////////////////////////////////////////////////////
;
;**************************************************************************
; Send START on i2c bus, defined as high-to-low SDA with SCL high.
; Return with SCL, SDA low.
; Returns CY set if bus is not available.
;**************************************************************************
I2C_START:
SETB SDA
SETB SCL
;
; Verify bus available.
JNB SDA, x46 ; jump if not high
JNB SCL, x46 ; jump if not high
;
NOP ; enforce setup delay and cycle delay
CLR SDA
CALL BITDLY ; enforce hold delay
CLR SCL
CLR C ; clear error flag
AJMP x47
x46:
SETB C ; set error flag
x47:
RET
;
;**************************************************************************
; Send STOP, defined as low-to-high SDA with SCL high.
; SCL expected low on entry. Return with SCL, SDA high.
;**************************************************************************
I2C_STOP:
CLR SDA
NOP ; enforce SCL low and data setup
NOP
SETB SCL
CALL BITDLY ; enforce setup delay
SETB SDA
RET
;
;**************************************************************************
; Shift out a byte to the AT24Cxx, most significant bit first.
; SCL, SDA expected low on entry. Return with SCL low.
; Called with data to send in A.
; Returns CY set to indicate failure by slave to acknowledge.
; Destroys A.
;**************************************************************************
I2C_SHOUT:
PUSH B
MOV B,#08H ; bit counter
x48:
RLC A ; move bit into CY
MOV SDA,C ; output bit
NOP ; enforce SCL low and data setup
SETB SCL ; raise clock
CALL BITDLY ; enforce SCL high
CLR SCL ; drop clock
DJNZ B,x48 ; next bit
;
SETB SDA ; release SDA for ACK
NOP ; enforce SCL low and tAA
NOP
SETB SCL ; raise ACK clock
CALL BITDLY ; enforce SCL high
MOV C,SDA ; get ACK bit
CLR SCL ; drop ACK clock
;
POP B
RET
;
;**************************************************************************
; Shift in a byte from the AT24Cxx, most significant bit first.
; SCL expected low on entry. Return with SCL low.
; Returns received data byte in A.
;**************************************************************************
I2C_SHIN:
SETB SDA ; make SDA an input
;
PUSH B
MOV B,#08H ; bit count
x49:
CALL BITDLY ; enforce SCL low and data setup
SETB SCL ; raise clock
CALL BITDLY ; enforce SCL high
MOV C,SDA ; input bit
RLC A ; move bit into byte
CLR SCL ; drop clock
DJNZ B,x49 ; next bit
;
POP B
RET
;
;**************************************************************************
; Clock out an acknowledge bit (low).
; SCL expected low on entry. Return with SCL, SDA low.
;**************************************************************************
I2C_ACK:
CLR SDA ; ACK bit
NOP ; enforce SCL low and data setup
NOP
SETB SCL ;raise clock
CALL BITDLY ; enforce SCL high
CLR SCL ; drop clock
RET
;
;**************************************************************************
; Clock out a negative acknowledge bit (high).
; SCL expected low on entry. Return with SCL low, SDA high.
;**************************************************************************
I2C_NAK:
SETB SDA ; NAK bit
NOP ; enforce SCL low and data setup
NOP
SETB SCL ; raise clock
CALL BITDLY ; enforce SCL high
CLR SCL ; drop clock
RET
;
;//////////////////////////////////////////////////////////////////////////
; END OF I2C BUS ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; DISPLAY ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;*************************************************************************
;loads LED_STATUS byte in LED port.
;*************************************************************************
LOAD_LED:
PUSH ACC
MOV A,LED_STATUS
CPL A
MOV P0,A
POP ACC
RET
;
;**************************************************************************
;INCREMENT FUNCTION DISPLAY. low nibble of LED_STATUS stores function display
;DESTROYS ACC
;**************************************************************************
;**************************************************************************
INC_SELD:
MOV A,LED_STATUS
ANL A,#0FH ;Clear high nibble (source display)
JNZ NOTVOL
MOV B,BASS
CALL DISP_AUD
MOV A,#01H ;BASS LED on
AJMP LDFUN
NOTVOL:
JNB ACC.0,NOTBASS
MOV B,MIDDLE
CALL DISP_AUD
MOV A,#02H ;MIDDLE LED on
AJMP LDFUN
NOTBASS:
JNB ACC.1,NOTMIDDLE
MOV B,TREBLE
CALL DISP_AUD
MOV A,#04H ;TREBLE LED on
AJMP LDFUN
NOTMIDDLE:
JNB ACC.2,NOTTREBLE
CALL DISP_ATT
MOV A,#08H ;ATTENUATION LED on
AJMP LDFUN
NOTTREBLE:
JNB ACC.3,NOTATTN
CALL DISP_VOL
MOV A,#00H ;All LEDs off(Volume)
AJMP LDFUN
LDFUN:
ANL LED_STATUS,#0F0H ;clear low nibble
ORL LED_STATUS,A ;save function selection display
ACALL LOAD_LED
NOTATTN:
RET
;
;**************************************************************************
;LOAD SOURCE DISPLAY. high nibble of LED_STATUS stores source display
;Also updates GAIN byte.
;DESTROYS A,B,CY
;**************************************************************************
LOAD_SRCD:
MOV A,CHANNEL
CJNE A,#00H,SRC3
MOV B,#080H ;IN4
MOV GAIN,GAIN4
AJMP LDSRC
SRC3: CJNE A,#01H,SRC2
MOV B,#040H ;IN3
MOV GAIN,GAIN3
AJMP LDSRC
SRC2: CJNE A,#02H,SRC1
MOV B,#020H ;IN2
MOV GAIN,GAIN2
AJMP LDSRC
SRC1: MOV B,#010H ;IN1
MOV GAIN,GAIN1
LDSRC:
MOV LED_STATUS,B ;function select = volume & save status to RAM
ACALL LOAD_LED
RET
;
;**************************************************************************
; BINARY TO BCD CONVERSION ROUTINE
;SEE P313 OF R. S. GAONKAR'S 8085 BOOK FOR ACTUAL LOGIC
;ACCEPTS A BINARY NUMBER BETWEEN 0-99D(63H) IN ACC & CONVERTS TO BCD
;IF ACC>63H(99D) OUTPUTS 00H
;DESTROYS A,CY & B
;**************************************************************************
HEXBCD:
MOV B,#00H
CJNE A,#64H,N100 ;NOT EQUAL 100D
N100: JC LT99
AJMP GT99 ;greater than 99D
LT99: ;less than 99D, continue
SUB10: ;repeatedly subtaract 10D from Acc till reminder less than 10D
CLR C
CJNE A,#0AH,N10 ;NOT EQUAL 10D
N10: JC LT10 ;reminder less than 10D
SUBB A,#0AH
INC B ;loop counter
AJMP SUB10
GT99: CLR A ;output 00 only if greater than 99D
LT10: SWAP A ;A contains low BCD nibble & B contains high BCD nibble
ORL A,B
SWAP A
RET
;
;*************************************************************************
;loads a byte FROM P1 in DISPLAY port.
;*************************************************************************
LOAD_DISP:
SETB DISP_LATCH ;latch the byte in Display latch
NOP
CLR DISP_LATCH
RET
;
;**************************************************************************
;Displays input gain settings(0 - 15) on LED Display
;destroys A,CY,P1
;**************************************************************************
DISP_GAIN:
MOV A,GAIN
ACALL HEXBCD ;convert to BCD
MOV P1,A
ANL A,#0F0H ;clear low nibble
JNZ LDGAIN
ORL P1,#0F0H ;set illegal BCD to supress leading zero
LDGAIN:
ACALL LOAD_DISP
RET
;
;**************************************************************************
;Displays volume (1-80)settings on LED Display
;Entry: B=setting value & ACC=max value for the setting(4F/2F)
;destroys A,CY,P1,B
;**************************************************************************
DISP_VOL:
MOV A,#050H
MOV B,R_ATTN
CLR C
SUBB A,B
ACALL HEXBCD
MOV P1,A
ANL A,#0F0H ;clear low nibble
JNZ LDVOL
ORL P1,#0F0H ;set illegal BCD to supress leading zero
LDVOL:
ACALL LOAD_DISP
RET
;
;**************************************************************************
;Displays attenuation (0-47)settings on LED Display
;destroys A,P1
;**************************************************************************
DISP_ATT:
MOV A,VOLUME
ACALL HEXBCD
MOV P1,A
ANL A,#0F0H ;clear low nibble
JNZ LDATT
ORL P1,#0F0H ;set illegal BCD to supress leading zero
LDATT:
ACALL LOAD_DISP
RET
;
;**************************************************************************
;Displays bass/middle/treble settings(07-00-0-7) on LED Display.
;called with bass/middle/treble settings in B register
;destroys A,P1,CY,B
;**************************************************************************
DISP_AUD:
JB B.3,GT8
MOV A,#07H ;if settings less than 8H, subtract from 07H
CLR C
SUBB A,B
ACALL HEXBCD ;do not supress leading zero => CUT
AJMP LDDSPL
GT8: ;if settings greater than 8H, subtract from 0FH
MOV A,#0FH
CLR C
SUBB A,B
ACALL HEXBCD
ORL A,#0F0H ;set illegal BCD to supress leading zero=>BOOST
LDDSPL:
MOV P1,A
ACALL LOAD_DISP
RET
;
;//////////////////////////////////////////////////////////////////////////
; END OF DISPLAY ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; COMMAND & KEY DECODING ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;*************************************************************************
; Bass_Middle_Treble Up, used by DO_VOL_UP routine
;*************************************************************************
B_M_T_UP:
CJNE A,#07H,NE7_BMTUP
MOV A,#0FH
RET
NE7_BMTUP:
JNC GT7_BMTUP
INC A
RET
GT7_BMTUP:
CJNE A,#08H,NE8_BMTUP
RET ;Setting already maximum
NE8_BMTUP:
DEC A
RET
;
;*************************************************************************
; Bass_Middle_Treble Down, used by DO_VOL_DN routine
;*************************************************************************
B_M_T_DN:
JNZ NE0_BMTDN
RET ;Already minimum, do nothing
NE0_BMTDN:
JB ACC.3,GT7_BMTDN
DEC A ;Decrement if less than 7
RET
GT7_BMTDN:
CJNE A,#0FH,LT15_BMTDN
MOV A,#07H
RET
LT15_BMTDN:
INC A ;Increment if less than 15
RET
;
;*************************************************************************
; Process VOL_UP command
;*************************************************************************
DO_VOL_UP:
JNB GAIN_ON,FUN_UP
CALL DO_GAIN_UP
JMP DONE_VUP
FUN_UP:
MOV A,LED_STATUS
ANL A,#0FH ;CLEAR HIGH NIBBLE (LOW NIBBLE = FUNCTION DISPLAY)
CHECK_VOL_UP:
JNZ CHECK_BAS_UP ; Increase VOL IF ACC=0
MOV A,R_ATTN ;PROCESS RIGHT CHANNEL
JZ DONE_VUP ;Attenuation already 0dB, do nothing
DEC A ;Volume UP
MOV AUDIODATA,A
MOV SUBADDR,#06H
CALL SET_AUDIO
JC DONE_VUP
MOV R_ATTN,AUDIODATA
;
MOV A,L_ATTN ;PROCESS LEFT CHANNEL
JZ DONE_VUP ;Attenuation already 0dB, do nothing
DEC A ;Volume UP
MOV AUDIODATA,A
MOV SUBADDR,#07H
CALL SET_AUDIO
JC DONE_VUP
MOV L_ATTN,AUDIODATA
;
CALL DISP_VOL ;UPDATE LED DISPLAY
AJMP DONE_VUP
CHECK_BAS_UP: ; Increment BASS
CJNE A,#01H,CHECK_MID_UP
MOV A,BASS
CALL B_M_T_UP
MOV B,A ;used by DISP_AUD
MOV SUBADDR,#03H
MOV AUDIODATA,A
CALL SET_AUDIO ;Change audio settings
JC DONE_VUP
MOV BASS,AUDIODATA ;Update RAM
CALL DISP_AUD ;B-reg already contains display settings
AJMP DONE_VUP
CHECK_MID_UP: ; Increment MIDDLE
CJNE A,#02H,CHECK_TRE_UP
MOV A,MIDDLE
CALL B_M_T_UP
MOV B,A ;used by DISP_AUD
MOV SUBADDR,#04H
MOV AUDIODATA,A
CALL SET_AUDIO ;Change audio settings
JC DONE_VUP
MOV MIDDLE,AUDIODATA ;Update RAM
CALL DISP_AUD ;B-reg already contains display settings
AJMP DONE_VUP
CHECK_TRE_UP: ; Increment TREBLE
CJNE A,#04H,CHECK_ATT_UP
MOV A,TREBLE
CALL B_M_T_UP
MOV B,A ;used by DISP_AUD
MOV SUBADDR,#05H
MOV AUDIODATA,A
CALL SET_AUDIO ;Change audio settings
JC DONE_VUP
MOV TREBLE,AUDIODATA ;Update RAM
CALL DISP_AUD ;B-reg already contains display settings
AJMP DONE_VUP
CHECK_ATT_UP:
CJNE A,#08H,DONE_VUP
MOV A,VOLUME
CJNE A,#02FH,NE2FVOL
AJMP DONE_VUP ;Already max attenuation
NE2FVOL:
JNC DONE_VUP ;Already max attenuation/Mute
INC A
MOV AUDIODATA,A
MOV SUBADDR,#02H
CALL SET_AUDIO
JC DONE_VUP
; ;UPDATE DISPLAY
MOV VOLUME,AUDIODATA
CALL DISP_ATT
DONE_VUP:
RET
;
;*************************************************************************
; Process VOL_DN command
;*************************************************************************
DO_VOL_DN:
JNB GAIN_ON,FUN_DN
CALL DO_GAIN_DN
JMP DONE_VUP
FUN_DN:
MOV A,LED_STATUS
ANL A,#0FH ;CLEAR HIGH NIBBLE (LOW NIBBLE = FUNCTION DISPLAY)
CHECK_VOL_DN:
JNZ CHECK_BAS_DN ; Decrease VOL IF ACC=0
MOV A,R_ATTN ;PROCESS RIGHT CHANNEL
CJNE A,#04FH,RV_DN
AJMP DONE_VDN ;Attenuation already -79dB, do nothing
RV_DN:
INC A ;Volume DOWN
MOV AUDIODATA,A
MOV SUBADDR,#06H
CALL SET_AUDIO
JC DONE_VDN
MOV R_ATTN,AUDIODATA ;Save settings to RAM
;
MOV A,L_ATTN ;PROCESS LEFT CHANNEL
CJNE A,#04FH,LV_DN
AJMP DONE_VDN ;Attenuation already -79dB, do nothing
LV_DN:
INC A ;Volume DOWN
MOV AUDIODATA,A
MOV SUBADDR,#07H
CALL SET_AUDIO
JC DONE_VDN
MOV L_ATTN,AUDIODATA ;Save settings to RAM
; ;UPDATE LED DISPLAY
CALL DISP_VOL
AJMP DONE_VDN
CHECK_BAS_DN: ; Decrement BASS
CJNE A,#01H,CHECK_MID_DN
MOV A,BASS
CALL B_M_T_DN
MOV B,A ;used by DISP_AUD
MOV SUBADDR,#03H
MOV AUDIODATA,A
CALL SET_AUDIO ;Change audio settings
JC DONE_VDN
MOV BASS,AUDIODATA ;Update RAM
CALL DISP_AUD ;B-reg already contains display settings
AJMP DONE_VDN
CHECK_MID_DN: ; Decrement MIDDLE
CJNE A,#02H,CHECK_TRE_DN
MOV A,MIDDLE
CALL B_M_T_DN
MOV B,A ;used by DISP_AUD
MOV SUBADDR,#04H
MOV AUDIODATA,A
CALL SET_AUDIO ;Change audio settings
JC DONE_VDN
MOV MIDDLE,AUDIODATA ;Update RAM
CALL DISP_AUD ;B-reg already contains display settings
AJMP DONE_VDN
CHECK_TRE_DN: ; Decrement TREBLE
CJNE A,#04H,CHECK_ATT_DN
MOV A,TREBLE
CALL B_M_T_DN
MOV B,A ;used by DISP_AUD
MOV SUBADDR,#05H
MOV AUDIODATA,A
CALL SET_AUDIO ;Change audio settings
JC DONE_VDN
MOV TREBLE,AUDIODATA ;Update RAM
CALL DISP_AUD ;B-reg already contains display settings
AJMP DONE_VDN
CHECK_ATT_DN:
CJNE A,#08H,DONE_VDN
MOV A,VOLUME
JZ DONE_VDN ;Already minimum Attenuation
DEC A
MOV AUDIODATA,A
MOV SUBADDR,#02H
CALL SET_AUDIO
JC DONE_VDN
; ;UPDATE DISPLAY
MOV VOLUME,AUDIODATA
CALL DISP_ATT
DONE_VDN:
RET
;
;*************************************************************************
; Increment Source
;Destroys A,CY
;*************************************************************************
INC_SOURCE:
MOV A,CHANNEL
INC A
JNB ACC.2,ST_SRC
CLR A
ST_SRC: ;Store source
MOV SUBADDR,#00H ;R4=TDA7439 FUNCTION SELECTION BYTE
MOV AUDIODATA,A ;R3=INPUT CHANNEL
CALL SET_AUDIO ;TDA7439 change channel
JC SRC_ERR
MOV CHANNEL,AUDIODATA ;STORE IN RAM
CALL LOAD_SRCD ;update display & GAIN byte
MOV SUBADDR,#01H ;R4=TDA7439 FUNCTION SELECTION BYTE
MOV AUDIODATA,GAIN ;R3=INPUT GAIN
CALL SET_AUDIO ;TDA7439 change gain settings
SRC_ERR:
RET
;
;*************************************************************************
; PROCESS GAIN KEY (TOGGLE)
;*************************************************************************
DO_GAIN:
JB GAIN_ON,OFF_GAIN
SETB GAIN_ON
ANL LED_STATUS,#0F0H
CALL LOAD_LED
CALL DISP_GAIN
RET
OFF_GAIN:
CLR GAIN_ON
CALL DISP_VOL
CALL LOAD_LED
RET
;
;*************************************************************************
; PROCESS GAIN UP
;*************************************************************************
DO_GAIN_UP:
MOV A,GAIN
CJNE A,#0FH,GAIN_INC
RET ;Already maximum
GAIN_INC:
INC A
MOV AUDIODATA,A
MOV SUBADDR,#01H
CALL SET_AUDIO
JC END_GAIN_UP
MOV GAIN,AUDIODATA
CALL UPDATE_GAIN
CALL DISP_GAIN
END_GAIN_UP:
RET
;
;*************************************************************************
; PROCESS GAIN DN
;*************************************************************************
DO_GAIN_DN:
MOV A,GAIN
JZ END_GAIN_DN ;Already minimum
DEC A
MOV AUDIODATA,A
MOV SUBADDR,#01H
CALL SET_AUDIO
JC END_GAIN_DN
MOV GAIN,AUDIODATA
CALL UPDATE_GAIN
CALL DISP_GAIN
END_GAIN_DN:
RET
;
;*************************************************************************
; MOVE GAIN TO GAIN1/GAIN2/GAIN3/GAIN4 depending on active channel
;*************************************************************************
UPDATE_GAIN:
MOV A,LED_STATUS
ANL A,#0F0H
CJNE A,#010H,CH2
MOV GAIN1,GAIN
RET
CH2: CJNE A,#020H,CH3
MOV GAIN2,GAIN
RET
CH3: CJNE A,#040H,CH4
MOV GAIN3,GAIN
RET
CH4: MOV GAIN4,GAIN
RET
;
;*************************************************************************
; TOGGLE STANDBY STATUS
;*************************************************************************
TOGGLE_STDBY:
JB STANDBY,STANDBY_OFF
CALL SET_MUTE_ON
SETB STANDBY
CALL SAVE_STATE
MOV R5,#05H ;0.5 Sec Delay
CALL DELAYSEC
MOV P0,#0FFH ;Turn off LEDs
SETB POWER ;Active low
CLR INDICATOR ;Turn on Command Indicator LED
RET
STANDBY_OFF:
CLR STANDBY
CLR POWER
CALL LOAD_LED
SETB INDICATOR ;Turn off Command Indicator LED
JNB MUTE,MUTE_OFF
MOV P1,#00H
CALL LOAD_DISP
RET
MUTE_OFF:
MOV R5,#0AH ;1 Sec Delay
CALL DELAYSEC
CALL SET_MUTE_OFF
RET
;
;*************************************************************************
; TOGGLE MUTE STATUS
;*************************************************************************
DO_MUTE:
JB MUTE,DO_MUTE_OFF ;TURN OFF MUTE
CALL SET_MUTE_ON
JC END_MUTE
SETB MUTE
MOV P1,#00H
CALL LOAD_DISP
RET
DO_MUTE_OFF:
CALL SET_MUTE_OFF
JC END_MUTE
CLR MUTE
CALL DISP_VOL
END_MUTE:
RET
;
;*************************************************************************
SET_MUTE_ON:
MOV AUDIODATA,#078H ;MUTE
MOV SUBADDR,#06H ;RIGHT CHANNEL
CALL SET_AUDIO
JC END_MUTE_ON
MOV SUBADDR,#07H ;LEFT CHANNEL
CALL SET_AUDIO
END_MUTE_ON:
RET
;
;*************************************************************************
SET_MUTE_OFF:
MOV AUDIODATA,R_ATTN ;RIGHT CHANNEL VOLUME
MOV SUBADDR,#06H ;RIGHT CHANNEL
CALL SET_AUDIO
JC END_MUTE_OFF
MOV AUDIODATA,L_ATTN ;LEFT CHANNEL VOLUME
MOV SUBADDR,#07H ;LEFT CHANNEL
CALL SET_AUDIO
JC END_MUTE_OFF
MOV AUDIODATA,VOLUME ;ATTNEUATION
MOV SUBADDR,#02H
CALL SET_AUDIO
END_MUTE_OFF:
RET
;
;*************************************************************************
; IMPLEMENTS REMOTE COMMANDS
;*************************************************************************
DO_COM:
MOV R0,COMMAND
CALL DO_COMMAND
CLR NEW_COM
RET
;
;*************************************************************************
; IMPLEMENTS KEYPAD COMMANDS
;*************************************************************************
DO_KEY:
MOV R0,KEY
CALL DO_COMMAND
CLR NEW_KEY
RET
;
;*************************************************************************
; IMPLEMENTS KEYPAD/REMOTE COMMANDS
;*************************************************************************
DO_COMMAND:
CHECK_STANDBY: ;check if STANDBY pressed
CJNE R0,#STDBY,CHECK_V_UP
JB REPEAT,END_COMMAND ;No contineous-key-press
CALL OFF_GAIN
CALL TOGGLE_STDBY
AJMP END_COMMAND
CHECK_V_UP: ;check if VOL_UP pressed
JB STANDBY,END_COMMAND ;If in standby do nothing
CJNE R0,#VOL_UP,CHECK_V_DN
CALL DO_VOL_UP
AJMP END_COMMAND
CHECK_V_DN: ;check if VOL_DN pressed
CJNE R0,#VOL_DN,CHECK_SEL
CALL DO_VOL_DN
AJMP END_COMMAND
CHECK_SEL: ;check if SEL pressed
CJNE R0,#SEL,CHECK_SOURCE
JB REPEAT,END_COMMAND
CALL OFF_GAIN
CALL INC_SELD ;Increment function selection
AJMP END_COMMAND
CHECK_SOURCE: ;check if SOURCE pressed
CJNE R0,#SOURCE,CHECK_GAIN
JB REPEAT,END_COMMAND
CALL OFF_GAIN
CALL INC_SOURCE
AJMP END_COMMAND
CHECK_GAIN: ;check if GAIN pressed
CJNE R0,#INGAIN,CHECK_MUTE
JB REPEAT,END_COMMAND
CALL DO_GAIN
AJMP END_COMMAND
CHECK_MUTE: ;check if MUTE pressed
CJNE R0,#MUT,END_COMMAND
JB REPEAT,END_COMMAND
CALL OFF_GAIN
CALL DO_MUTE
END_COMMAND:
CALL INIT_TIMER1
RET
;
;*************************************************************************
INIT_TIMER1:
CLR TR1
MOV T1_COUNT,#01H
MOV TH1,#00H
MOV TL1,#00H
SETB TR1
CLR INDICATOR ;Turn on INDICATOR LED
RET
;
;//////////////////////////////////////////////////////////////////////////
; END OF COMMAND & KEY DECODING ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; TIMER1 INTERRUPT HANDLER ROUTINE
; Volume function (default) selected if T1 is running for 4Sec+.
; Keeps source display flashing if GAIN_ON is set.
;//////////////////////////////////////////////////////////////////////////
INTR_T1:
PUSH IE
CLR EA ;disable interrupts
CLR TR1 ;stop timer temporarily
PUSH ACC
PUSH PSW
MOV A,T1_COUNT
CJNE A,#066H,NE66T1
MOV T1_COUNT,#01H
ANL LED_STATUS,#0F0H ;Function select = Volume
CLR GAIN_ON
CALL DISP_VOL
CALL LOAD_LED
JNB STANDBY,END_INT_T1
MOV P0,#0FFH
AJMP END_INT_T1
NE66T1:
MOV TH1,#015H ;T1 reload value =65535-60000=5535D=159FH
MOV TL1,#09FH ;T1 overflow every 60mS
INC T1_COUNT
SETB TR1
CJNE A,#01H,NE01T1
CLR INDICATOR ;Turn on Command Indicator LED
AJMP FLASH_DISP
NE01T1:
JB STANDBY,FLASH_DISP
SETB INDICATOR ;Turn off Command Indicator LED
FLASH_DISP:
JNB GAIN_ON,END_INT_T1
ANL A,#07H ;Clear A except last 3 bits
JNZ MULTIPLE_4
MOV P0,#0FFH ;Clear display if multiple of 8
AJMP END_INT_T1
MULTIPLE_4:
CLR ACC.2
JNZ END_INT_T1
CALL LOAD_LED ;load led display if multiple of 4
END_INT_T1:
POP PSW
POP ACC
POP IE
RETI
;
;//////////////////////////////////////////////////////////////////////////
; END OF TIMER1 INTERRUPT HANDLER ROUTINE
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; MAIN ENTRY ROUTINE
;//////////////////////////////////////////////////////////////////////////
;
START:
;*************************************************************************
; REGISTER INITIALIZATION
;*************************************************************************
MOV SP,#STACKBASE ;stack base address
CLR A
MOV TCON,A
MOV PSW,A
MOV IE,A ;Disable Interrupts
MOV T1_COUNT,A
MOV TMOD,#011H ;T1 & T0 IN 16-bit MODE1, GATEx=0 & CTx=0
CLR TR1
SETB TR0 ;START TIMER TO REJECT FIRST TRANSMISSION
SETB SDA ;I2C Initialize
SETB SCL
SETB POWER ;Standby on (active low)
SETB MONITOR ;Power monitor as input(active low)
CLR REPEAT
CLR NEW_COM
CLR NEW_KEY
CLR DISP_LATCH
CLR GAIN_ON
;
INIT: ;INITIALIZATION STARTS HERE
CLR C
;*************************************************************************
; STANDBY & MUTE INITIALIZATION
;*************************************************************************
CLR A
MOV ADDR,#00H ;READ STANDBY STATUS
ACALL READ_RANDOM
JC INIT ;RETRY
RRC A ;move LSB into CY bit
MOV STANDBY,C ;store standby status in RAM
RRC A
MOV MUTE,C ;store mute status in RAM
;*************************************************************************
; AUDIO PARAMETERS INITIALIZATION
;*************************************************************************
;
; Read 8 bytes (01H to 0CH) sequentially from 24Cxx and move to
; internal RAM locations 024H to 02FH
;*************************************************************************
CALL INIT_MEM
JC INIT
;
;*************************************************************************
;Validity check of memory data bytes
;*************************************************************************
VAL_CH: MOV A,CHANNEL
CJNE A,#04H,NE04V
NE04V: JC VAL_G1
MOV CHANNEL,#03H ;Select IN1
VAL_G1: MOV A,GAIN1
CJNE A,#010H,NE10G1
NE10G1: JC VAL_G2
MOV GAIN1,#00H ;GAIN1 = 0
VAL_G2: MOV A,GAIN2
CJNE A,#010H,NE10G2
NE10G2: JC VAL_G3
MOV GAIN2,#00H ;GAIN2 = 0
VAL_G3: MOV A,GAIN3
CJNE A,#010H,NE10G3
NE10G3: JC VAL_G4
MOV GAIN3,#00H ;GAIN3 = 0
VAL_G4: MOV A,GAIN4
CJNE A,#010H,NE10G4
NE10G4: JC VAL_ATT
MOV GAIN4,#00H ;GAIN4 = 0
VAL_ATT: MOV A,VOLUME
CJNE A,#030H,NE30ATT
NE30ATT: JC VAL_BAS
MOV VOLUME,#00H ;ATTN = 0
VAL_BAS: MOV A,BASS
CJNE A,#010H,NE10BAS
NE10BAS: JC VAL_MID
MOV BASS,#07H ;BASS = 0
VAL_MID: MOV A,MIDDLE
CJNE A,#010H,NE10MID
NE10MID: JC VAL_TRE
MOV MIDDLE,#07H ;VOICE = 0
VAL_TRE: MOV A,TREBLE
CJNE A,#010H,NE10TRE
NE10TRE: JC VAL_VOL
MOV TREBLE,#07H ;TRE = 0
VAL_VOL: MOV A,R_ATTN
CJNE A,#050H,NE50VOL
NE50VOL: JC VAL_LEFT
MOV R_ATTN,#04FH ;VOL = 0
;
VAL_LEFT: MOV L_ATTN,R_ATTN ;Remove if balance adj addeed
;
;**************************************************************************
;initialize LED & Display port.
;**************************************************************************
CALL LOAD_SRCD ;display input channel & function selected->volume
CALL DISP_VOL ;Display volume settings
JNB STANDBY,AUDIO_INIT
MOV P0,#0FFH ;Turn off all LEDs
CLR INDICATOR ;Turn on Command Indicator/Standby LED
JNB MUTE,AUDIO_INIT
MOV P1,#00H ;Display 00 if Mute on
CALL LOAD_DISP
;*************************************************************************
; Send audio parameter values to audio processor with incremental bus
; except R & L Volume
;*************************************************************************
AUDIO_INIT:
CALL BITDLY
CALL INIT_AUDIO
JC AUDIO_INIT
;
MOV C,STANDBY ;<- POWER SHOULD BE ACTIVATED ONLY AFTER AUDIO SET
MOV POWER,C
MOV R5,#014H
CALL DELAYSEC ;2SEC Delay
;
JB MUTE,GO_EVENTS
JB STANDBY,GO_EVENTS
CALL SET_MUTE_OFF ;Initialize volume
GO_EVENTS:
;*************************************************************************
;############### WAIT-FOR-EVENTS LOOP ################################
;waits for three events -> power off, key press & remote rx
;*************************************************************************
SETB EX0 ;External Int0 for IR Sensor
SETB ET1 ;Timer1 interrupt
SETB EA ;Enable Interrupts
;
LOOP:
JB MONITOR,POWER_OFF ;If MONITOR high, go to POWER_OFF (active low)
CALL CHECK_KEY
JB NEW_KEY,GO_KEY
JB NEW_COM,GO_COM
AJMP LOOP
GO_KEY:
CLR EX0 ; disable Int0
CALL DO_KEY ; Process Key
SETB EX0 ; Enable Int0
AJMP LOOP
GO_COM:
CLR EX0 ; disable Int0
CALL DO_COM ; Process Command
SETB EX0 ; Enable Int0
AJMP LOOP
;
;*************************************************************************
;############## END OF WAIT-FOR-EVENTS LOOP ##########################
;*************************************************************************
;
;*************************************************************************
; POWER OFF SEQUENCE
;*************************************************************************
POWER_OFF:
CLR EA ; DISABLE INTERRUPTS
JB STANDBY,CONT_OFF ; no need to save settings if already in standby
CALL SAVE_STATE ; save settings to EEPROM
MOV R5,#05H
CALL DELAYSEC ;0.5 Sec delay
JNB MONITOR,GO_EVENTS
;
;**************************************************************************
;Settings saved on EEPROM. MUTE audio & turn off standby relay
;**************************************************************************
CONT_OFF:
CALL SET_MUTE_ON
SETB POWER ;turn off relay (active low)
MOV P0,#0FFH ;turn off LEDs
JB MONITOR,$ ;loop till power goes down or comes on
JMP RESET ;reset device
;**************************************************************************
;
;######################## THE END #####################################
END
;**************************************************************************
;PROGRAM FOR A DIGITALLY CONTROLLED AUDIO PROCESSING SYSTEM
;AUTHOR - KULAJIT SARMA, SEPTEMBER 2002
;ASSEMBLER - METALINK ASSEMBLER ASM51
;**************************************************************************
;CLOCK - 12 MHz CRYSTAL.
;AUDIO PROCESSOR - TDA7439. EEPROM - 24C02
;INPUT FROM A NEC FORMAT REMOTE OR FROM KEYPAD.
;DISPLAY - 2 DIGIT LED DISPLAY & 8-LED PORT.
;**************************************************************************
;
$MOD51 ;include predefined constants
;$NOPRINT
;
;**************************************************************************
; Variable & Constant Definitions
;**************************************************************************
;
STACKBASE EQU 034H ;stack starts at 35H
;
EEPROM_ADDR EQU 0A0H ;address of 24CXX on I2C bus
AUDIOPROC_ADDR EQU 088H ;address of TDA7439 on I2C bus
;
C_CODE1 EQU 084H ;CUSTOM CODE for Creative Remote
C_CODE2 EQU 035H ;CUSTOM CODE' for Creative Remote
;
; keypad/remote command codes
VOL_UP EQU 010H ;REMOTE- VOL +
VOL_DN EQU 014H ;REMOTE- VOL -
SEL EQU 004H ;REMOTE- MENU
SOURCE EQU 008H ;REMOTE- MOUSE
INGAIN EQU 018H ;REMOTE- ZOOM
MUT EQU 00CH ;REMOTE- MUTE
STDBY EQU 016H ;REMOTE- CANCEL
;
ZDATA EQU R1 ;data register for 24C01/02 functions
ADDR EQU R2 ;address register for 24C01/02 functions
AUDIODATA EQU R3 ;Audio parameter values for audio processor
SUBADDR EQU R4 ;Audio processor function selection byte
;
SDA BIT P3.0 ;i2c serial data
SCL BIT P3.1 ;i2c serial clock
IR_IN BIT P3.2 ;IR sensor input line, inverted output from sensor
INDICATOR BIT P3.4 ;Status indicator LED
POWER BIT P3.5 ;STANDBY relay control
DISP_LATCH BIT P3.6 ;Latch control of Display port (CD4543B)
MONITOR BIT P2.7 ;Power monitor input
;BIT Variables
; Max bit variables available is 16, as general user RAM starts from 022H
;
STOP BIT 00H ;stop bit in IR code
RX_BIT BIT 01H ;next received bit in IR stream
NEW_COM BIT 02H ;new IR command available
NEW_KEY BIT 03H ;new key input available
REPEAT BIT 04H ;Repeated Remote command (contineous key press)
STANDBY BIT 05H ;Standby status
MUTE BIT 06H ;Mute status
GAIN_ON BIT 07H ;Bit set if gain function selected
; BYTE Variables
; Max byte variables available is 18, as stack starts at 35H
;
COMMAND DATA 022H ;Received IR command
KEY DATA 023H ;Keyboard command
CHANNEL DATA 024H ;TDA7439 input channel
VOLUME DATA 025H ;TDA7439 input attenuation
BASS DATA 026H ;TDA7439 bass adj
MIDDLE DATA 027H ;TDA7439 voice adj
TREBLE DATA 028H ;TDA7439 treble adj
R_ATTN DATA 029H ;TDA7439 Right attenuation (volume)
L_ATTN DATA 02AH ;TDA7439 Left attenuation (volume)
GAIN1 DATA 02BH ;TDA7439 input gain of IN1
GAIN2 DATA 02CH ;TDA7439 input gain of IN2
GAIN3 DATA 02DH ;TDA7439 input gain of IN3
GAIN4 DATA 02EH ;TDA7439 input gain of IN4
GAIN DATA 02FH ;TDA7439 input gain of active channel
LED_STATUS DATA 030H ;currently loaded value in LED port
;LED_STATUS BITS 0-1-2-3-4-5-6-7 = BASS-MIDDLE-TREBLE-ATTN-IN1-IN2-IN3-IN4
T1_COUNT DATA 031H ;TIMER1 Counter
;
;**************************************************************************
;
;//////////////////////////////////////////////////////////////////////////
; PROGRAM STARTS HERE
;//////////////////////////////////////////////////////////////////////////
; RESET VECTOR
;
ORG 00H ;locate routine at 00H
RESET:
JMP START ;jump to START
;
;**************************************************************************
;
; INTERRUPTS ( place interrupt routines at appropriate memory locations )
ORG 03H ;external interrupt 0, used by IR Sensor
JMP INTR_EX0
ORG 0BH ;timer 0 interrupt
RETI
ORG 13H ;External interrupt 1
RETI
ORG 1BH ;timer 1 interrupt
JMP INTR_T1
ORG 23H ;serial port interrupt
RETI
ORG 25H ;locate beginning of rest of program
;
;**************************************************************************
;
;//////////////////////////////////////////////////////////////////////////
; DELAY ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;**************************************************************************
; Delay routine to introduce 6 microSec Delay with 12MHz crystal
;**************************************************************************
BITDLY: ;2cyl (CALL)
NOP ;1 Cyl
NOP ;1 Cyl
RET ;2 Cyl
;
;**************************************************************************
; Delay routine in miliSecond. (Approximate)
; Entry: R6 = (Delay in mS -0.004)/0.501 OR R6 = Delay in mS * 2
; assuming 12MHz clock, 1 Cyl=1 microSec
; delay in inner loop= R7*2 microSec
; delay in outer loop= R6*(3+R7*2) microSec
; delay in call & ret= 4 microSec
; Total delay = R6*(3+R7*2)+4 microSec
; R7=249(F9H)=>Min delay=0.507 miliSec, Max delay = 127.759 mS
; Destroys R6, R7
;*************************************************************************
DELAYMS: ;2-Cyl
x95: MOV R7,#0F9H ;1-Cyl
DJNZ R7,$ ;2-Cyl
DJNZ R6,x95 ;2-Cyl
RET ;2-Cyl
;
;*************************************************************************
; Delay routine in Seconds. (Approximate)
; Entry: R5 = Delay in Sec * 10
; Destroys R5, R6, R7
;*************************************************************************
DELAYSEC:
x96: MOV R6,#200
ACALL DELAYMS
DJNZ R5,x96
RET
;*************************************************************************
;
;//////////////////////////////////////////////////////////////////////////
; END OF DELAY ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; IR DECODING ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;**************************************************************************
; Receives one bit from IR_IN. The received bit is returned in RX_BIT,
; or STOP is set if it is a stop bit. IR_IN should be LOW while calling
; this function. Uses TIMER 0 already set in Mode1, TR0=1 & GATE0=1. EA=0
; DESTROYS PSW->CARRY AND R0
;**************************************************************************
RECEIVE_BIT:
MOV TH0,#0F4H ;TIMER0 RELOAD VALUE, MAX COUNT=65535-62464(F400H)=3071
;BIT WILL BE RECOGNISED AS STOP BIT IF TIMER0 OVERFLOWS
;SINCE TL0 IS IGNORED, OVERFLOW WILL BE ANYWHERE BETWEEN 2816 & 3071
CLR TF0
CLR C
CLR STOP
CLR RX_BIT ;ASSUME BIT=0
JNB IR_IN,$ ;LOOP UNTIL IR_IN GOES HIGH, TIMER0 STARTS AFTER THIS
x60: JB TF0,x62 ;STOP BIT IF TIMER OVERFLOWS
JB IR_IN,x60 ;LOOP TILL TIMER0 IS RUNNING
;TIMER0 STOPS HERE, CHECK PULSE LENGTH
MOV R0,TH0
CJNE R0,#0F8H,x61 ;BIT =0 IF COUNT LESS THAN 1024
x61: JC x63 ;RX_BIT=0
SETB RX_BIT ;RX_BIT=1
AJMP x63
x62: SETB STOP
x63:
RET
;
;******************************************************************************************
;External interrupt 0 handler -> DECODES A NEC FORMAT IR STREAM
;SETS NEW_COM(02H) IF A NEW COMMAND IS AVAILABLE. SHOULD BE CLEARED IF THE COMMAND IS PROCESSED
;THE COMMAND IS STORED IN THE COMMAND(021H) LOCATION IN INTERNAL RAM
;USES TIMER0
;DESTROYS R0,R2,TMOD0
;*****************************************************************************************
INTR_EX0:
CLR EX0 ;Disable Int0
PUSH ACC
PUSH PSW
;EVERY KEYCODE IS TRANSMITTED TWICE. THE FIRST TIME IS REJECTED
;
JNB TF0,IRDECODE ;SECOND & SUBSEQUENT CONTINEOUS TRANSMISSION
MOV R2,#0AAH ;DELAY 85mS TO REJECT THE FIRST TRANSMISSION
DLY85:
MOV R0,#0F9H ;1-Cyl
DJNZ R0,$ ;2-Cyl
DJNZ R2,DLY85 ;2-Cyl
AJMP x72
;
IRDECODE: ;DECODE INCOMING IR COMMAND
ORL TMOD,#01H ;SET MODE1 FOR TIMER0 (16-BIT TIMER )
ANL TMOD,#0F1H ;GATE0=0, CT=0
MOV TH0,#00H ;<-CHECK NECESSATY????????????????????????????????
MOV TL0,#00H ;<-CHECK NECESSATY????????????????????????????????
SETB TR0 ;START TIMER0
JNB IR_IN,$ ;LOOP UNTIL IR_IN GOES HIGH, END OF START PULSE
CLR TR0 ;STOP TIMER0
;
;*****check length of start pulse**********************************************************
;
MOV A,TH0
CJNE A,#020H,x64 ;MIN TIMER0 COUNT = 20OOH = 8192D i.e. 8.1ms START PULSE
AJMP x66
x64: JC x72
CJNE A,#025H,x65 ;MAX TIMER0 COUNT = 25FFH = 9727D i.e. 9.7ms START PULSE
AJMP x66
x65: JNC x72 ;START PULSE LENGTH INVALID
;
x66: ;START PULSE IDENTIFIED, CONTINUE
JB IR_IN,$ ;LOOP UNTIL IR_IN GOES LOW, SKIP 4.5mS SILENCE
;TODO->AVOID INFINITE LOOP IF ONLY A NOISE START SIGNAL RECEIVED BUT NO STOP BIT
;
ORL TMOD,#08H ;GATE0=1
SETB TR0 ;START TIMER0
ACALL RECEIVE_BIT ;RECEIVE THE INCOMING 0,1 OR STOP BIT
JB STOP,STOPBIT ;STOP BIT RECEIVED, REPEAT LAST COMMAND
MOV C,RX_BIT
RLC A
MOV R2,#07H ;NUMBER OF BITS IN A BYTE, 7 + 1 ALREADY RECEIVED
x67: ;RECEIVE CUSTOM CODE
ACALL RECEIVE_BIT ;RECEIVE THE INCOMING 0,1 OR STOP BIT
JB STOP,x72 ;STOP BIT RECEIVED, ERROR
MOV C,RX_BIT
RLC A
DJNZ R2,x67
CJNE A,#C_CODE1,x72 ;CHECK CUSTOM CODE
MOV R2,#08H ;NUMBER OF BITS IN A BYTE
x68: ;RECEIVE CUSTOM CODE'
ACALL RECEIVE_BIT ;RECEIVE THE INCOMING 0,1 OR STOP BIT
JB STOP,x72 ;STOP BIT RECEIVED, ERROR
MOV C,RX_BIT
RLC A
DJNZ R2,x68
CJNE A,#C_CODE2,x72 ;CHECK CUSTOM CODE'
MOV R2,#08H ;NUMBER OF BITS IN A BYTE
x69: ;RECEIVE COMMAND BYTE
ACALL RECEIVE_BIT ;RECEIVE THE INCOMING 0,1 OR STOP BIT
JB STOP,x72 ;STOP BIT RECEIVED, ERROR
MOV C,RX_BIT
RLC A
DJNZ R2,x69
MOV COMMAND,A ;MOVE VALUE TO COMMAND BYTE
MOV R2,#08H ;NUMBER OF BITS IN A BYTE
x70: ;RECEIVE INVERTED COMMAND BYTE
ACALL RECEIVE_BIT ;RECEIVE THE INCOMING 0,1 OR STOP BIT
JB STOP,x72 ;STOP BIT RECEIVED, ERROR
MOV C,RX_BIT
RLC A
DJNZ R2,x70
CPL A
CJNE A,COMMAND,x72 ;CHECK INVERTED COMMAND BYTE
ACALL RECEIVE_BIT ;RECEIVE STOP BIT
JNB STOP,x72 ;ERROR
AJMP x71 ;VALID COMMAND
STOPBIT:
SETB NEW_COM ;SHOULD BE CLEARED IF THE COMMAND IS PROCESSED
SETB REPEAT ;Repeated command<- contionous key press
MOV R2,#0AAH
AJMP DLY85
x71: ;NEW VALID COMMAND
SETB NEW_COM ;SHOULD BE CLEARED IF THE COMMAND IS PROCESSED
CLR REPEAT
x72: CLR TR0 ;STOP TIMER0
ANL TMOD,#0F7H ;GATE0=0
CLR A
MOV TH0,A
MOV TL0,A
CLR TF0 ;TIMER0 WILL OVERFLOW EXCEPT FOR SECOND TIME OR
SETB TR0 ;CONTINOUS TRANSMISSION
POP PSW
POP ACC
SETB EX0 ;Enable Int0
RETI ;INT0 Return
;
;//////////////////////////////////////////////////////////////////////////
; END OF IR DECODING ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; KEY INPUT PROCESSING ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;**************************************************************************
; Checks for keypress, sets NEW_KEY & code in KEY if key pressed
; No mulltiple key press, no continous key press
;**************************************************************************
CHECK_KEY:
MOV A,P2
SETB ACC.7
CJNE A,#0FFH,NE_FF_KEY
RET ;no keys pressed
NE_FF_KEY:
PUSH IE
CLR EA ;disable interrupts
PUSH B
MOV B,A
MOV R6,#064H ;50mS delay for key debounce
MOV A,P2
SETB ACC.7
CJNE A,B,END_CHECK_KEY
;key debounced, check for keys one by one, multiple key press not allowed
KEY1:
CJNE A,#0FEH,KEY2
MOV KEY,#VOL_UP
AJMP SET_NEW_KEY
KEY2:
CJNE A,#0FDH,KEY3
MOV KEY,#VOL_DN
AJMP SET_NEW_KEY
KEY3:
CJNE A,#0FBH,KEY4
MOV KEY,#SEL
AJMP SET_NEW_KEY
KEY4:
CJNE A,#0F7H,KEY5
MOV KEY,#SOURCE
AJMP SET_NEW_KEY
KEY5:
CJNE A,#0EFH,KEY6
MOV KEY,#INGAIN
AJMP SET_NEW_KEY
KEY6:
CJNE A,#0DFH,KEY7
MOV KEY,#MUT
AJMP SET_NEW_KEY
KEY7:
CJNE A,#0BFH,CONT_KEYPRESS
MOV KEY,#STDBY
SET_NEW_KEY: ;set flag as new key available
SETB NEW_KEY ;cleared by the key processing routine
CONT_KEYPRESS: ;Wait in a loop till key is released
MOV A,P2
SETB ACC.7
CJNE A,#0FFH,CONT_KEYPRESS
MOV R6,#064H ;Key must be released for at least 50mS
CALL DELAYMS
MOV A,P2
SETB ACC.7
CJNE A,#0FFH,CONT_KEYPRESS
END_CHECK_KEY:
POP B
POP IE
RET
;
;//////////////////////////////////////////////////////////////////////////
; END OF KEY INPUT PROCESSING ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; TDA7439 AUDIO PROCESSOR COMMUNICATION ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;**************************************************************************
; TDA7439 communication routine with no incremental bus.
; Called with function select byte in SUBADDR(R4) & data in AUDIODATA(R3).
; Returns CY set to indicate that the bus is not available
; or that the addressed device failed to acknowledge.
; Destroys A, R3, R4
;**************************************************************************
SET_AUDIO:
CLR C
CALL I2C_START
JC x56 ; abort if bus not available
;
MOV A,#AUDIOPROC_ADDR ; setup Device address
CALL I2C_SHOUT ; send device address
JC x55 ; abort if no acknowledge
;
MOV A,SUBADDR ; send address
CLR ACC.4 ; No Incremental Bus
CALL I2C_SHOUT
JC x55 ; abort if no acknowledge
;
MOV A,AUDIODATA ; get data
CALL I2C_SHOUT ; send data
JC x55 ; abort if no acknowledge
;
CLR C ; clear error flag
x55:
CALL I2C_STOP
x56:
RET
;
;*************************************************************************
; Initialize TDA7439.
; Send audio parameter values except R_ATTN & L_ATTN to audio processor
; with incremental bus.
; Destroys ACC, CY, B, R0
;*************************************************************************
INIT_AUDIO:
CLR C
MOV B,#05H ; byte count (6-1=5), leave out R_ATTN & L_ATTN
MOV R0,#024H ; RAM pointer
CALL I2C_START
JC INIT_AUDIO ; loop till bus available
MOV A,#AUDIOPROC_ADDR ; setup Device address
CALL I2C_SHOUT ; send device address
JC INITAUDEND ; abort if no acknowledge
;
MOV A,#00H ; send subaddress(function select)
SETB ACC.4 ; Incremental Bus
CALL I2C_SHOUT
JC INITAUDEND ; abort if no acknowledge
INCBUS:
MOV A,@R0 ; get audio parameter value
CALL I2C_SHOUT ; send data
JC INITAUDEND ; abort if no acknowledge
INC R0 ; increment RAM pointer, subaddress autoincrease
DJNZ B,INCBUS ; setup next audio parameter
CLR C ; clear error flag
INITAUDEND:
CALL I2C_STOP
RET
;
;//////////////////////////////////////////////////////////////////////////
; END OF TDA7439 AUDIO PROCESSOR COMMUNICATION ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; 24C01/02 COMMUNICATION ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;**************************************************************************
; 24Cxx Current Address Read function.
; Returns data in A.
; Returns CY set to indicate that the bus is not available
; or that the addressed device failed to acknowledge.
; Destroys A
;**************************************************************************
READ_CURRENT:
CALL I2C_START
JC x43 ; abort if bus not available
;
MOV A,#EEPROM_addr ; setup address
SETB ACC.0 ; specify read operation
CALL I2C_SHOUT ; send device address
JC x42 ; abort if no acknowledge
;
CALL I2C_SHIN ; receive data byte
CALL I2C_NAK ; do not acknowledge byte
CLR C ; clear error flag
x42:
CALL I2C_STOP
x43:
RET
;
;**************************************************************************
; 24C01/02 Random Read function.
; Called with byte address in ADDR
; Returns data in A.
; Returns CY set to indicate that the bus is not available
; or that the addressed device failed to acknowledge.
; Destroys A, R1
;**************************************************************************
READ_RANDOM:
CALL I2C_START
JC x45 ; abort if bus not available
;
MOV A,#EEPROM_addr ; setup address
CLR ACC.0 ; dummy write command to set internal address
CALL I2C_SHOUT ; send device address
JC x44 ; abort if no acknowledge
;
MOV A,ADDR ; send address
CALL I2C_SHOUT
JC x44 ; abort if no acknowledge
;
CALL READ_CURRENT ; Call Current Address Read function.
AJMP x45 ; exit
x44:
CALL I2C_STOP
x45:
RET
;
;*************************************************************************
; 24C01/02 Sequential Read function. Initializes audio parameters in RAM
; Read 11 bytes (01H to 0CH) sequentially from 24Cxx and move to
; internal RAM locations 024H to 02FH. Assumes address counter already
; set to 01H on entry (should be precedeed by read at 00H)
; destroys ACC, B, CY, R0
;*************************************************************************
INIT_MEM:
CALL I2C_START
JC INITMERR ; abort if bus not available
;
MOV B,#0BH ; byte count (11 bytes)
MOV R0,#024H ; RAM pointer
MOV A,#EEPROM_ADDR ; setup address
SETB ACC.0 ; specify read operation
CALL I2C_SHOUT ; send device address
JC INITMERR ; abort if no acknowledge
SEQREAD:
CALL I2C_SHIN ; receive data byte
MOV @R0,A ; move byte to internal RAM
INC R0 ; increment RAM pointer
DJNZ B,CONTRX
CALL I2C_NAK ; do not acknowledge byte to end transmission
AJMP ENDRX
CONTRX:
CALL I2C_ACK ; acknowledge byte to receive more bytes
AJMP SEQREAD
ENDRX:
CLR C ; clear error flag
CALL I2C_STOP
INITMERR:
CALL BITDLY
RET
;
;**************************************************************************
; 24C01/02 Byte Write function.
; Called with byte address in register ADDR(R2) & data in register ZDATA(R1)
; Does ACK polling till device responds.
; Does not wait for write cycle to complete.
; Returns CY set to indicate that the addressed device failed to acknowledge.
; Destroys A, R1, R2
;**************************************************************************
BYTEWRITE:
CLR C
CALL BITDLY ; wait min time between Stop & Start on I2C bus
CALL I2C_START
JC BYTEWRITE ; loop until bus available
MOV A,#EEPROM_ADDR ; setup device address & write operation
CALL I2C_SHOUT ; send device address
JC NACKBWR ; loop till device acknowledges (ACK Polling)
MOV A,ADDR ; send address
CALL I2C_SHOUT
JC ENDBWR
MOV A,ZDATA
CALL I2C_SHOUT ; send data
AJMP ENDBWR
NACKBWR:
CALL I2C_STOP
CALL BITDLY ; wait some time
AJMP BYTEWRITE ;retry
ENDBWR:
CALL I2C_STOP
RET
;
;*************************************************************************
;save standby status & audio parameters to EEPROM
;Writes 12 Bytes from RAM locations 24H to 2FH & one byte for standby + mute bits
;to EEPROM addresses 00H to 0CH using byte write with ack polling.
;Returns CY set to indicate error.
;Destroys ACC, CY, B, R0, R1, R2
;*************************************************************************
SAVE_STATE:
mov l_attn,r_attn ;REMOVE WHEN BALANCE ADJUSTEMENT IS ADDED???????????
CLR A
MOV C,MUTE
RLC A ; move standby bit into ACC.0
MOV C,STANDBY
RLC A ; move standby bit into ACC.0, MUTE to ACC.1
MOV ZDATA,A ; load data byte
MOV ADDR,#00H ; load address
CALL BYTEWRITE ; write byte
JC END_SAVE_STATE
MOV B,#0BH ; BYTE COUNT
MOV R0,#024H ; RAM Pointer
BWRLOOP:
INC ADDR ; increment address
MOV A,@R0 ; load data
MOV ZDATA,A ; load data
CALL BYTEWRITE ; write byte
JC END_SAVE_STATE
INC R0 ; increment RAM pointer
DJNZ B,BWRLOOP ; decrement byte counter & loop
END_SAVE_STATE:
RET ;END SAVE_STATE
;
;//////////////////////////////////////////////////////////////////////////
; END OF 24C01/02 COMMUNICATION FUNCTIONS
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; I2C BUS FUNCTIONS
;//////////////////////////////////////////////////////////////////////////
;
;**************************************************************************
; Send START on i2c bus, defined as high-to-low SDA with SCL high.
; Return with SCL, SDA low.
; Returns CY set if bus is not available.
;**************************************************************************
I2C_START:
SETB SDA
SETB SCL
;
; Verify bus available.
JNB SDA, x46 ; jump if not high
JNB SCL, x46 ; jump if not high
;
NOP ; enforce setup delay and cycle delay
CLR SDA
CALL BITDLY ; enforce hold delay
CLR SCL
CLR C ; clear error flag
AJMP x47
x46:
SETB C ; set error flag
x47:
RET
;
;**************************************************************************
; Send STOP, defined as low-to-high SDA with SCL high.
; SCL expected low on entry. Return with SCL, SDA high.
;**************************************************************************
I2C_STOP:
CLR SDA
NOP ; enforce SCL low and data setup
NOP
SETB SCL
CALL BITDLY ; enforce setup delay
SETB SDA
RET
;
;**************************************************************************
; Shift out a byte to the AT24Cxx, most significant bit first.
; SCL, SDA expected low on entry. Return with SCL low.
; Called with data to send in A.
; Returns CY set to indicate failure by slave to acknowledge.
; Destroys A.
;**************************************************************************
I2C_SHOUT:
PUSH B
MOV B,#08H ; bit counter
x48:
RLC A ; move bit into CY
MOV SDA,C ; output bit
NOP ; enforce SCL low and data setup
SETB SCL ; raise clock
CALL BITDLY ; enforce SCL high
CLR SCL ; drop clock
DJNZ B,x48 ; next bit
;
SETB SDA ; release SDA for ACK
NOP ; enforce SCL low and tAA
NOP
SETB SCL ; raise ACK clock
CALL BITDLY ; enforce SCL high
MOV C,SDA ; get ACK bit
CLR SCL ; drop ACK clock
;
POP B
RET
;
;**************************************************************************
; Shift in a byte from the AT24Cxx, most significant bit first.
; SCL expected low on entry. Return with SCL low.
; Returns received data byte in A.
;**************************************************************************
I2C_SHIN:
SETB SDA ; make SDA an input
;
PUSH B
MOV B,#08H ; bit count
x49:
CALL BITDLY ; enforce SCL low and data setup
SETB SCL ; raise clock
CALL BITDLY ; enforce SCL high
MOV C,SDA ; input bit
RLC A ; move bit into byte
CLR SCL ; drop clock
DJNZ B,x49 ; next bit
;
POP B
RET
;
;**************************************************************************
; Clock out an acknowledge bit (low).
; SCL expected low on entry. Return with SCL, SDA low.
;**************************************************************************
I2C_ACK:
CLR SDA ; ACK bit
NOP ; enforce SCL low and data setup
NOP
SETB SCL ;raise clock
CALL BITDLY ; enforce SCL high
CLR SCL ; drop clock
RET
;
;**************************************************************************
; Clock out a negative acknowledge bit (high).
; SCL expected low on entry. Return with SCL low, SDA high.
;**************************************************************************
I2C_NAK:
SETB SDA ; NAK bit
NOP ; enforce SCL low and data setup
NOP
SETB SCL ; raise clock
CALL BITDLY ; enforce SCL high
CLR SCL ; drop clock
RET
;
;//////////////////////////////////////////////////////////////////////////
; END OF I2C BUS ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; DISPLAY ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;*************************************************************************
;loads LED_STATUS byte in LED port.
;*************************************************************************
LOAD_LED:
PUSH ACC
MOV A,LED_STATUS
CPL A
MOV P0,A
POP ACC
RET
;
;**************************************************************************
;INCREMENT FUNCTION DISPLAY. low nibble of LED_STATUS stores function display
;DESTROYS ACC
;**************************************************************************
;**************************************************************************
INC_SELD:
MOV A,LED_STATUS
ANL A,#0FH ;Clear high nibble (source display)
JNZ NOTVOL
MOV B,BASS
CALL DISP_AUD
MOV A,#01H ;BASS LED on
AJMP LDFUN
NOTVOL:
JNB ACC.0,NOTBASS
MOV B,MIDDLE
CALL DISP_AUD
MOV A,#02H ;MIDDLE LED on
AJMP LDFUN
NOTBASS:
JNB ACC.1,NOTMIDDLE
MOV B,TREBLE
CALL DISP_AUD
MOV A,#04H ;TREBLE LED on
AJMP LDFUN
NOTMIDDLE:
JNB ACC.2,NOTTREBLE
CALL DISP_ATT
MOV A,#08H ;ATTENUATION LED on
AJMP LDFUN
NOTTREBLE:
JNB ACC.3,NOTATTN
CALL DISP_VOL
MOV A,#00H ;All LEDs off(Volume)
AJMP LDFUN
LDFUN:
ANL LED_STATUS,#0F0H ;clear low nibble
ORL LED_STATUS,A ;save function selection display
ACALL LOAD_LED
NOTATTN:
RET
;
;**************************************************************************
;LOAD SOURCE DISPLAY. high nibble of LED_STATUS stores source display
;Also updates GAIN byte.
;DESTROYS A,B,CY
;**************************************************************************
LOAD_SRCD:
MOV A,CHANNEL
CJNE A,#00H,SRC3
MOV B,#080H ;IN4
MOV GAIN,GAIN4
AJMP LDSRC
SRC3: CJNE A,#01H,SRC2
MOV B,#040H ;IN3
MOV GAIN,GAIN3
AJMP LDSRC
SRC2: CJNE A,#02H,SRC1
MOV B,#020H ;IN2
MOV GAIN,GAIN2
AJMP LDSRC
SRC1: MOV B,#010H ;IN1
MOV GAIN,GAIN1
LDSRC:
MOV LED_STATUS,B ;function select = volume & save status to RAM
ACALL LOAD_LED
RET
;
;**************************************************************************
; BINARY TO BCD CONVERSION ROUTINE
;SEE P313 OF R. S. GAONKAR'S 8085 BOOK FOR ACTUAL LOGIC
;ACCEPTS A BINARY NUMBER BETWEEN 0-99D(63H) IN ACC & CONVERTS TO BCD
;IF ACC>63H(99D) OUTPUTS 00H
;DESTROYS A,CY & B
;**************************************************************************
HEXBCD:
MOV B,#00H
CJNE A,#64H,N100 ;NOT EQUAL 100D
N100: JC LT99
AJMP GT99 ;greater than 99D
LT99: ;less than 99D, continue
SUB10: ;repeatedly subtaract 10D from Acc till reminder less than 10D
CLR C
CJNE A,#0AH,N10 ;NOT EQUAL 10D
N10: JC LT10 ;reminder less than 10D
SUBB A,#0AH
INC B ;loop counter
AJMP SUB10
GT99: CLR A ;output 00 only if greater than 99D
LT10: SWAP A ;A contains low BCD nibble & B contains high BCD nibble
ORL A,B
SWAP A
RET
;
;*************************************************************************
;loads a byte FROM P1 in DISPLAY port.
;*************************************************************************
LOAD_DISP:
SETB DISP_LATCH ;latch the byte in Display latch
NOP
CLR DISP_LATCH
RET
;
;**************************************************************************
;Displays input gain settings(0 - 15) on LED Display
;destroys A,CY,P1
;**************************************************************************
DISP_GAIN:
MOV A,GAIN
ACALL HEXBCD ;convert to BCD
MOV P1,A
ANL A,#0F0H ;clear low nibble
JNZ LDGAIN
ORL P1,#0F0H ;set illegal BCD to supress leading zero
LDGAIN:
ACALL LOAD_DISP
RET
;
;**************************************************************************
;Displays volume (1-80)settings on LED Display
;Entry: B=setting value & ACC=max value for the setting(4F/2F)
;destroys A,CY,P1,B
;**************************************************************************
DISP_VOL:
MOV A,#050H
MOV B,R_ATTN
CLR C
SUBB A,B
ACALL HEXBCD
MOV P1,A
ANL A,#0F0H ;clear low nibble
JNZ LDVOL
ORL P1,#0F0H ;set illegal BCD to supress leading zero
LDVOL:
ACALL LOAD_DISP
RET
;
;**************************************************************************
;Displays attenuation (0-47)settings on LED Display
;destroys A,P1
;**************************************************************************
DISP_ATT:
MOV A,VOLUME
ACALL HEXBCD
MOV P1,A
ANL A,#0F0H ;clear low nibble
JNZ LDATT
ORL P1,#0F0H ;set illegal BCD to supress leading zero
LDATT:
ACALL LOAD_DISP
RET
;
;**************************************************************************
;Displays bass/middle/treble settings(07-00-0-7) on LED Display.
;called with bass/middle/treble settings in B register
;destroys A,P1,CY,B
;**************************************************************************
DISP_AUD:
JB B.3,GT8
MOV A,#07H ;if settings less than 8H, subtract from 07H
CLR C
SUBB A,B
ACALL HEXBCD ;do not supress leading zero => CUT
AJMP LDDSPL
GT8: ;if settings greater than 8H, subtract from 0FH
MOV A,#0FH
CLR C
SUBB A,B
ACALL HEXBCD
ORL A,#0F0H ;set illegal BCD to supress leading zero=>BOOST
LDDSPL:
MOV P1,A
ACALL LOAD_DISP
RET
;
;//////////////////////////////////////////////////////////////////////////
; END OF DISPLAY ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; COMMAND & KEY DECODING ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;*************************************************************************
; Bass_Middle_Treble Up, used by DO_VOL_UP routine
;*************************************************************************
B_M_T_UP:
CJNE A,#07H,NE7_BMTUP
MOV A,#0FH
RET
NE7_BMTUP:
JNC GT7_BMTUP
INC A
RET
GT7_BMTUP:
CJNE A,#08H,NE8_BMTUP
RET ;Setting already maximum
NE8_BMTUP:
DEC A
RET
;
;*************************************************************************
; Bass_Middle_Treble Down, used by DO_VOL_DN routine
;*************************************************************************
B_M_T_DN:
JNZ NE0_BMTDN
RET ;Already minimum, do nothing
NE0_BMTDN:
JB ACC.3,GT7_BMTDN
DEC A ;Decrement if less than 7
RET
GT7_BMTDN:
CJNE A,#0FH,LT15_BMTDN
MOV A,#07H
RET
LT15_BMTDN:
INC A ;Increment if less than 15
RET
;
;*************************************************************************
; Process VOL_UP command
;*************************************************************************
DO_VOL_UP:
JNB GAIN_ON,FUN_UP
CALL DO_GAIN_UP
JMP DONE_VUP
FUN_UP:
MOV A,LED_STATUS
ANL A,#0FH ;CLEAR HIGH NIBBLE (LOW NIBBLE = FUNCTION DISPLAY)
CHECK_VOL_UP:
JNZ CHECK_BAS_UP ; Increase VOL IF ACC=0
MOV A,R_ATTN ;PROCESS RIGHT CHANNEL
JZ DONE_VUP ;Attenuation already 0dB, do nothing
DEC A ;Volume UP
MOV AUDIODATA,A
MOV SUBADDR,#06H
CALL SET_AUDIO
JC DONE_VUP
MOV R_ATTN,AUDIODATA
;
MOV A,L_ATTN ;PROCESS LEFT CHANNEL
JZ DONE_VUP ;Attenuation already 0dB, do nothing
DEC A ;Volume UP
MOV AUDIODATA,A
MOV SUBADDR,#07H
CALL SET_AUDIO
JC DONE_VUP
MOV L_ATTN,AUDIODATA
;
CALL DISP_VOL ;UPDATE LED DISPLAY
AJMP DONE_VUP
CHECK_BAS_UP: ; Increment BASS
CJNE A,#01H,CHECK_MID_UP
MOV A,BASS
CALL B_M_T_UP
MOV B,A ;used by DISP_AUD
MOV SUBADDR,#03H
MOV AUDIODATA,A
CALL SET_AUDIO ;Change audio settings
JC DONE_VUP
MOV BASS,AUDIODATA ;Update RAM
CALL DISP_AUD ;B-reg already contains display settings
AJMP DONE_VUP
CHECK_MID_UP: ; Increment MIDDLE
CJNE A,#02H,CHECK_TRE_UP
MOV A,MIDDLE
CALL B_M_T_UP
MOV B,A ;used by DISP_AUD
MOV SUBADDR,#04H
MOV AUDIODATA,A
CALL SET_AUDIO ;Change audio settings
JC DONE_VUP
MOV MIDDLE,AUDIODATA ;Update RAM
CALL DISP_AUD ;B-reg already contains display settings
AJMP DONE_VUP
CHECK_TRE_UP: ; Increment TREBLE
CJNE A,#04H,CHECK_ATT_UP
MOV A,TREBLE
CALL B_M_T_UP
MOV B,A ;used by DISP_AUD
MOV SUBADDR,#05H
MOV AUDIODATA,A
CALL SET_AUDIO ;Change audio settings
JC DONE_VUP
MOV TREBLE,AUDIODATA ;Update RAM
CALL DISP_AUD ;B-reg already contains display settings
AJMP DONE_VUP
CHECK_ATT_UP:
CJNE A,#08H,DONE_VUP
MOV A,VOLUME
CJNE A,#02FH,NE2FVOL
AJMP DONE_VUP ;Already max attenuation
NE2FVOL:
JNC DONE_VUP ;Already max attenuation/Mute
INC A
MOV AUDIODATA,A
MOV SUBADDR,#02H
CALL SET_AUDIO
JC DONE_VUP
; ;UPDATE DISPLAY
MOV VOLUME,AUDIODATA
CALL DISP_ATT
DONE_VUP:
RET
;
;*************************************************************************
; Process VOL_DN command
;*************************************************************************
DO_VOL_DN:
JNB GAIN_ON,FUN_DN
CALL DO_GAIN_DN
JMP DONE_VUP
FUN_DN:
MOV A,LED_STATUS
ANL A,#0FH ;CLEAR HIGH NIBBLE (LOW NIBBLE = FUNCTION DISPLAY)
CHECK_VOL_DN:
JNZ CHECK_BAS_DN ; Decrease VOL IF ACC=0
MOV A,R_ATTN ;PROCESS RIGHT CHANNEL
CJNE A,#04FH,RV_DN
AJMP DONE_VDN ;Attenuation already -79dB, do nothing
RV_DN:
INC A ;Volume DOWN
MOV AUDIODATA,A
MOV SUBADDR,#06H
CALL SET_AUDIO
JC DONE_VDN
MOV R_ATTN,AUDIODATA ;Save settings to RAM
;
MOV A,L_ATTN ;PROCESS LEFT CHANNEL
CJNE A,#04FH,LV_DN
AJMP DONE_VDN ;Attenuation already -79dB, do nothing
LV_DN:
INC A ;Volume DOWN
MOV AUDIODATA,A
MOV SUBADDR,#07H
CALL SET_AUDIO
JC DONE_VDN
MOV L_ATTN,AUDIODATA ;Save settings to RAM
; ;UPDATE LED DISPLAY
CALL DISP_VOL
AJMP DONE_VDN
CHECK_BAS_DN: ; Decrement BASS
CJNE A,#01H,CHECK_MID_DN
MOV A,BASS
CALL B_M_T_DN
MOV B,A ;used by DISP_AUD
MOV SUBADDR,#03H
MOV AUDIODATA,A
CALL SET_AUDIO ;Change audio settings
JC DONE_VDN
MOV BASS,AUDIODATA ;Update RAM
CALL DISP_AUD ;B-reg already contains display settings
AJMP DONE_VDN
CHECK_MID_DN: ; Decrement MIDDLE
CJNE A,#02H,CHECK_TRE_DN
MOV A,MIDDLE
CALL B_M_T_DN
MOV B,A ;used by DISP_AUD
MOV SUBADDR,#04H
MOV AUDIODATA,A
CALL SET_AUDIO ;Change audio settings
JC DONE_VDN
MOV MIDDLE,AUDIODATA ;Update RAM
CALL DISP_AUD ;B-reg already contains display settings
AJMP DONE_VDN
CHECK_TRE_DN: ; Decrement TREBLE
CJNE A,#04H,CHECK_ATT_DN
MOV A,TREBLE
CALL B_M_T_DN
MOV B,A ;used by DISP_AUD
MOV SUBADDR,#05H
MOV AUDIODATA,A
CALL SET_AUDIO ;Change audio settings
JC DONE_VDN
MOV TREBLE,AUDIODATA ;Update RAM
CALL DISP_AUD ;B-reg already contains display settings
AJMP DONE_VDN
CHECK_ATT_DN:
CJNE A,#08H,DONE_VDN
MOV A,VOLUME
JZ DONE_VDN ;Already minimum Attenuation
DEC A
MOV AUDIODATA,A
MOV SUBADDR,#02H
CALL SET_AUDIO
JC DONE_VDN
; ;UPDATE DISPLAY
MOV VOLUME,AUDIODATA
CALL DISP_ATT
DONE_VDN:
RET
;
;*************************************************************************
; Increment Source
;Destroys A,CY
;*************************************************************************
INC_SOURCE:
MOV A,CHANNEL
INC A
JNB ACC.2,ST_SRC
CLR A
ST_SRC: ;Store source
MOV SUBADDR,#00H ;R4=TDA7439 FUNCTION SELECTION BYTE
MOV AUDIODATA,A ;R3=INPUT CHANNEL
CALL SET_AUDIO ;TDA7439 change channel
JC SRC_ERR
MOV CHANNEL,AUDIODATA ;STORE IN RAM
CALL LOAD_SRCD ;update display & GAIN byte
MOV SUBADDR,#01H ;R4=TDA7439 FUNCTION SELECTION BYTE
MOV AUDIODATA,GAIN ;R3=INPUT GAIN
CALL SET_AUDIO ;TDA7439 change gain settings
SRC_ERR:
RET
;
;*************************************************************************
; PROCESS GAIN KEY (TOGGLE)
;*************************************************************************
DO_GAIN:
JB GAIN_ON,OFF_GAIN
SETB GAIN_ON
ANL LED_STATUS,#0F0H
CALL LOAD_LED
CALL DISP_GAIN
RET
OFF_GAIN:
CLR GAIN_ON
CALL DISP_VOL
CALL LOAD_LED
RET
;
;*************************************************************************
; PROCESS GAIN UP
;*************************************************************************
DO_GAIN_UP:
MOV A,GAIN
CJNE A,#0FH,GAIN_INC
RET ;Already maximum
GAIN_INC:
INC A
MOV AUDIODATA,A
MOV SUBADDR,#01H
CALL SET_AUDIO
JC END_GAIN_UP
MOV GAIN,AUDIODATA
CALL UPDATE_GAIN
CALL DISP_GAIN
END_GAIN_UP:
RET
;
;*************************************************************************
; PROCESS GAIN DN
;*************************************************************************
DO_GAIN_DN:
MOV A,GAIN
JZ END_GAIN_DN ;Already minimum
DEC A
MOV AUDIODATA,A
MOV SUBADDR,#01H
CALL SET_AUDIO
JC END_GAIN_DN
MOV GAIN,AUDIODATA
CALL UPDATE_GAIN
CALL DISP_GAIN
END_GAIN_DN:
RET
;
;*************************************************************************
; MOVE GAIN TO GAIN1/GAIN2/GAIN3/GAIN4 depending on active channel
;*************************************************************************
UPDATE_GAIN:
MOV A,LED_STATUS
ANL A,#0F0H
CJNE A,#010H,CH2
MOV GAIN1,GAIN
RET
CH2: CJNE A,#020H,CH3
MOV GAIN2,GAIN
RET
CH3: CJNE A,#040H,CH4
MOV GAIN3,GAIN
RET
CH4: MOV GAIN4,GAIN
RET
;
;*************************************************************************
; TOGGLE STANDBY STATUS
;*************************************************************************
TOGGLE_STDBY:
JB STANDBY,STANDBY_OFF
CALL SET_MUTE_ON
SETB STANDBY
CALL SAVE_STATE
MOV R5,#05H ;0.5 Sec Delay
CALL DELAYSEC
MOV P0,#0FFH ;Turn off LEDs
SETB POWER ;Active low
CLR INDICATOR ;Turn on Command Indicator LED
RET
STANDBY_OFF:
CLR STANDBY
CLR POWER
CALL LOAD_LED
SETB INDICATOR ;Turn off Command Indicator LED
JNB MUTE,MUTE_OFF
MOV P1,#00H
CALL LOAD_DISP
RET
MUTE_OFF:
MOV R5,#0AH ;1 Sec Delay
CALL DELAYSEC
CALL SET_MUTE_OFF
RET
;
;*************************************************************************
; TOGGLE MUTE STATUS
;*************************************************************************
DO_MUTE:
JB MUTE,DO_MUTE_OFF ;TURN OFF MUTE
CALL SET_MUTE_ON
JC END_MUTE
SETB MUTE
MOV P1,#00H
CALL LOAD_DISP
RET
DO_MUTE_OFF:
CALL SET_MUTE_OFF
JC END_MUTE
CLR MUTE
CALL DISP_VOL
END_MUTE:
RET
;
;*************************************************************************
SET_MUTE_ON:
MOV AUDIODATA,#078H ;MUTE
MOV SUBADDR,#06H ;RIGHT CHANNEL
CALL SET_AUDIO
JC END_MUTE_ON
MOV SUBADDR,#07H ;LEFT CHANNEL
CALL SET_AUDIO
END_MUTE_ON:
RET
;
;*************************************************************************
SET_MUTE_OFF:
MOV AUDIODATA,R_ATTN ;RIGHT CHANNEL VOLUME
MOV SUBADDR,#06H ;RIGHT CHANNEL
CALL SET_AUDIO
JC END_MUTE_OFF
MOV AUDIODATA,L_ATTN ;LEFT CHANNEL VOLUME
MOV SUBADDR,#07H ;LEFT CHANNEL
CALL SET_AUDIO
JC END_MUTE_OFF
MOV AUDIODATA,VOLUME ;ATTNEUATION
MOV SUBADDR,#02H
CALL SET_AUDIO
END_MUTE_OFF:
RET
;
;*************************************************************************
; IMPLEMENTS REMOTE COMMANDS
;*************************************************************************
DO_COM:
MOV R0,COMMAND
CALL DO_COMMAND
CLR NEW_COM
RET
;
;*************************************************************************
; IMPLEMENTS KEYPAD COMMANDS
;*************************************************************************
DO_KEY:
MOV R0,KEY
CALL DO_COMMAND
CLR NEW_KEY
RET
;
;*************************************************************************
; IMPLEMENTS KEYPAD/REMOTE COMMANDS
;*************************************************************************
DO_COMMAND:
CHECK_STANDBY: ;check if STANDBY pressed
CJNE R0,#STDBY,CHECK_V_UP
JB REPEAT,END_COMMAND ;No contineous-key-press
CALL OFF_GAIN
CALL TOGGLE_STDBY
AJMP END_COMMAND
CHECK_V_UP: ;check if VOL_UP pressed
JB STANDBY,END_COMMAND ;If in standby do nothing
CJNE R0,#VOL_UP,CHECK_V_DN
CALL DO_VOL_UP
AJMP END_COMMAND
CHECK_V_DN: ;check if VOL_DN pressed
CJNE R0,#VOL_DN,CHECK_SEL
CALL DO_VOL_DN
AJMP END_COMMAND
CHECK_SEL: ;check if SEL pressed
CJNE R0,#SEL,CHECK_SOURCE
JB REPEAT,END_COMMAND
CALL OFF_GAIN
CALL INC_SELD ;Increment function selection
AJMP END_COMMAND
CHECK_SOURCE: ;check if SOURCE pressed
CJNE R0,#SOURCE,CHECK_GAIN
JB REPEAT,END_COMMAND
CALL OFF_GAIN
CALL INC_SOURCE
AJMP END_COMMAND
CHECK_GAIN: ;check if GAIN pressed
CJNE R0,#INGAIN,CHECK_MUTE
JB REPEAT,END_COMMAND
CALL DO_GAIN
AJMP END_COMMAND
CHECK_MUTE: ;check if MUTE pressed
CJNE R0,#MUT,END_COMMAND
JB REPEAT,END_COMMAND
CALL OFF_GAIN
CALL DO_MUTE
END_COMMAND:
CALL INIT_TIMER1
RET
;
;*************************************************************************
INIT_TIMER1:
CLR TR1
MOV T1_COUNT,#01H
MOV TH1,#00H
MOV TL1,#00H
SETB TR1
CLR INDICATOR ;Turn on INDICATOR LED
RET
;
;//////////////////////////////////////////////////////////////////////////
; END OF COMMAND & KEY DECODING ROUTINES
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; TIMER1 INTERRUPT HANDLER ROUTINE
; Volume function (default) selected if T1 is running for 4Sec+.
; Keeps source display flashing if GAIN_ON is set.
;//////////////////////////////////////////////////////////////////////////
INTR_T1:
PUSH IE
CLR EA ;disable interrupts
CLR TR1 ;stop timer temporarily
PUSH ACC
PUSH PSW
MOV A,T1_COUNT
CJNE A,#066H,NE66T1
MOV T1_COUNT,#01H
ANL LED_STATUS,#0F0H ;Function select = Volume
CLR GAIN_ON
CALL DISP_VOL
CALL LOAD_LED
JNB STANDBY,END_INT_T1
MOV P0,#0FFH
AJMP END_INT_T1
NE66T1:
MOV TH1,#015H ;T1 reload value =65535-60000=5535D=159FH
MOV TL1,#09FH ;T1 overflow every 60mS
INC T1_COUNT
SETB TR1
CJNE A,#01H,NE01T1
CLR INDICATOR ;Turn on Command Indicator LED
AJMP FLASH_DISP
NE01T1:
JB STANDBY,FLASH_DISP
SETB INDICATOR ;Turn off Command Indicator LED
FLASH_DISP:
JNB GAIN_ON,END_INT_T1
ANL A,#07H ;Clear A except last 3 bits
JNZ MULTIPLE_4
MOV P0,#0FFH ;Clear display if multiple of 8
AJMP END_INT_T1
MULTIPLE_4:
CLR ACC.2
JNZ END_INT_T1
CALL LOAD_LED ;load led display if multiple of 4
END_INT_T1:
POP PSW
POP ACC
POP IE
RETI
;
;//////////////////////////////////////////////////////////////////////////
; END OF TIMER1 INTERRUPT HANDLER ROUTINE
;//////////////////////////////////////////////////////////////////////////
;
;//////////////////////////////////////////////////////////////////////////
; MAIN ENTRY ROUTINE
;//////////////////////////////////////////////////////////////////////////
;
START:
;*************************************************************************
; REGISTER INITIALIZATION
;*************************************************************************
MOV SP,#STACKBASE ;stack base address
CLR A
MOV TCON,A
MOV PSW,A
MOV IE,A ;Disable Interrupts
MOV T1_COUNT,A
MOV TMOD,#011H ;T1 & T0 IN 16-bit MODE1, GATEx=0 & CTx=0
CLR TR1
SETB TR0 ;START TIMER TO REJECT FIRST TRANSMISSION
SETB SDA ;I2C Initialize
SETB SCL
SETB POWER ;Standby on (active low)
SETB MONITOR ;Power monitor as input(active low)
CLR REPEAT
CLR NEW_COM
CLR NEW_KEY
CLR DISP_LATCH
CLR GAIN_ON
;
INIT: ;INITIALIZATION STARTS HERE
CLR C
;*************************************************************************
; STANDBY & MUTE INITIALIZATION
;*************************************************************************
CLR A
MOV ADDR,#00H ;READ STANDBY STATUS
ACALL READ_RANDOM
JC INIT ;RETRY
RRC A ;move LSB into CY bit
MOV STANDBY,C ;store standby status in RAM
RRC A
MOV MUTE,C ;store mute status in RAM
;*************************************************************************
; AUDIO PARAMETERS INITIALIZATION
;*************************************************************************
;
; Read 8 bytes (01H to 0CH) sequentially from 24Cxx and move to
; internal RAM locations 024H to 02FH
;*************************************************************************
CALL INIT_MEM
JC INIT
;
;*************************************************************************
;Validity check of memory data bytes
;*************************************************************************
VAL_CH: MOV A,CHANNEL
CJNE A,#04H,NE04V
NE04V: JC VAL_G1
MOV CHANNEL,#03H ;Select IN1
VAL_G1: MOV A,GAIN1
CJNE A,#010H,NE10G1
NE10G1: JC VAL_G2
MOV GAIN1,#00H ;GAIN1 = 0
VAL_G2: MOV A,GAIN2
CJNE A,#010H,NE10G2
NE10G2: JC VAL_G3
MOV GAIN2,#00H ;GAIN2 = 0
VAL_G3: MOV A,GAIN3
CJNE A,#010H,NE10G3
NE10G3: JC VAL_G4
MOV GAIN3,#00H ;GAIN3 = 0
VAL_G4: MOV A,GAIN4
CJNE A,#010H,NE10G4
NE10G4: JC VAL_ATT
MOV GAIN4,#00H ;GAIN4 = 0
VAL_ATT: MOV A,VOLUME
CJNE A,#030H,NE30ATT
NE30ATT: JC VAL_BAS
MOV VOLUME,#00H ;ATTN = 0
VAL_BAS: MOV A,BASS
CJNE A,#010H,NE10BAS
NE10BAS: JC VAL_MID
MOV BASS,#07H ;BASS = 0
VAL_MID: MOV A,MIDDLE
CJNE A,#010H,NE10MID
NE10MID: JC VAL_TRE
MOV MIDDLE,#07H ;VOICE = 0
VAL_TRE: MOV A,TREBLE
CJNE A,#010H,NE10TRE
NE10TRE: JC VAL_VOL
MOV TREBLE,#07H ;TRE = 0
VAL_VOL: MOV A,R_ATTN
CJNE A,#050H,NE50VOL
NE50VOL: JC VAL_LEFT
MOV R_ATTN,#04FH ;VOL = 0
;
VAL_LEFT: MOV L_ATTN,R_ATTN ;Remove if balance adj addeed
;
;**************************************************************************
;initialize LED & Display port.
;**************************************************************************
CALL LOAD_SRCD ;display input channel & function selected->volume
CALL DISP_VOL ;Display volume settings
JNB STANDBY,AUDIO_INIT
MOV P0,#0FFH ;Turn off all LEDs
CLR INDICATOR ;Turn on Command Indicator/Standby LED
JNB MUTE,AUDIO_INIT
MOV P1,#00H ;Display 00 if Mute on
CALL LOAD_DISP
;*************************************************************************
; Send audio parameter values to audio processor with incremental bus
; except R & L Volume
;*************************************************************************
AUDIO_INIT:
CALL BITDLY
CALL INIT_AUDIO
JC AUDIO_INIT
;
MOV C,STANDBY ;<- POWER SHOULD BE ACTIVATED ONLY AFTER AUDIO SET
MOV POWER,C
MOV R5,#014H
CALL DELAYSEC ;2SEC Delay
;
JB MUTE,GO_EVENTS
JB STANDBY,GO_EVENTS
CALL SET_MUTE_OFF ;Initialize volume
GO_EVENTS:
;*************************************************************************
;############### WAIT-FOR-EVENTS LOOP ################################
;waits for three events -> power off, key press & remote rx
;*************************************************************************
SETB EX0 ;External Int0 for IR Sensor
SETB ET1 ;Timer1 interrupt
SETB EA ;Enable Interrupts
;
LOOP:
JB MONITOR,POWER_OFF ;If MONITOR high, go to POWER_OFF (active low)
CALL CHECK_KEY
JB NEW_KEY,GO_KEY
JB NEW_COM,GO_COM
AJMP LOOP
GO_KEY:
CLR EX0 ; disable Int0
CALL DO_KEY ; Process Key
SETB EX0 ; Enable Int0
AJMP LOOP
GO_COM:
CLR EX0 ; disable Int0
CALL DO_COM ; Process Command
SETB EX0 ; Enable Int0
AJMP LOOP
;
;*************************************************************************
;############## END OF WAIT-FOR-EVENTS LOOP ##########################
;*************************************************************************
;
;*************************************************************************
; POWER OFF SEQUENCE
;*************************************************************************
POWER_OFF:
CLR EA ; DISABLE INTERRUPTS
JB STANDBY,CONT_OFF ; no need to save settings if already in standby
CALL SAVE_STATE ; save settings to EEPROM
MOV R5,#05H
CALL DELAYSEC ;0.5 Sec delay
JNB MONITOR,GO_EVENTS
;
;**************************************************************************
;Settings saved on EEPROM. MUTE audio & turn off standby relay
;**************************************************************************
CONT_OFF:
CALL SET_MUTE_ON
SETB POWER ;turn off relay (active low)
MOV P0,#0FFH ;turn off LEDs
JB MONITOR,$ ;loop till power goes down or comes on
JMP RESET ;reset device
;**************************************************************************
;
;######################## THE END #####################################
END
No comments:
Post a Comment