Код:
;**************************************************************************
;**************************************************************************
;*
;* Stereo Audio Volume Control Firmware
;*
;* Version 1.0 16/12/06
;*
;* Created by P.B.Smith
;* (C)2006 Silicon Chip Publications P/L
;* All Rights Reserved.
;*
;* www.siliconchip.com.au
;*
;* +-----------------------------------------------+
;* | This source code is NOT in the public domain! |
;* +-----------------------------------------------+
;*
;************************************^*************************************
;*
;* CHANGE RECORD
;*
;* Nil.
;*
;**************************************************************************
;*
;* NOTES
;*
;* 1. Requires AVRASM v1.74 or later (set tab size to 8 in editor).
;* 2. Implements a software SPI port rather than using the hardware
;* port to circumvent a physical layout issue.
;* 3. Support for up to 6 daisy-chained PGA2310*s is included but has
;* not been fully implemented or tested in this version.
;*
;**************************************************************************
.equ VERSION_MAJOR = 1
.equ VERSION_MINOR = 0
.equ TRUE = 1
.equ FALSE = 0
.equ debug = FALSE ;for special debugging hardware only!
.nolist
.if debug
.include "8515ndef.inc" ;AVR definitions
.else
.include "m8515ndef.inc"
.endif
.list
;**************************************************************************
;*
;* Registers
;*
;**************************************************************************
.def status =R0 ;state save (used by tmr0_irq)
.def ir_state =R1 ;ir receive state
.def ir_bit_cnt =R2 ;ir bit count
.def ir_sys =R3 ;ir received system bits
.def ir_cmd =R4 ;ir received command bits
.def ir_code =R5 ;last received command bits
.def irate_tmr =R6 ;interrupt rate timer
.def idle_tmr_lo =R7 ;idle timer (ms)
.def idle_tmr_hi =R8
.def fast_tmr_lo =R9 ;fast adjust timer (ms)
.def fast_tmr_hi =R10
.def sw_timer =R11 ;switch filter timer
.def d_timer =R12 ;display *flash* timer
.def spi_state =R13 ;spi state
.def spi_pipe_lo =R14 ;spi bit pipe
.def spi_pipe_hi =R15 ;
.def A =R16 ;scratch
.def B =R17 ;scratch
.def C =R18 ;scratch
.def D =R19 ;scratch
.def aflags =R20 ;various flags (see bit vars below)
.def bflags =R21 ;ditto
.def cflags =R22 ;ditto
.def spi_cnt =R23 ;spi word counter
.def spi_bits =R24 ;spi bit count
.def ir_timer =R25 ;ir bit timer
.def XL =R26 ;scratch pointer
.def XH =R27 ;
.def YL =R28 ;spi buffer pointer (used by spi_io)
.def YH =R29 ;
.def ZL =R30 ;scratch pointer
.def ZH =R31 ;
; Bit variables
; aflags
.equ ir_event =0 ;infrared data available
.equ ir_rpt =1 ;repeat infrared code
.equ rot_event =2 ;rotary encoder event
.equ rot_dir =3 ;1=right, 0=left
.equ rot_f1 =4 ;rotary handler flag
.equ rot_f2 =5 ;ditto
.equ spi_req =6 ;spi transfer request
.equ wd_res =7 ;watchdog keep-alive
; bflags
.equ sw_event =0 ;switch event occurred
.equ sw_stat =1 ;1=switch closed, 0=open
.equ sw_run =2 ;switch filter active
.equ d_flash =3 ;flash display request
.equ d_state =4 ;blank display request
.equ d_blank =5 ;display blanked/not blanked
; cflags
.equ b_mode =0 ;balance mode
.equ c_mode =1 ;channel mode
.equ c_slave =2 ;channels slaved (future upgrade)
.equ v_mute =3 ;mute status
.equ fast_run =4 ;fast adjust timer active
.equ fast_adj =5 ;fast adjust mode
.equ dirty_bit =7 ;volume save pending
; vflags (stored with volume data)
.equ lr_offset =0 ;0=vol offset is left, 1=vol offset is right
;**************************************************************************
;*
;* Hardware specific
;*
;**************************************************************************
; Port B bits
.equ jp1 =PB0 ;setup jumper
.equ jp2 =PB3 ;0.5dB/1.5dB vol adjust jumper
.equ pga_mute =PB4 ;mute control
.equ sdi =PB5 ;SPI bus serial input
.equ sdo =PB6 ;SPI bus serial output
.equ sck =PB7 ;SPI bus clock
; Port D bits
.equ pga_cs =PD0 ;SPI bus chip select
.equ pga_zcen =PD1 ;zero crossing switching enable
.equ rot_a =PD2 ;rotary encoder *A* terminal
.equ rot_b =PD3 ;rotary encoder *B* terminal
.if debug
.equ ir_rxd =PD4 ;ir module input
.equ ch_sw =PD5 ;channel switch
.equ bal_sw =PD6 ;balance switch
.endif
.equ ack_led =PD7 ;infrared acknowledge led
.if !debug
; Port E bits
.equ ir_rxd =PE0 ;ir module input
.equ ch_sw =PE1 ;balance switch
.equ bal_sw =PE2 ;channel switch
.endif
;**************************************************************************
;*
;* Constants
;*
;**************************************************************************
.equ KEY_RPT =114 ;time between ir code repeats (ms)
; Supported infrared equipment addresses
.equ TV_ADDR =0
.equ SAT1_ADDR =8
.equ SAT2_ADDR =10
.equ CD_ADDR =20
; Supported infrared remote key codes
.equ CH_1 =1
.equ CH_2 =2
.equ CH_3 =3
.equ CH_4 =4
.equ CH_5 =5
.equ CH_6 =6
.equ VOL_UP =16
.equ VOL_DN =17
.equ CH_UP =32
.equ CH_DN =33
.equ MUTE_TV1 =13 ;*punch-through* mute (sys = 0)
.equ MUTE_ALT1 =18 ;alt mute: 12 (Aifa), TV1 code 191
.equ MUTE_ALT2 =43 ;alt mute: 12 (Aifa), CD code 651
; Codes used by main function handlers
.equ chup =1 ;channel up
.equ chdn =2 ;channel down
.equ chset =3 ;channel set
.equ panl =4 ;pan left
.equ panr =5 ;pan right
;**************************************************************************
;*
;* Interrupt vectors
;*
;**************************************************************************
.cseg
.org $0
rjmp reset ;reset
rjmp bad_irq ;INT0
rjmp bad_irq ;INT1
rjmp bad_irq ;timer 1 capture
rjmp bad_irq ;timer 1 compare A
rjmp bad_irq ;timer 1 compare B
rjmp bad_irq ;timer 1 overflow
rjmp tmr0_irq ;timer 0 overflow
rjmp bad_irq ;SPI transfer complete
rjmp bad_irq ;UART receive complete
rjmp bad_irq ;UART data register empty
rjmp bad_irq ;UART transmit complete
rjmp bad_irq ;analog comparator
rjmp bad_irq ;INT2
rjmp bad_irq ;timer 0 compare
rjmp bad_irq ;EEPROM ready
rjmp bad_irq ;SPM ready
bad_irq:
reti
;**************************************************************************
;*
;* Reset entry point
;*
;* Initialise 8515 I/O ports & registers
;*
;**************************************************************************
reset: cli
ldi A,0b11111111
out DDRA,A ;port A: 7 - 0 out (7-seg display)
ldi A,0b00000000 ;all segments off
out PORTA,A
ldi A,0b00000000 ;port B: 7-5 in (SPI), 4 out (mute)
out DDRB,A ;3-0 in (jumpers, unused)
ldi A,0b11101111 ;inputs pulled up, mute active
out PORTB,A
ldi A,0b11111111
out DDRC,A ;port C: 7 - 0 out (7-seg display)
ldi A,0b00000000 ;all segments off
out PORTC,A
ldi A,0b10000011 ;port D: 7 out (LED), 6-4 in (unused)
out DDRD,A ;3-2 in (rotary), 1-0 out (pga control)
ldi A,0b01111111 ;LED off, inputs pulled up, ZCEN & -CS high
out PORTD,A
.if !debug
ldi A,0b00000000 ;port E: 2-0 in (ir & switches)
out DDRE,A
ldi A,0b00000111 ;inputs pulled up
out PORTE,A
.endif
sbi ACSR,ACD ;power down comparator
;**************************************************************************
;*
;* Warm reset entry point
;*
;* Initialise counter/timer 0, watchdog & various flags
;*
;**************************************************************************
warm_reset:
ldi A,low(RAMEND) ;set stack top
out SPL,A
ldi A,high(RAMEND)
out SPH,A
; Start timer 0
ldi A,1<<CS00 ;CT0 clocked at CK (no prescale)
out TCCR0,A
ldi A,128 ;timer 0 up count
out TCNT0,A
ldi A,1<<TOIE0 ;enable CT0 overflow interrupt
out TIMSK,A
; Init variables
clr A
mov aflags,A ;and program flags...
mov bflags,A
mov cflags,A
mov spi_state,A
mov ir_state,A
sei ;enable interrupts
;**************************************************************************
;*
;* Initialisation
;*
;**************************************************************************
; Mute all channels
init: ldi A,6
sts pga_cnt,A ;assume 6 x PGAs on the bus...
rcall mute_all ;mute *em all
rcall display_clear ;blank the display
; Init eeprom if first power up
ldi ZL,low(ee_magic)
ldi ZH,high(ee_magic)
rcall ee_read
cpi A,$5A ;magic number?
breq in2 ;continue if found
rcall init_eeprom ;else initialise
in2: sbic PINB,JP1 ;skip if *setup* jumper in
rjmp in5 ;else continue init
;**************************************************************************
;*
;* Infrared setup (JP1 installed)
;*
;**************************************************************************
in3: ldi B,5
rcall flash_it ;flash *ack* LED to indicate setup
; Wait for two consecutive identical infrared codes...
in4: rcall wait_ir ;wait for an infrared code
mov C,ir_code ;save it
andi C,$7F
mov D,ir_sys
rcall wait_ir ;get second code
mov A,ir_code
andi A,$7F
cp A,C ;same code?
brne in4
cp D,ir_sys ;same sys address?
brne in4
ldi ZL,low(ee_blank)
ldi ZH,high(ee_blank)
rcall ee_write ;key code becomes blanking selector
adiw ZH:ZL,1 ;to ee_ir_sys
mov A,ir_sys
rcall ee_write ;save as our address
rjmp in3 ;loop forever
;**************************************************************************
;*
;* Initialisation (continued)
;*
;**************************************************************************
; Display firmware version number if *balance* switch is pressed
.if !debug
in5: in A,PINE ;get switch state
.else
in5: in A,PIND ;get switch state
.endif
andi A,1<<bal_sw ;keep balance switch bit
ldi A,(VERSION_MAJOR*10)+VERSION_MINOR
breq in6 ;go display version # if pressed
; Determine number of connected PGAs
rcall get_pga
tst C ;zero detected?
brne in8 ;continue if not
; No PGAs found, display error code
cbr cflags,1<<v_mute ;turn off mute indication...
cbi PORTA,PA5
ldi A,90 ;error code [90]
in6: rcall display ;display it
sbr bflags,1<<d_flash ;enable flash
in7: rjmp in7 ;wait for power down
; Enable watchdog
in8: wdr
ldi A,1<<WDTOE|1<<WDE
out WDTCR,A
ldi A,1<<WDE|1<<WDP2|1<<WDP1 ;1s (typ) timeout
out WDTCR,A
; Restore volume & channel settings from EEPROM
rcall restore_vol ;restore vol/ch settings
rcall unmute_all ;unmute & display volume
;**************************************************************************
;*
;* Foreground loop
;*
;**************************************************************************
main: clr idle_tmr_lo ;zero idle timer
clr idle_tmr_hi
mn1: sbrc aflags,rot_event ;rotary encoder operated
rjmp rotary_event
sbrc aflags,ir_event ;infrared code received
rjmp infra_event
sbrc bflags,sw_event ;switch pressed/released
rjmp switch_event
;**************************************************************************
;*
;* Idle timeout functions
;*
;**************************************************************************
; Disable fast adjustment mode unless key held down
idle: mov A,idle_tmr_lo
cpi A,200*1000/1024 ;about 200ms expired?
brlo id0 ;skip if not
cbr cflags,1<<fast_run|1<<fast_adj ;else disable fast adjust mode
; Save vol to eeprom & turn off display flash after 1 idle secs
id0: mov A,idle_tmr_hi
cpi A,high(1*1000000/1024) ;about 1s expired?
brlo id4 ;skip idle stuff if not
sbrc cflags,dirty_bit ;skip if already saved eeprom
rcall save_vol ;else do it
cbr bflags,1<<d_flash ;turn off display flash
; Exit balance/channel modes after 4 idle secs
cpi A,high(4*1000000/1024) ;about 4s expired?
brne id3
sbrc cflags,b_mode
rjmp id2 ;balance mode...
id1: sbrs cflags,c_mode ;channel mode
rjmp id4 ;skip if not
id2: rcall get_display_vol ;revert to volume display
rjmp id4
; Blank display (if enabled) after 8 idle secs
id3: cpi A,high(8*1000000/1024)
brne id4 ;skip unless 8s expired
sbrc bflags,d_blank ;skip if not already blanked
rjmp id4
ldi ZL,low(ee_blank)
ldi ZH,high(ee_blank)
rcall ee_read ;get blanking option
cpi A,CH_1 ;key code *1* enables blanking...
brne id4
rcall display_clear ;blank the display
sbr bflags,1<<d_blank ;flag it
id4: sbr aflags,1<<wd_res ;watchdog keep-alive
rjmp mn1 ;loop
;**************************************************************************
;*
;* Rotary encoder event
;*
;**************************************************************************
rotary_event:
cbr aflags,1<<rot_event
cbr bflags,1<<d_flash ;turn off display flash
sbrc cflags,c_mode
rjmp re2 ;channel select mode
rcall unmute_all ;exit mute mode if muted
sbrc cflags,b_mode
rjmp re1 ;balance mode
; Volume adjustment mode
sbrs aflags,rot_dir
rjmp volume_down
rjmp volume_up
; Balance adjustment mode
re1: ldi D,panr
sbrs aflags,rot_dir
ldi D,panl
rjmp pan_lr
; Channel selection mode
re2: ldi D,chup
sbrs aflags,rot_dir
ldi D,chdn
rjmp ch_select
;**************************************************************************
;*
;* Infrared remote event
;*
;**************************************************************************
infra_event:
cbr aflags,1<<ir_event
cbr bflags,1<<d_flash ;turn off display flash
ldi ZL,low(ee_ir_sys)
ldi ZH,high(ee_ir_sys)
rcall ee_read ;get programmed address
mov B,ir_code
andi B,$7F ;remove the toggle bit
cp A,ir_sys ;our address?
breq ie1 ;go if it is
; Check for TV *punch-through* mute
tst ir_sys ;address 0 (TV1)?
brne ie10 ;ignore code if not
mov B,ir_code ;get received code again
andi B,$7F
cpi B,MUTE_TV1 ;is it a punch-through mute?
breq ie3 ;go mute if it is
rjmp ie10 ;else not for us
ie1: cpi B,MUTE_TV1 ;mute/unmute?
breq ie3
; Check for alternate *mute* keys in TV & CD modes
cpi A,TV_ADDR ;TV code?
brne ie2
cpi B,MUTE_ALT1 ;alternate *mute*?
breq ie3
rjmp ie4 ;no, go check other
ie2: cpi A,CD_ADDR ;CD code?
brne ie4 ;no, skip next bit
cpi B,MUTE_ALT2 ;yes, alternate *mute* key?
brne ie4 ;go check other functions if not
; Mute code received, check if repeat
ie3: rcall flash_led ;flash the *ack* LED
sbrs aflags,ir_rpt ;ignore if a repeat code
rjmp mute_toggle
rjmp ie10
; Enable *fast adjust* mode if key is held down for >1 sec
ie4: sbrs cflags,fast_run ;skip if timer is already running
rjmp ie5 ;else go start it
sbrs aflags,ir_rpt ;continue if repeat of last key
rjmp ie5 ;else go restart timer
mov A,fast_tmr_hi
cpi A,high(1*1000000/1024) ;about 1s expired?
brne ie6 ;continue if not
sbr cflags,1<<fast_adj ;else flag fast adjust mode
rjmp ie6
ie5: clr fast_tmr_lo ;zero fast adjust timer
clr fast_tmr_hi
sbr cflags,1<<fast_run
ie6: rcall flash_led ;flash the *ack* LED
; Not mute, keep looking...
cpi B,VOL_UP
brne ie7
rcall unmute_all ;exit mute mode if muted
rjmp volume_up ;vol up
ie7: cpi B,VOL_DN
brne ie8
rjmp volume_down ;vol down
ie8: cpi B,CH_1 ;channel selection, check valid (1-6)
brlo ie9
cpi B,CH_6+1
brsh ie9
ldi D,chset
rjmp ch_select
ie9: sbrc cflags,v_mute
rjmp ie10 ;ignore other codes in mute mode
ldi D,panr
cpi B,CH_UP
breq pan_lr_ir ;balance right
ldi D,panl
cpi B,CH_DN
breq pan_lr_ir ;balance left
ie10: rjmp idle ;ignore
;**************************************************************************
;*
;* Front panel switch event
;*
;**************************************************************************
switch_event:
cbr bflags,1<<sw_event
sbrs bflags,sw_stat ;continue if switch press
rjmp se3 ;ignore releases...
lds A,sw_code
cpi A,1<<bal_sw ;balance or channel switches?
brne se1
; Toggle balance adjust/display mode
sbrc cflags,v_mute
rjmp se3 ;ignore balance switch if in mute mode
sbrc cflags,b_mode ;skip if not already in balance mode
rjmp se2 ;else go exit mode
rcall display_bal ;enter balance adjust/display mode
rjmp se3
; Toggle channel adjust/display mode
se1: sbrc cflags,c_mode ;skip if not in channel mode
rjmp se2 ;else go exit mode
rcall display_ch
rjmp se3
se2: rcall get_display_vol ;exit balance/channel mode, display volume
se3: rjmp main
;**************************************************************************
;*
;* Balance left/right
;*
;**************************************************************************
pan_lr_ir:
sbrs cflags,b_mode ;skip if already in balance mode
rjmp plr8 ;else just display (first press)
pan_lr:
rcall get_vol ;get volume for current channel
cpi D,panr
breq plr1
; Pan left
sbrc C,lr_offset ;skip if left attenuated
rjmp plr4
rjmp plr2
; Pan right
plr1: sbrs C,lr_offset ;skip if right attenuated
rjmp plr4
plr2: tst B ;zero offset?
brne plr6
plr3: ldi D,1<<lr_offset
eor C,D ;switch direction...
plr4: inc B ;increase left/right attenuation
breq plr5 ;abort if already at max
sbrs cflags,fast_adj ;skip if fast adjust (1.5dB) mode
rjmp plr7 ;else go update
cpi B,254 ;at least two points from top?
brsh plr7 ;single step (0.5dB) if not
subi B,-2 ;for 3x (1.5dB) step
rjmp plr7
plr5: dec B
sbr bflags,1<<d_flash ;set to flash the display
rjmp plr8
plr6: dec B ;decrease right attenuation
sbrs cflags,fast_adj ;skip if fast adjust (1.5dB) mode
rjmp plr7 ;else go update
cpi B,2 ;at least two points from bottom?
brlo plr7 ;single step (0.5dB) if not
subi B,2 ;for 3x (1.5dB) step
plr7: rcall put_vol ;update volume
plr8: rcall display_bal
rjmp main ;done
;**************************************************************************
;*
;* Volume up
;*
;**************************************************************************
volume_up:
rcall get_vol
inc A ;increase volume
brne vu2
vu1: dec A ;already at max...
clr d_timer ;to synchronise the flash...
sbr bflags,1<<d_flash ;set to flash the display
rjmp vu5
vu2: sbic PINB,JP2 ;skip if set for 0.5dB adjustments
rjmp vu3 ;must be 1.5dB...
sbrs cflags,fast_adj ;skip if fast adjust (1.5dB) mode
rjmp vu4 ;else go update
vu3: cpi A,254 ;at least two points from top?
brsh vu4 ;single step (0.5dB) if not
subi A,-2 ;for 3x (1.5dB) step
vu4: rcall put_vol ;update volume
vu5: rcall get_display_vol
rjmp main ;done
;**************************************************************************
;*
;* Volume down
;*
;**************************************************************************
volume_down:
rcall get_vol
tst A
breq vd4 ;quit if already at min
vd1: dec A
sbic PINB,JP2 ;skip if 0.5dB adjustments
rjmp vd2 ;must be 1.5dB...
sbrs cflags,fast_adj
rjmp vd3
vd2: cpi A,2 ;at least two points from bottom?
brlo vd3 ;single step (0.5dB) if not
subi A,2 ;for 3x (1.5dB) step
vd3: rcall put_vol ;update volume
vd4: rcall get_display_vol
rjmp main ;done
;**************************************************************************
;*
;* Mute/unmute system
;*
;**************************************************************************
mute_toggle:
sbrs cflags,v_mute ;skip if currently muted...
rjmp mt1
rcall unmute_all ;restore volume level
rjmp mt2
mt1: rcall mute_all ;mute all PGAs
mt2: rjmp main
;**************************************************************************
;*
;* Channel selection
;*
;**************************************************************************
ch_select:
cbr cflags,1<<b_mode ;exit balance mode
cbi PORTA,PA0 ;ensure left *DP* bit is off
sbr cflags,1<<c_mode ;enter channel mode
mov A,B ;A=channel #
cpi D,chset
breq cs2
lds A,pga_ch ;get current channel
cpi D,chdn
breq cs1 ;go if channel down
inc A ;must be channel up...
rjmp cs2
cs1: dec A
tst A
breq cs4 ;ch #1 is min
cs2: lds B,pga_cnt ;get number of actual channels
cp B,A
brlo cs4 ;ignore if exceeds actual
cs3: sts pga_ch,A ;else update as current
rcall save_ch ;save in EEPROM
cs4: lds A,pga_ch
rcall display ;display channel number (Cn)
rjmp main ;done
; Subroutines start here...
;**************************************************************************
;*
;* Save current channel to EEPROM
;*
;* Entry: pga_ch = current channel (1-6)
;*
;**************************************************************************
save_ch:
ldi ZL,low(ee_ch) ;channel # in EEPROM
ldi ZH,high(ee_ch)
lds A,pga_ch
rcall ee_write ;save current channel #
ret
;**************************************************************************
;*
;* Save current left & right channel volume to EEPROM
;*
;* Entry: pga_ch = current channel (1-6)
;*
;**************************************************************************
save_vol:
ldi XL,low(vol_data) ;vol data in RAM
ldi XH,high(vol_data)
lds A,pga_ch
dec A
mov B,A
lsl A ;entries are 3 bytes long...
add A,B
add XL,A
clr B
adc XH,B
ldi ZL,low(ee_vol) ;vol data in EEPROM
ldi ZH,high(ee_vol)
add ZL,A
adc ZH,B
ld A,X+
rcall ee_write ;save volume
adiw ZH:ZL,1
ld A,X+
rcall ee_write ;save offset
adiw ZH:ZL,1
ld A,X+
rcall ee_write ;save flags
cbr cflags,1<<dirty_bit
ret
;**************************************************************************
;*
;* Restore volume & channel data from EEPROM
;*
;**************************************************************************
restore_vol:
ldi ZL,low(ee_ch) ;vol data in EEPROM
ldi ZH,high(ee_ch)
rcall ee_read
sts pga_ch,A ;becomes current channel
ldi XL,low(vol_data) ;put vol data here
ldi XH,high(vol_data)
lds B,pga_cnt ;number of PGAs installed
rv1: adiw ZH:ZL,1
rcall ee_read
st X+,A ;copy vol data
adiw ZH:ZL,1
rcall ee_read
st X+,A ;copy offset data
adiw ZH:ZL,1
rcall ee_read
st X+,A ;copy channel flags
dec B
brne rv1 ;do for all channels (PGAs)
ret
;**************************************************************************
;*
;* Mute all channels
;*
;**************************************************************************
mute_all:
sbr cflags,1<<v_mute
cbi PORTB,pga_mute ;mute local device
rcall write_pga ;write to PGAs
rcall get_display_vol
ret
;**************************************************************************
;*
;* Unmute all channels
;*
;**************************************************************************
unmute_all:
sbrs cflags,v_mute
rjmp um1
cbr cflags,1<<v_mute ;reset muted flag
rcall write_pga ;write to PGAs
cbi PORTA,PA5 ;ensure right *DP* bit is off
sbi PORTB,pga_mute ;release local MUTE pin
rcall get_display_vol
um1: ret
;**************************************************************************
;*
;* Display balance level
;*
;**************************************************************************
display_bal:
cbr cflags,1<<c_mode ;exit channel mode
sbr cflags,1<<b_mode ;enter balance mode
rcall get_vol
cpi B,2
breq db1
cpi B,1
breq db1
cpi B,0
brne db4
ldi C,$0A
ldi A,$0A
rjmp db3 ;display *--*
db1: sbrc C,lr_offset
rjmp db2
ldi C,$0C
ldi A,$0A
rjmp db3 ;display * -*
db2: ldi C,$0A
ldi A,$0C ;display *- *
db3: rcall disp_raw
rjmp db5
db4: mov A,B ;get offset
rcall dpv1
db5: ret
;**************************************************************************
;*
;* Display channel number
;*
;**************************************************************************
display_ch:
cbr cflags,1<<b_mode ;may be in balance mode so exit
cbi PORTA,PA0 ;ensure left *DP* bit is off
sbr cflags,1<<c_mode ;enter channel mode
lds A,pga_ch ;get current channel
rcall display ;and display it
ret
;**************************************************************************
;*
;* Get and display volume
;*
;* Retrieves the volume for the currently selected PGA and displays it.
;*
;**************************************************************************
get_display_vol:
rcall get_vol ;fall thru to display_vol
;**************************************************************************
;*
;* Display volume (input range is 0-255, display range is 0-85)
;*
;* Input: A = volume
;*
;**************************************************************************
display_vol:
cbr cflags,1<<b_mode|1<<c_mode ;exit *balance* or *channel* modes
cbi PORTA,PA0 ;ensure left *DP* bit is off
dpv1: push B
mov B,A
rcall divide_by_3 ;returns A = B/3
rcall display ;display it
pop B
ret
;**************************************************************************
;*
;* Get volume (from buffer)
;*
;* Exit: A = volume (0-255) for current pga_ch
;* B = offset (0-255)
;* C = vflags
;*
;**************************************************************************
get_vol:
ldi ZL,low(vol_data) ;vol data in RAM
ldi ZH,high(vol_data)
lds A,pga_ch
dec A
mov B,A
lsl A ;entries are 3 bytes long...
add A,B
add ZL,A
clr B
adc ZH,B
ld A,Z+ ;volume
ld B,Z+ ;offset
ld C,Z+ ;flags
ret
;**************************************************************************
;*
;* Put volume (in buffer) & write to PGAs
;*
;* Entry: A = volume (0-255) for current pga_ch
;* B = offset (0-255)
;* C = vflags
;*
;**************************************************************************
put_vol:
ldi ZL,low(vol_data) ;vol data in RAM
ldi ZH,high(vol_data)
push A
push B
lds A,pga_ch
dec A
mov B,A
lsl A ;entries are 3 bytes long...
add A,B
add ZL,A
clr B
adc ZH,B
pop B
pop A
st Z+,A ;volume
st Z+,B ;offset
st Z+,C ;flags
rcall write_pga ;update PGAs
sbr cflags,1<<dirty_bit ;not saved yet...
ret
;**************************************************************************
;*
;* Determine number of connected PGAs
;*
;* Exit: C = PGA count
;*
;**************************************************************************
get_pga:
ldi ZL,low(spi_buff) ;spi data buffer
ldi ZH,high(spi_buff)
ldi B,24 ;tx + rx buffer size
clr A
gpg1: st Z+,A ;zero the buffer
dec B
brne gpg1
ldi ZL,low(spi_buff)
ldi ZH,high(spi_buff)
ldi A,1 ;for a single 16-bit transfer
sts pga_cnt,A
st Z+,A
ldi A,2
st Z+,A
clr C
gpg2: rcall spi_write ;write test data to the PGA(s)
ldd A,Z+10 ;get data read (left channel)
cpi A,1 ;equals write?
brne gpg3 ;skip if not
ldd A,Z+11 ;get data read (right channel)
cpi A,2
breq gpg4 ;go if match
gpg3: inc C
cpi C,7 ;tested for max PGAs?
brne gpg2 ;keep trying if not
clr C
gpg4: sts pga_cnt,C ;set number connected
ret
;**************************************************************************
;*
;* Format spi buffer with volume data & initiate write
;*
;**************************************************************************
write_pga:
ldi XL,low(vol_data) ;vol data in RAM
ldi XH,high(vol_data)
ldi ZL,low(spi_buff) ;spi data buffer
ldi ZH,high(spi_buff)
lds A,pga_cnt
wp1: push A
ld A,X+ ;left vol
mov B,A ;right vol
ld C,X+ ;offset
ld D,X+ ;vflags
tst A
breq wp3 ;zero offset
sbrs D,lr_offset
rjmp wp2
; Panned left, so subtract offset from right channel
sub B,C
brcc wp3
clr B
rjmp wp3
; Panned right, so subtract offset from left channel
wp2: sub A,C
brcc wp3
clr A
; Now ignore all of that if muted...
wp3: sbrs cflags,v_mute
rjmp wp4
clr A
clr B
wp4: st Z+,A ;left vol to spi_buff
st Z+,B ;right vol to spi_buff
pop A
dec A
brne wp1
;**************************************************************************
;*
;* Initiate spi transfer & wait until done
;*
;**************************************************************************
spi_write:
sbr aflags,1<<spi_req ;initiate the write
spi1: sbrc aflags,spi_req
rjmp spi1 ;wait till done
ret
;**************************************************************************
;*
;* 7-segment display write
;*
;* Entry: A = data to display
;*
;**************************************************************************
; Convert input to BCD in C,A
display:
clr C ;becomes tens
ds1: subi A,10
brcs ds2
inc C ;bump MSD
rjmp ds1
ds2: subi A,-10 ;adjust units
; Lookup *units* 7-seg bit pattern
disp_raw:
ldi ZH,high(units_table*2) ;units lookup table
ldi ZL,low(units_table*2)
lsl A ;for 2-byte entries
add ZL,A ;input is index
clr A
adc ZH,A
.if !debug
lpm A,Z+ ;get port C...
lpm B,Z ;...and port A bit patterns
.else
cli ;R0 is used by interrputs!
lpm ;get port C...
adiw ZH:ZL,1
mov A,R0
lpm ;...and port A bit patterns
mov B,R0
sei
.endif
; Display *C* in the tens position in channel select mode
sbrc cflags,c_mode
ldi C,$0B ;offset to *C* pattern
; Lookup *tens* 7-seg bit pattern
ldi ZH,high(tens_table*2) ;tens lookup table
ldi ZL,low(tens_table*2)
lsl C ;for 2-byte entries
add ZL,C ;input is index
clr C
adc ZH,C
; Merge the bit patterns and write to ports A & C
.if !debug
lpm C,Z+ ;get port C *tens* bits
.else
cli ;R0 is used by interrputs!
lpm
adiw ZH:ZL,1
mov C,R0
sei
.endif
or A,C ;merge with *units* bits
.if !debug
lpm C,Z ;get port A *tens* bits
.else
cli
lpm
mov C,R0
sei
.endif
or B,C ;merge with *units* bits
ds3: out PORTC,A ;write the results...
in A,PORTA
andi A,0b00100001 ;keep *DP* bits
or A,B
out PORTA,A
cbr bflags,1<<d_blank ;not blanked!
ret
;**************************************************************************
;*
;* 7-segment display clear
;*
;**************************************************************************
display_clear:
clr A
out PORTC,A ;write zeros to blank
out PORTA,A
ret
;**************************************************************************
;*
;* Fixed 8-bit divide-by-3
;*
;* Entry: B = hex byte
;* Exit: A = dividend, B = remainder
;* Uses: C,D
;*
;**************************************************************************
divide_by_3:
clr A
ldi D,3*16
rcall dv1
ldi D,3
dv1: ldi C,-1
dv2: sub B,D
inc C
brcc dv2
add B,D
swap A
or A,C
ret
;**************************************************************************
;*
;* Wait for infrared code
;*
;**************************************************************************
wait_ir:
sbrs aflags,ir_event
rjmp wait_ir
cbr aflags,1<<ir_event
sbrc aflags,ir_rpt
rjmp wait_ir ;ignore if repeat code
ret
;**************************************************************************
;*
;* Flash LED *B* times
;*
;**************************************************************************
flash_it:
rcall flash_led
fi1: sbic PIND,ack_led
rjmp fi1 ;wait for LED off
ldi A,250
rcall delay ;delay for about 250ms
dec B
brne flash_it
ret
;**************************************************************************
;*
;* Flash LED
;*
;**************************************************************************
flash_led:
push A
ldi A,50 ;about 50ms on time
sts led_timer,A
sbi PORTD,ack_led ;switch LED on
pop A
ret
;**************************************************************************
;*
;* Timed delay
;*
;**************************************************************************
delay:
sts led_timer,A
dy1: lds A,led_timer
tst A
brne dy1 ;A * 1.024ms
ret
;**************************************************************************
;*
;* Initialise EEPROM
;*
;**************************************************************************
init_eeprom:
ldi ZL,low(ee_ir_sys)
ldi ZH,high(ee_ir_sys)
ldi A,0
rcall ee_write ;default infrared address
adiw ZH:ZL,1
ldi A,1
rcall ee_write ;default channel
adiw ZH:ZL,1
clr A
ldi B,3*6
ine1: rcall ee_write ;zero vol data for all channels
adiw ZH:ZL,1
dec B
brne ine1
ldi ZL,low(ee_magic) ;write magic number
ldi ZH,high(ee_magic)
ldi A,$5A
rcall ee_write
ret
;**************************************************************************
;*
;* EEPROM random read/write routines
;*
;* Entry: Z = address, A = data (writes)
;* Exit : A = data (reads)
;*
;**************************************************************************
ee_read:
sbic EECR,EEWE
rjmp ee_read ;loop until last cycle complete
out EEARL,ZL ;write address
out EEARH,ZH
sbi EECR,EERE ;set read strobe
in A,EEDR ;get data
ret
ee_write:
sbic EECR,EEWE
rjmp ee_write ;loop until last cycle complete
out EEARL,ZL ;write address
out EEARH,ZH
out EEDR,A ;write data
cli ;interrupts off for the next bit...
sbi EECR,EEMWE ;set master write enable
sbi EECR,EEWE ;set write strobe
sei
ret
;**************************************************************************
;*
;* Timer/counter 0 overflow interrupt handler
;*
;* Tick interval is 32us (1/fOSC x 128)
;*
;**************************************************************************
tmr0_irq:
in status,SREG ;save state
push A ;save used global
push B
push ZH
push ZL
ldi A,128 ;reload timer 0 up count
out TCNT0,A
;**************************************************************************
;* Do 32us tasks
;**************************************************************************
rcall spi_io ;serial i/o
inc irate_tmr
sbrs irate_tmr,0
rjmp tq1
;**************************************************************************
;* Do 64us tasks (interleaved to reduce overhead)
;**************************************************************************
rcall infrared ;infrared receive state machine
rjmp tq7 ;exit
tq1:
rcall switch ;switch input
rcall rotary ;rotary encoder input
;**************************************************************************
;* Do 1.024ms tasks
;**************************************************************************
tq2: mov A,irate_tmr
cpi A,32 ;32 * 32us = 1.024ms
brne tq7
clr irate_tmr ;reset timer
lds A,led_timer
dec A
sts led_timer,A
brne tq3
cbi PORTD,ack_led ;switch LED off
tq3: inc idle_tmr_lo ;idle timer
brne tq4
inc idle_tmr_hi
tq4: inc fast_tmr_lo ;*fast adjust* timer
brne tq5
inc fast_tmr_hi
tq5: dec sw_timer ;switch filter timer
dec d_timer ;display flash timer
brne tq6
rcall flash
tq6: sbrs aflags,wd_res ;keep-alive set?
rjmp tq7
cbr aflags,1<<wd_res
wdr ;kick the *dog
tq7: pop ZL ;restore used registers
pop ZH
pop B
pop A
out SREG,status ;and flags
reti
;**************************************************************************
;*
;* Flash display
;*
;**************************************************************************
flash:
sbrc bflags,d_state ;skip if not currently blanked
rjmp fl2 ;blanked, so go restore
sbrc bflags,d_flash ;skip if flash not enabled
rjmp fl1 ;else go flash
sbrc cflags,v_mute
rjmp fl0 ;go if muted
sbrs cflags,b_mode ;skip if in *balance* mode
rjmp fl3 ;else quit
; Toggle the left *DP* bit (indicates *balance* mode)
in A,PORTA
ldi B,0b00000001
eor A,B ;toggle left *DP*
out PORTA,A
rjmp fl3
; Toggle the right *DP* bit (indicates muted)
fl0: in A,PORTA
ldi B,0b00100000
eor A,B ;toggle right *DP*
out PORTA,A
rjmp fl3
; Blank the display
fl1: in A,PORTC ;save port state
sts d_portc,A
in A,PORTA
sts d_porta,A
clr A
out PORTC,A ;now write zeros to blank
out PORTA,A
sbr bflags,1<<d_state ;flag blanked
rjmp fl3
; Restore the display
fl2: lds A,d_portc
out PORTC,A
lds A,d_porta
out PORTA,A
cbr bflags,1<<d_state
fl3: ret
;**************************************************************************
;*
;* Switch input
;*
;**************************************************************************
switch:
.if !debug
in A,PINE ;get port state
.else
in A,PIND ;get port state
.endif
sbrs bflags,sw_run ;filter running?
rjmp ss2 ;go check for switch press if not
lds B,sw_code
and A,B ;switch open or closed?
breq ss4 ;go reset timer if closed
ss1: tst sw_timer ;check if timer expired
brne ss5 ;exit if not
cbr bflags,1<<sw_run|1<<sw_stat
sbr bflags,1<<sw_event
rjmp ss5
ss2: ldi B,1<<ch_sw
and A,B
breq ss3 ;switch down
.if !debug
in A,PINE
.else
in A,PIND
.endif
ldi B,1<<bal_sw
and A,B
brne ss5 ;both switches up
ss3: sts sw_code,B ;save the switch code
sbr bflags,1<<sw_run|1<<sw_stat|1<<sw_event ;start filter & flag press
ss4: ldi A,30 ;30ms debounce timer
mov sw_timer,A
ss5: ret
;**************************************************************************
;*
;* Rotary encoder input
;*
;* The effects of contact bounce are eliminated by qualifying
;* the operation of one switch against the other, as follows:
;*
;* Set rot_f1 when A=0 & B=0, clear when A=1 & B=1
;* Set rot_f2 when A=1 & B=0, clear when A=0 & B=1
;*
;* Trailing edge of rot_f1 sets rot_event, rot_f2 = rot_dir
;*
;* NOTE: requires an encoder mechanism of equal cycles & detents!
;*
;**************************************************************************
rotary:
in A,PIND
andi A,1<<rot_a|1<<rot_b
brne rs1
; A=0 & B=0
sbrc aflags,rot_f1
rjmp rs4
bst aflags,rot_f2 ;becomes direction bit
bld aflags,rot_dir
sbr aflags,1<<rot_f1|1<<rot_event
rjmp rs4
rs1: cpi A,1<<rot_a|1<<rot_b
brne rs2
; A=1 & B=1
cbr aflags,1<<rot_f1
rjmp rs4
rs2: cpi A,1<<rot_a
brne rs3
; A=1 & B=0
sbr aflags,1<<rot_f2
rjmp rs4
; A=0 & B=1
rs3: cbr aflags,1<<rot_f2
rs4: ret
;**************************************************************************
;*
;* SPI state machine
;*
;**************************************************************************
; Start (resume) transfer in the correct state
spi_io:
ldi ZH,high(spi_jmp_tbl)
ldi ZL,low(spi_jmp_tbl)
add ZL,spi_state ;state number becomes index
clr A
adc ZH,A ;find the correct fragment
ijmp ; and execute it
spi_jmp_tbl:
rjmp spi_s0
rjmp spi_s1
rjmp spi_s2
rjmp spi_s3
;**************************************************************************
;
; SPI State 0
;
; Wait for foreground request, then initialise
;
;**************************************************************************
spi_s0:
sbrs aflags,spi_req ;skip if transfer request
rjmp s0_0 ;else just exit
lds A,pga_cnt ;# of PGAs on the bus
mov spi_cnt,A ;words to transfer
ldi YL,low(spi_buff) ;data buffer
ldi YH,high(spi_buff)
lsl A ;x2 to get byte count
add YL,A ;add as offset to send high word(s) first
clr A
adc YH,A
ldi spi_bits,16 ;init word size
ld spi_pipe_hi,-Y ;load the pipe - right channel
ld spi_pipe_lo,-Y ; - left channel
cbi PORTB,sck ;clock low
sbi DDRB,sck ;make clock & data lines outputs
sbi DDRB,sdo
inc spi_state ;to state #1
s0_0: ret
;**************************************************************************
;
; SPI State 1
;
; Write data to bus, clock low [pga-->]
;
;**************************************************************************
spi_s1:
cbi PORTB,sck ;clock low
cbi PORTD,pga_cs ;assert pga chip select (first cycle)
lsl spi_pipe_lo
rol spi_pipe_hi ;msb first
brcc s1_0
sbi PORTB,sdo ;data line high
rjmp s1_1
s1_0: cbi PORTB,sdo ;data line low
s1_1: inc spi_state ;to state #2
ret
;**************************************************************************
;
; SPI State 2
;
; Read data from bus, clock high [-->pga]
;
;**************************************************************************
spi_s2: sbis PINB,sdi ;skip if data input low
rjmp s2_0
ldi A,1
or spi_pipe_lo,A ;high, so set lsb
s2_0: sbi PORTB,sck ;clock high
dec spi_bits ;done 16 bits?
brne s2_2 ;continue if not
std Y+13,spi_pipe_hi ;save received word
std Y+12,spi_pipe_lo
dec spi_cnt ;done all pgas?
brne s2_1 ;more to do...
inc spi_state ;else bump to state #3
rjmp s2_3
s2_1: ldi spi_bits,16 ;reload word size
ld spi_pipe_hi,-Y ;and pipe - right channel
ld spi_pipe_lo,-Y ; - left channel
s2_2: dec spi_state ;loop back to state #1
s2_3: ret
;**************************************************************************
;
; SPI State 3
;
; End transfer
;
;**************************************************************************
spi_s3: cbi PORTB,sck ;clock low
rjmp s3_0 ;waste a cycle or two...
s3_0: sbi PORTD,pga_cs ;deassert pga chip select
cbi DDRB,sck ;clock & data bits to inputs
cbi DDRB,sdo
sbi PORTB,sck ;enable pullups
sbi PORTB,sdo
cbr aflags,1<<spi_req ;transfer done, clear request bit
clr spi_state
ret
;**************************************************************************
;*
;* Infrared receive state machine (must be called every 64us)
;*
;**************************************************************************
infrared:
sbrs bflags,sw_run ;switch press will pull ir_rxd low...
rjmp ix0 ;continue if not pressed
clr ir_state ;switch pressed, reset state
ret ;and exit
ix0: inc ir_timer ;bump ir protocol (bit) timer
; Start (resume) ir decode in the correct state
ldi ZH,high(rc5_jmp_tbl)
ldi ZL,low(rc5_jmp_tbl)
add ZL,ir_state ;state number becomes index
clr A
adc ZH,A ;find the correct fragment
ijmp ; and execute it
rc5_jmp_tbl:
rjmp rc5_s0
rjmp rc5_s1
rjmp rc5_s2
rjmp rc5_s3
rjmp rc5_s4
rjmp rc5_s5
rjmp rc5_s6
rjmp rc5_s7
;**************************************************************************
;
; RC5 State 0
;
; Wait for line idle (high)
;
;**************************************************************************
rc5_s0:
.if debug
sbis PIND,ir_rxd ;wait for line high
.else
sbis PINE,ir_rxd ;wait for line high
.endif
rjmp exit_state
clr ir_timer ;init timer
rjmp next_state ;move to state 1 & exit
;**************************************************************************
;
; RC5 State 1
;
; Establish line is idle (high) for 5ms before waiting for a start bit
;
;**************************************************************************
rc5_s1:
.if debug
sbis PIND,ir_rxd ;skip if line high
.else
sbis PINE,ir_rxd ;skip if line high
.endif
rjmp reset_state ;else reset & exit
cpi ir_timer,78 ;idle high for 5ms?
brlo r1_0 ;keep waiting if not
rjmp next_state ;else move to state 2 & exit
r1_0: rjmp exit_state
;**************************************************************************
;
; RC5 State 2
;
; Wait (forever) for start bit
;
;**************************************************************************
rc5_s2:
.if debug
sbic PIND,ir_rxd ;skip if start bit detected
.else
sbic PINE,ir_rxd ;skip if start bit detected
.endif
rjmp exit_state
r2_0: clr ir_timer ;init timer
rjmp next_state ;move to state 3 & exit
;**************************************************************************
;
; RC5 State 3
;
; Wait for rising edge of first start bit
;
;**************************************************************************
rc5_s3:
.if debug
sbis PIND,ir_rxd ;skip if line returned high
.else
sbis PINE,ir_rxd ;skip if line returned high
.endif
rjmp r3_0 ;else go check for timeout
clr ir_timer ;init timer
rjmp next_state ;move to state 4 & exit
r3_0: cpi ir_timer,31 ;more than 2ms?
brlo exit_state ;exit to keep sampling
rjmp reset_state ;else reset
;**************************************************************************
;
; RC5 State 4
;
; Wait for trailing edge of second start bit to synchronise timing
;
;**************************************************************************
rc5_s4:
.if debug
sbic PIND,ir_rxd ;skip when line goes low
.else
sbic PINE,ir_rxd ;skip when line goes low
.endif
rjmp r4_0 ;else go check for timeout
ldi A,12 ;init bit count
mov ir_bit_cnt,A
clr ir_sys ;zero the bit store
clr ir_cmd
clr ir_timer ;init timer
rjmp next_state ;more to state 5 & exit
r4_0: cpi ir_timer,31 ;more than 2ms?
brlo r4_1 ;skip to keep sampling
rjmp reset_state ;timeout, reset
r4_1: rjmp exit_state
;**************************************************************************
;
; RC5 State 5
;
; Sample the line at 1/4 bit time and store result
;
;**************************************************************************
rc5_s5:
cpi ir_timer,21 ;3/4 bit time from last edge (1.34ms)?
brlo r5_1 ;keep waiting if not
inc ir_state ;assume will be low, next state = 6
.if debug
sbic PIND,ir_rxd ;skip if sampled low
.else
sbic PINE,ir_rxd ;skip if sampled low
.endif
rjmp r5_2
clc ;to shift in a low bit
r5_0: rol ir_cmd
rol ir_sys
clr ir_timer ;init timer
r5_1: rjmp exit_state
r5_2: inc ir_state ;sampled high, next state = 7
sec
rjmp r5_0 ;go shift in the high bit
;**************************************************************************
;
; RC5 State 6
;
; Bit was a low, so wait for rising edge to syncronize timing
;
;**************************************************************************
rc5_s6:
.if debug
sbis PIND,ir_rxd ;skip if sampled high
.else
sbis PINE,ir_rxd ;skip if sampled high
.endif
rjmp r6_3 ;else go check for timeout
r6_0: dec ir_bit_cnt ;done all bits?
brne r6_2 ;not yet...
mov A,ir_cmd ;get all the bits...
rol A
rol ir_sys ;...in the right places
rol A
rol ir_sys
bst ir_sys,5 ;move toggle bit...
bld ir_cmd,7 ;to command byte MSB
clt
bld ir_sys,5
bld ir_cmd,6 ;clear unused bits
cbr aflags,1<<ir_rpt
cp ir_code,ir_cmd ;same code as last time?
brne r6_1 ;skip if not
sbr aflags,1<<ir_rpt ;else flag key repeat
r6_1: mov ir_code,ir_cmd
sbr aflags,1<<ir_event ;mail to the foreground
rjmp reset_state ;reset machine & exit
r6_2: ldi A,5 ;more to do
mov ir_state,A ;loop back to get another bit
clr ir_timer
rjmp exit_state
r6_3: cpi ir_timer,35 ;5/4 bit time from edge (2.2ms)?
brlo exit_state ;keep sampling if not
rjmp reset_state ;else timeout waiting for middle edge
;**************************************************************************
;
; RC5 State 7
;
; Bit was a high, so wait for falling edge to syncronize timing
;
;**************************************************************************
rc5_s7:
.if debug
sbic PIND,ir_rxd ;skip if sampled low
.else
sbic PINE,ir_rxd ;skip if sampled low
.endif
rjmp r6_3 ;else go check for timeout
rjmp r6_0
;**************************************************************************
; Common exit stuff...
next_state:
inc ir_state ;bump to next state
rjmp exit_state
reset_state:
clr ir_state ;reset machine
exit_state:
ret
;**************************************************************************
;**************************************************************************
;*
;* DATA
;*
;**************************************************************************
;**************************************************************************
; 7-segment display lookup table,
; organised as port C, port A.
units_table:
.db 0b00110100, 0b00011100 ;0
.db 0b00000100, 0b00001000 ;1
.db 0b00111000, 0b00001100 ;2
.db 0b00011100, 0b00001100 ;3
.db 0b00001100, 0b00011000 ;4
.db 0b00011100, 0b00010100 ;5
.db 0b00111100, 0b00010100 ;6
.db 0b00000100, 0b00001100 ;7
.db 0b00111100, 0b00011100 ;8
.db 0b00001100, 0b00011100 ;9
.db 0b00001000, 0b00000000 ;-
.db 0b00110000, 0b00010100 ;C
.db 0b00000000, 0b00000000 ;blank
tens_table:
.db 0b10000011, 0b11000010 ;0
.db 0b10000000, 0b01000000 ;1
.db 0b01000011, 0b11000000 ;2
.db 0b11000010, 0b11000000 ;3
.db 0b11000000, 0b01000010 ;4
.db 0b11000010, 0b10000010 ;5
.db 0b11000011, 0b10000010 ;6
.db 0b10000000, 0b11000000 ;7
.db 0b11000011, 0b11000010 ;8
.db 0b11000000, 0b11000010 ;9
.db 0b01000000, 0b00000000 ;-
.db 0b00000011, 0b10000010 ;C
.db 0b00000000, 0b00000000 ;blank
copyright:
.db "(C)2007 Silicon Chip Publications P/L",0
;**************************************************************************
;**************************************************************************
;*
;* DEFINE USED SRAM
;*
;**************************************************************************
;**************************************************************************
.dseg
d_porta: .byte 1 ;port A state save (see flash_display)
d_portc: .byte 1 ;port C state save
led_timer: .byte 1 ;led/delay timer (ms)
sw_code: .byte 1 ;switch input code
pga_cnt: .byte 1 ;number of pgas on the bus
pga_ch: .byte 1 ;current channel number
spi_buff: .byte 24 ;spi tx & rx buffer
vol_data: .byte 18 ;volume, offset & vflags array
; Stack top is at $25F (reserve 32 bytes)
;**************************************************************************
;**************************************************************************
;*
;* DEFINE USED EEPROM
;*
;**************************************************************************
;**************************************************************************
.eseg
.org 0
ee_start: .byte 1 ;reserved
ee_magic: .byte 1 ;magic number
ee_blank: .byte 1 ;display blanking select
ee_ir_sys: .byte 1 ;RC5 equipment address
ee_ch: .byte 1 ;last selected channel
ee_vol: .byte 6*3 ;volume, offset & vflags array
Вот исходник нашел к вашем проекту, времени разобраться пока нет.
Социальные закладки