PAGE 0,80 ;Program:- i2c_asm_mt.asm ;Bit Bangs the I2C interface in order to read the RTC module's registers, ;and then prints the time & date on the Microtan screen. ;Powershell command for assembling with AS assembler ;PS C:\Microtan\AS> .\bin\asw -cpu 65C02 i2c_asm_mt.asm -L -o a.out ; if ($?) { .\bin\p2bin a.out } ORG $0 AY_BASE_ADR: EQU $BC00 ; (Base address of the AY chip.) AY_WRITE_ADR: EQU AY_BASE_ADR+1 EN: EQU 7 ;Address of ENABLE register in AY chip. PA: EQU 14 ;Address of Port A register in AY chip. PB: EQU 15 ;Addresses of Port B register in AY chip. NUM_REGS EQU 19 ;Number of RTC registers RTC_SECS: EQU RTC_VARS+0 ;Seconds RTC_MINS: EQU RTC_VARS+1 ;Mins RTC_HRS: EQU RTC_VARS+2 ;Hours RTC_DOW: EQU RTC_VARS+3 ;Day Of Week RTC_DATE: EQU RTC_VARS+4 ;Date RTC_MTH: EQU RTC_VARS+5 ;Month RTC_YEAR: EQU RTC_VARS+6 ;Years RTC_TEMPMSB: EQU RTC_VARS+$11 ;MSB of temperature RTC_TEMPLSB: EQU RTC_VARS+$12 ;LSB of temperature TIMESCNADD: EQU $202 ;Start address of time display TEMPSCNADD: EQU $224 ;Start address of temperature display ORG $7C00 ; (31744) CLOCK: JSR CLR_I2C JSR I2C_START LDA #$D0 ;RTC address JSR SEND_I2C_BYTE LDA #$0 JSR SEND_I2C_BYTE JSR I2C_STOP JSR I2C_START LDA #$D1 JSR SEND_I2C_BYTE LDY #$0 ;first register = seconds JSR RCV_I2C_BYTE ; LDA I2C_TEMP ;get the seconds value CMP RTC_SECS ;is the new value different to the current value? BEQ QUIT ;if not then stop processing JSR I2C_ACK ;else ACK it LDA I2C_TEMP ;get the seconds value again STA RTC_VARS,Y ;and store the new value INY NEXT: JSR RCV_I2C_BYTE ;get the next register's value LDA I2C_TEMP ; STA RTC_VARS,Y ;save it INY CPY #NUM_REGS ;have we done all registers? BNE DO_ACK ;No then do an Acknowlege FINISH: JSR I2C_NAK ;Do a Not Acknowledge JSR I2C_STOP ;and a final Stop. JSR PRINTTIME ;display the time and date. RTS DO_ACK: JSR I2C_ACK JMP NEXT QUIT: JSR I2C_NAK ;Do a Not Acknowledge JSR I2C_STOP ;and a final Stop. RTS PRINTTIME: LDX #$00 ; LDA #$20 ;Century = 20 JSR PRINT2BCD ;print it INX ;next location LDA RTC_YEAR ;get year JSR PRINT2BCD ;print it INX ;next location JSR PRINTSEP ;print a separator INX ;next location JSR PRINTDOW ;print Day Of Week INX ;next location JSR PRINTSEP ;print a separator INX ;next location LDA RTC_DATE ;get the day of the month. JSR PRINT2BCD ;print it INX ;next location JSR PRINTSEP ;print a separator INX ;next location JSR PRINTMTH ;print month INX ;next location JSR PRINTSEP ;print a separator INX ;next location LDA RTC_HRS ;get the hours AND #$3F ;only the hours BCD bits req. JSR PRINT2BCD ;print hours INX ; LDA #':' ;time separator = : STA TIMESCNADD,X ;display it INX ;next location LDA RTC_MINS ;get the mins AND #$7F ;only the mins BCD bits req. JSR PRINT2BCD ;print mins INX ; LDA #':' ;time separator = : STA TIMESCNADD,X ;display it INX ;next location LDA RTC_SECS ;get the seconds AND #$7F ;only the seconds BCD bits req. JSR PRINT2BCD ;print seconds RTS PRINT2BCD: ;print 2 ASCII characters from the value in A PHA ;save BCD value LSR A ;convert MSD to ASCII LSR A ; LSR A ; LSR A ; ORA #'0' ; STA TIMESCNADD,X ;display it INX ;next display location PLA ;retrieve BCD value AND #$0F ;convert LSD to ASCII ORA #'0' STA TIMESCNADD,X ;display it RTS PRINTDOW: ;print the Day Of Week from value in A 1-7 (3 chars) ; 1 = Sun, 2 = Mon etc. LDA RTC_DOW ;get DOW SEC ;multiply by 3 (each DOW string is 3 chars) SBC #1 ;subtract 1 as the strings are '0' indexed STA I2C_TEMP ;store it for a moment ASL A ;x2 CLC ; ADC I2C_TEMP ;+ itself again = x3 in total TAY ;Y = offset of DOW string LDA DOWSTRGS,Y ;Get character STA TIMESCNADD,X ;display it INX ;next location INY ;next char LDA DOWSTRGS,Y ;Get character STA TIMESCNADD,X ;display it INX ;next location INY ;next char LDA DOWSTRGS,Y ;Get character STA TIMESCNADD,X ;display it RTS DOWSTRGS: BYT 'SunMonTueWedThrFriSat' PRINTMTH: ;print the Day Of Week from value in A 1-7 (3 chars) ; 1 = Sun, 2 = Mon etc. LDA RTC_MTH ;get MTH AND #$10 ;is 10's of months set? BEQ NOTENS ;if not branch LDA RTC_MTH ; AND #$0F ;get just the month units value CLC ADC #10 ;Add ten to the month units value JMP PRNTMTH2 ;carry on NOTENS: LDA RTC_MTH ; AND #$0F ;just the month units value PRNTMTH2: SEC ; SBC #1 ;subtract 1 as the strings are '0' indexed STA I2C_TEMP ;store it for a moment ;multiply by 3 (each month string is 3 chars) ASL A ;x2 CLC ; ADC I2C_TEMP ;+ itself again = x3 in total TAY ;Y = offset of Month string LDA MTHSTRGS,Y ;Get character STA TIMESCNADD,X ;display it INX ;next location INY ;next char LDA MTHSTRGS,Y ;Get character STA TIMESCNADD,X ;display it INX ;next location INY ;next char LDA MTHSTRGS,Y ;Get character STA TIMESCNADD,X ;display it RTS MTHSTRGS: BYT 'JanFebMarAprMayJunJulAugSepOctNovDec' PRINTSEP: ;print a seperator LDA #' ' ;separator = space STA TIMESCNADD,X ;display it RTS ;I2C routines : -based in part on work published by WilsonMinesco ; See - http://wilsonminesco.com/6502primer/GENRLI2C.ASM I2C_START: JSR I2C_DATA_DN ; Data down. JSR I2C_CLK_DN ; Clk down. RTS ;----------------------- I2C_STOP: JSR I2C_DATA_DN JSR I2C_CLK_UP JSR I2C_DATA_UP RTS ;----------------------- I2C_ACK: JSR I2C_DATA_DN ;The ACK bit in I2C is the 9th bit of a "byte". ia1: JSR I2C_CLK_UP ; JSR I2C_CLK_DN ; JSR I2C_DATA_UP RTS ;----------------------- I2C_NAK: JSR I2C_DATA_UP ; JSR I2C_CLK_UP ; JSR I2C_CLK_DN ; RTS ;----------------------- I2C_ACKR: JSR I2C_DATA_UP ; At end of write, N=0 means ACK. N=1 means NAK. JSR I2C_CLK_UP LDA #15 STA AY_BASE_ADR LDA AY_BASE_ADR ; Read the data. JSR I2C_CLK_DN ; Clk down. RTS ;----------------------- INIT_I2C: ;Set up the port bit directions and values, clk & data low. LDA #PA ;Clk line is on port A bit 0 STA AY_BASE_ADR LDA #1 ;Clk high STA AY_WRITE_ADR LDA #PB ;Data line is on port B bit 0 STA AY_BASE_ADR LDA #0 ;Set data line bit low STA AY_WRITE_ADR LDA #EN ;Set the port directions STA AY_BASE_ADR LDA AY_BASE_ADR ORA #%01000000 ;port A o/p, don't affect other bits AND #%01111111 ;port B i/p, don't affect other bits STA AY_WRITE_ADR ;Implement setting RTS ;--------------------- CLR_I2C: ;This clears any unwanted transaction that might be in progress, JSR I2C_STOP ;by giving enough clock pulses to finish a byte and, JSR I2C_START ;not acknowledging it. JSR I2C_DATA_UP ;Keep data line released so we don't ACK any byte sent by a device. LDX #9 ;Loop 9x to send 9 pulses to finish any byte a device might send. ci2c: JSR I2C_CLK_UP JSR I2C_CLK_DN DEX BNE ci2c JSR I2C_START JMP I2C_STOP ;------------------ SEND_I2C_BYTE: ;Start with byte in A, and clock low. Ends with I2C_ACKR. STA I2C_TEMP ;Store the byte in a variable so we can use A. LDX #8 ;We will do 8 bits. sIb2: JSR I2C_DATA_UP ;Release data line. ASL I2C_TEMP ;Get next bit to send and put it in the C flag. BCS sIb1 JSR I2C_DATA_DN ;If the bit was 0, pull data line down by making it an output. sIb1: JSR I2C_CLK_UP ;Do a high pulse on the clock line. JSR I2C_CLK_DN ;register bit DEX BNE sIb2 JMP I2C_ACKR ;get the receiver's ACK (or NAK) bit. ;------------------ RCV_I2C_BYTE: ;Starts with clock low. Ends with byte in I2C_TEMP. JSR I2C_DATA_UP ;Make sure we're not holding the data line down. LDX #8 ;We will do 8 bits. There's no need to init I2C_TEMP. rIb1: JSR I2C_CLK_UP ;Set clock line high. ASL I2C_TEMP ;Get ready to accept the bit. LDA #PB STA AY_BASE_ADR LDA AY_BASE_ADR ;Read the data. AND #$1 ;LSB is the data BEQ rIb2 ;If the data line was high, INC I2C_TEMP ;increment the 1's place to a 1 in the forming byte. rIb2: JSR I2C_CLK_DN ;Put clock line back low. DEX BNE rIb1 ;Go back for next bit if there is one. RTS ;------------------ I2C_DATA_UP: LDA #EN ;Set PB as input. STA AY_BASE_ADR LDA AY_BASE_ADR AND #$7F ;MSB=0 STA AY_WRITE_ADR RTS ;----------------------- I2C_DATA_DN: LDA #EN ;Set PB as output. STA AY_BASE_ADR LDA AY_BASE_ADR ORA #$80 ;MSB=1 STA AY_WRITE_ADR RTS ;----------------------- I2C_CLK_UP: LDA #PA ;Set PA0 high STA AY_BASE_ADR LDA AY_BASE_ADR ORA #$1 ;LSB=1 STA AY_WRITE_ADR RTS ;----------------------- I2C_CLK_DN: LDA #PA ;Set PA0 low. STA AY_BASE_ADR LDA AY_BASE_ADR AND #$FE ;LSB=0. STA AY_WRITE_ADR RTS ;----------------------- I2C_TEMP: dfs 1 ;Define Storage for variables, RTC_VARS: dfs 18 ;storage area for the read RTC registers. ;END