;program name: upsd-7seg-test.asm ;author: Thomas Hoehn ;date: Nov/Dec 2006 ; ;description: ;programm for uPSD test board to drive 7-segment LED display over I2C bus with SAA1064 .title 7-segment display test .module upsd-7seg-test .radix x ;default radix hex ;program area code1, absolute address .area CODE (ABS,CSEG) ;SFR Registers WDKEY == 0xAE ; Watchdog Key Register IE == 0xA8 ; Interrupt Enable Register IEA == 0xA7 ; Interrupt Enable All Register S2CON == 0xDC ; I2C Bus Control Register S2STA == 0xDD ; I2C Bus Status Register S2DAT == 0xDE ; I2C Data Hold Register S2ADR == 0xDF ; I2C Address Register ;Port definitions P3SFS == 0x93 P4SFS == 0x94 ; Port 4 SFS P4SFR == 0xC0 ; Port 4 IO SFR LED_PORT_SFS == P4SFS ; Status LED Port SFS LED_PORT_SFR == P4SFR ; Status LED Port SFR ;IE and IEA register interrrupt enable bit masks IE_EA == 0x80 ; Enable all interrupts IE_ET0 == 0x02 ; Enable Timer 0 interrupt IE_ET1 == 0x08 ; Enable Timer 1 interrupt IE_ET2 == 0x20 ; Enable Timer 2 interrupt IE_EX0 == 0x01 ; Enable external interrupt Int0 IE_EX1 == 0x04 ; Enable external interrupt Int1 IE_ES == 0x10 ; Enable USART interrupt IEA_ES2 == 0x10 ; Enable USART2 interrupt IEA_EI2C == 0x02 ; Enable I2C interrupt IEA_EUSB == 0x01 ; Enable USB interrupt IEA_EDDC == 0x80 ; Enable DDC interrupt ;Port 3 SFS bitmasks P3SFS_SCL == 0x80 ; Enable SCL for I2C, disable Port 3.7 GPIO P3SFS_SDA == 0x40 ; Enable SDA for I2C, disable Port 3.6 GPIO ;I2C control register bit masks SxCON_CR2 == 0x80 ; SxCON CR bit (determine clock frequency) SxCON_ENI == 0x40 ; SxCON ENII bit (enable I2C) SxCON_STA == 0x20 ; SxCON STA bit (generate START condition) SxCON_STO == 0x10 ; SxCON STO bit (generate STOP condition) SxCON_AA == 0x04 ; SxCON AA bit (Acknowledge enable) SxCON_CR1 == 0x02 ; SxCON CR bit (determine clock frequency) SxCON_CR0 == 0x01 ; SxCON CR bit (determine clock frequency) ;I2C status register bit masks SxSTA_STOP == 0x40 ; SxSTA Stop flag SxSTA_INTR == 0x20 ; SxSTA Interrupt Flag SxSTA_TX == 0x10 ; SxSTA Transmission Mode Flag SxSTA_BBUSY == 0x08 ; SxSTA Bus Busy Flag SxSTA_BLOST == 0x04 ; SxSTA Bus Lost Flag SxSTA_ACK == 0x02 ; SxSTA Acknowledge Response Flag SxSTA_SLV == 0x01 ; SxSTA Slave Mode Flag ;status LED's bit masks OK_LED == 0x01 ; bit mask for green LED on Port 4.0 ERR_LED == 0x02 ; bit mask for red LED on Port 4.1 ;I2C address and buffer definitions SAA_SLAVE_ADR == 0x70 ; LED driver chip (SAA1064) I2C address ;first free ram address (after register banks and addressable bits) is 0x30 ;variables start there, stack from 0x40 I2C_XMIT_LEN == 0x30 ; I2C data buffer length I2C_XMIT_IDX == 0x31 ; I2C data buffer index I2C_XMIT_ADR == 0x32 ; I2C data buffer start ;I2C bus speed definitions I2C_SPEED1 == SxCON_CR0|SxCON_CR1|SxCON_CR2; f[OSC]-Divisor 960 (lowest speed), 21 KHz (OSC=20.480 MHz) I2C_SPEED2 == SxCON_CR1|SxCON_CR2 ; f[OSC]-Divisor 480, 43 KHz I2C_SPEED3 == SxCON_CR0|SxCON_CR2 ; f[OSC]-Divisor 240, 85 KHz I2C_SPEED4 == SxCON_CR2 ; f[OSC]-Divisor 120, 171 KHz (max. I2C speed with 20.480 Mhz quartz) I2C_SPEED5 == SxCON_CR0|SxCON_CR1 ; f[OSC]-Divisor 60, 341 KHz I2C_SPEED6 == SxCON_CR1 ; f[OSC]-Divisor 30, 683 KHz I2C_SPEED7 == SxCON_CR0 ; f[OSC]-Divisor 24, 853 KHz I2C_SPEED8 == 0x00 ; f[OSC]-Divisor 16 (highest speed), 1.28 Mhz ;I2C xmit done bit I2C_DONE == 0x00 ;LED brightness: 1 - normal ...7 - very bright (SAA1064 will heat up quickly!) LED_BRIGHT == 0x01 ;2 digit number to display on 7-segment display LED_DIGITS == 0x34 ;Stack Pointer address STACK_ADR == 0x40 .org 0x00 ; start at 0x00 after reset, before interrupt table reset:: sjmp start ; jump to programm code after interrupt table, global label ; interrupt table compromises 0x03-0x52 ;interrupt table start ;i2c_intr: .org 0x43 ajmp i2c_intr ;interrupt table end ;; main programm .org 0x053 ; programm code for LED control start: mov sp,#STACK_ADR ; init stackpointer mov WDKEY,#0x55 ; disable watchdog timer in WDKEY SFR mov IEA,#0 ; prepare I2C interrupt enable mov IE,#IE_EA ; enable only I2C interrupt ;reset status LED's (green on, red off) mov LED_PORT_SFS,#0x00 ; disable DDC function, activate GPIO for LED Port (Port 4) mov LED_PORT_SFR,#0x00 ; reset LED Port (Port 4) ;init I2C transmitt buffer with data to display mov a,#LED_DIGITS acall init_xmit_buffer ;acall init_xmit_test ;initialize I2C subsystem acall init_i2c ;wait until I2C operation is finished acall wait_i2c acall green_led_on ;stop/halt stop: sjmp stop ;stop with looping ;-) ;function: init_xmit_test() ;description: init I2C transmit buffer with data to switch all segments on for testing ;parameters: none ;return value: none init_xmit_test: ;initialize I2C xmit buffer mov I2C_XMIT_IDX,#0 mov I2C_XMIT_LEN,#0 mov r0,#I2C_XMIT_ADR ;1st data mov @r0,#0x00 ; SAA1064 instruction byte (SA-SC=0) inc r0 inc I2C_XMIT_LEN ;2nd data mov @r0,#0x1E inc I2C_XMIT_LEN ret ;function: init_xmit_buffer() ;description: init I2C transmit buffer ;parameters: register A holds the 2-digit number to display ;return value: none init_xmit_buffer: ;initialize I2C xmit buffer mov I2C_XMIT_IDX,#0 mov I2C_XMIT_LEN,#0 mov r0,#I2C_XMIT_ADR ;1st data mov @r0,#0x00 ; SAA1064 instruction byte (SA-SC=0) inc r0 inc I2C_XMIT_LEN ;2nd data mov @r0,#(((LED_BRIGHT << 4) & 0x70) | 0x06) ; SAA1064 control register value inc r0 inc I2C_XMIT_LEN ;3rd data mov r1,a ; temp register for A swap a ; write high nibble digit anl a,#0x0F acall digit_to_led_bits mov @r0,a inc r0 inc I2C_XMIT_LEN ;4th data mov a,r1 ; write low nibble digit anl a,#0x0F acall digit_to_led_bits mov @r0,a inc I2C_XMIT_LEN ret ;function: init_i2c() ;description: initialize (enable) I2C bus ;parameters: none ;return value: none init_i2c: ;enable I2C SDA and SCL on Port 3.6 and 3.7, disable GPIO orl P3SFS,#(P3SFS_SCL|P3SFS_SDA) ;init I2C_DONE bit clr I2C_DONE ;enable I2C bus, no start/stop bit, mid frequency (CR0,CR1=1) mov S2CON,#(SxCON_ENI|I2C_SPEED4) ;send slave address (0x70) on I2C bus mov S2DAT,#SAA_SLAVE_ADR ;check if bus is used by another master (BBUSY) mov A,S2STA anl A,#SxSTA_BBUSY acall err_if_nz ;set start flag orl S2CON,#SxCON_STA ;check if I2C is slave mov A,S2STA anl A,#SxSTA_SLV acall err_if_nz ;check if bus is lost mov A,S2STA anl A,#SxSTA_BLOST acall err_if_nz ;enable I2C interrupt orl IEA,#IEA_EI2C ret ;function: wait_i2c() ;description: finish I2C data transmission (wait until I2C_DONE bit is set) ;parameters: none ;return value: none wait_i2c: ;wait until I2C data is sent and interrupts are finished wait: jnb I2C_DONE,wait orl S2CON,#SxCON_STO ; set stop flag anl S2CON,#~SxCON_ENI ; disable I2C anl IEA,#~IEA_EI2C ; disable I2C interrupt ;indicate successful transmission with green led ;acall green_led_on ret ;function: i2c_intr() ;description: I2C interrupt service routine to send data over I2C bus ;parameters: none ;return value: none i2c_intr: ;check if I2C is a transmitter (TX_MODE) mov A,S2STA anl A,#SxSTA_TX acall err_if_zero ;check if bus is lost mov A,S2STA anl A,#SxSTA_BLOST acall err_if_nz ;check if ack was sent mov A,S2STA anl A,#SxSTA_ACK acall err_if_nz anl S2CON,#~SxCON_STA mov a,I2C_XMIT_IDX cjne a,I2C_XMIT_LEN,1$ setb I2C_DONE reti 1$: add a,#I2C_XMIT_ADR mov r0,a mov S2DAT,@r0 inc I2C_XMIT_IDX reti ;function: check_ack() ;switches error LED (red) on if receiver sent not acknowledge check_ack: mov A,S2STA anl A,#SxSTA_ACK acall err_if_nz ret ;function: err_if_nz() ;description: switch on error LED (red) if register A not null ;parameters: register A holds value to compare err_if_nz: jz 1$ orl LED_PORT_SFR,#ERR_LED ajmp stop 1$: ret ;function: err_if_zero() ;description: switch on error LED (red) if register A is null ;parameters: register A holds value to compare err_if_zero: jnz 1$ orl LED_PORT_SFR,#ERR_LED ajmp stop 1$: ret ;function: green_led_on() ;description: switch (green) OK LED on green_led_on: orl LED_PORT_SFR,#OK_LED ; switch on green OK LED (Port 4.0) ret ;function: green_led_off() ;description: switch (green) OK LED off green_led_off: anl LED_PORT_SFR,#(0xFF&~OK_LED) ; switch on green OK LED (Port 4.0) ret ;function: red_led_on() ;description: switch (red) ERR LED on red_led_on: orl LED_PORT_SFR,#ERR_LED ; switch on green OK LED (Port 4.1) ret ;function: red_led_off() ;description: switch (red) ERR LED off red_led_off: anl LED_PORT_SFR,#~ERR_LED ; switch on green OK LED (Port 4.1) ret ;function: digit_to_led_bits() ;description: returns the bit mask for 7-segment display to show LED digit ;parameters: low nibble (4 bits) of register A holds the digit ;return value: register A has the bit mask to switch on the ; correspondig segments on the 7-segment display digit_to_led_bits: mov dptr,#digit_seg_table movc a,@a+dptr ret ;table to translate digit to segment bit ;pattern meaningful to LED driver chip SAA1064 digit_seg_table: .byte 0b00111111 ;LED digit 0 .byte 0b00000110 ;LED digit 1 .byte 0b01011011 ;LED digit 2 .byte 0b01001111 ;LED digit 3 .byte 0b01100110 ;LED digit 4 .byte 0b01101101 ;LED digit 5 .byte 0b01111101 ;LED digit 6 .byte 0b00000111 ;LED digit 7 .byte 0b01111111 ;LED digit 8 .byte 0b01101111 ;LED digit 9