; > TestSrc.Cmos TTL RISC OS 2+ POST battery-backed RAM access ; ; A function to read bytes from CMOS, for use in verifying the checksum ; and reading memory test flag & video modes. ;------------------------------------------------------------------------ ; History ; ; Date Name Comment ; ---- ---- ------- ; 05-Apr-91 ArtG Initial version, based on IICMod. ; ; ;------------------------------------------------------------------------ ; ; in: ; R0 = device address (bit 8 - 15 register address ) ; R1 = length of block to read ; R2 = initial sum value ; ; out: R0 = sum of all bytes in block ; R1 - R13 trashed ; ts_CMOSread ROUT MOV R13,R14 MOV R8,R2 ; initialise accumulator MOV R7,R1 ; initialise byte counter MOV R6,R0 ; stash register address MOV R2, #IOC MOV R0, #-1 ; ensure timer is ticking STRB R0, [R2, #Timer0LL] ; (nonzero in input latch) STRB R0, [R2, #Timer0LH] STRB R0, [R2, #Timer0GO] ; load the count registers BL ts_Start BEQ %FT30 ; check clock line toggles OK AND R0, R6, #&FE BL ts_TXCheckAck ; transmit device address (write) BVS %FT30 MOV R0, R6, LSR #8 BL ts_TXCheckAck ; write register address BVS %FT30 BL ts_Start ; Extra START bit to switch modes AND R0, R6, #&FE ORR R0, R0, #1 BL ts_TXCheckAck ; transmit device address (read) BVS %FT30 20 BL ts_RXByte ; read byte from bus ADD R8, R8, R0 ; accumulate total SUBS R7, R7, #1 ; is it last byte ? MOVNE R0, #0 ; no, then acknowledge with 0 bit MOVEQ R0, #1 ; yes, then don't acknowledge BL ts_ClockData ; but always send ack clock pulse TEQ R7, #0 ; loop, until last byte BNE %BT20 30 MOVVS R7, #-1 ; pass error indicator to caller BL ts_Stop MOV R0, R8 TEQ R7, #0 ; return zero flag if read OK MOV PC,R13 ; ***************************************************************************** ; ; TXCheckACK - transmit a byte and wait for slave to ACK ; ; out: Trashes r0,r1,r2,r3,r4,r5,r9,r10,r11,r12 ; V bit set on error. ; ts_TXCheckAck ROUT MOV R12,R14 BL ts_TXByte BL ts_Acknowledge MOV PC, R12 ; ***************************************************************************** ; ; SetC1C0 - Set clock and data lines to values in R1 and R0 respectively ; ; out: Trashes r0,r1,r2,r11 ; ts_SetC1C0 ROUT MOVS R11, R14 ; NE: indicate not checking clock ts_SetOrCheck MRS R14, CPSR ORR R14, R14, #I32_bit ; disable interrupts MSR CPSR_c, R14 ADD R0, R0, R1, LSL #1 ; R0 := C0 + C1*2 ORR R0, R0, #&C0 ; make sure two test bits are ; always set to 1 ! MOV R2, #IOC STRB R0, [R2, #IOCControl] 10 LDREQB R1, [R2, #IOCControl] ; wait for clock TSTEQ R1, #i2c_clock_bit ; to read high BEQ %BT10 MOV R0, #10 ; delay for >= 10/2 microsecs ; ; in-line do-micro-delay to save a stack level ; STRB R0, [R2, #Timer0LR] ; copy counter into output latch LDRB R1, [R2, #Timer0CL] ; R1 := low output latch 20 STRB R0, [R2, #Timer0LR] ; copy counter into output latch LDRB R14, [R2, #Timer0CL] ; R14 := low output latch TEQ R14, R1 ; unchanged ? MOVNE R1, R14 ; copy anyway BEQ %BT20 ; then loop SUBS R0, R0, #1 ; decrement count BNE %BT20 ; loop if not finished ; ; end do-micro-delay ; MOV PC, R11 ; Set clock and data lines to R1 and R0 and then wait for clock to be high ts_SetC1C0CheckClock ROUT MOV R11, R14 CMP R0, R0 ; EQ: indicate checking clock B ts_SetOrCheck ; ***************************************************************************** ; ; ClockData - Clock a bit of data down the IIC bus ; ; in: R0 = data bit ; ; out: Trashes r0,r1,r2,r3,r10,r11 ; ts_ClockData ROUT MOV R10,R14 MOV R3, R0 ; save data MOV R1, #0 ; clock LO BL ts_SetC1C0 MOV R1, #1 ; clock HI MOV R0, R3 BL ts_SetC1C0CheckClock ; Delay here must be >= 4.0 microsecs MOV R1, #0 ; clock LO MOV R0, R3 BL ts_SetC1C0 MOV PC,R10 ; ***************************************************************************** ; ; Start - Send the Start signal ; ; out: Trashes r0,r1,r2,r9,r11 ; R0 (and Z flag) indicates state of clock .. should be NZ. ; ts_Start ROUT MOV R9,R14 MOV R0, #1 ; clock HI, data HI MOV R1, #1 BL ts_SetC1C0 ; Delay here must be >= 4.0 microsecs MOV R0, #0 ; clock HI, data LO MOV R1, #1 BL ts_SetC1C0 ; Make sure clock really is high (and not shorted to gnd) LDRB R3, [R2, #IOCControl] ; Delay here must be >= 4.7 microsecs MOV R0, #0 ; clock LO, data LO MOV R1, #0 BL ts_SetC1C0 ANDS R0, R3, #i2c_clock_bit MOV PC,R9 ; ***************************************************************************** ; ; Acknowledge - Check acknowledge after transmitting a byte ; ; out: Trashes r0,r1,r2,r3,r9,r11 ; V=0 => acknowledge received ; V=1 => no acknowledge received ; ts_Acknowledge ROUT MOV R9,R14 MOV R0, #1 ; clock LO, data HI MOV R1, #0 BL ts_SetC1C0 MOV R0, #1 ; clock HI, data HI MOV R1, #1 BL ts_SetC1C0CheckClock ; Delay here must be >= 4.0 microsecs MOV R2, #IOC LDRB R3, [R2, #IOCControl] ; get the data from IOC MOV R0, #1 ; clock LO, data HI MOV R1, #0 BL ts_SetC1C0 TST R3, #1 ; should be LO for correct acknowledge MRS R3, CPSR BICEQ R3, R3, #V_bit ; clear V if correct acknowledge ORRNE R3, R3, #V_bit ; set V if no acknowledge MSR CPSR_f, R3 MOV PC,R9 ; ***************************************************************************** ; ; Stop - Send the Stop signal ; ; out: Trashes r0,r1,r2,r9,r11 ; ts_Stop ROUT MOV R9,R14 MOV R0, #0 ; clock HI, data LO MOV R1, #1 BL ts_SetC1C0 ; Delay here must be >= 4.0 microsecs MOV R0, #1 ; clock HI, data HI MOV R1, #1 BL ts_SetC1C0 MOV PC,R9 ; ***************************************************************************** ; ; TXByte - Transmit a byte ; ; in: R0 = byte to be transmitted ; ; out: Trashes r0,r1,r2,r3,r4,r5,r9,r10,r11 ; ts_TXByte ROUT MOV R9, R14 MOV R4, R0 ; byte goes into R4 MOV R5, #&80 ; 2^7 the bit mask 10 ANDS R0, R4, R5 ; zero if bit is zero MOVNE R0, #1 BL ts_ClockData ; send the bit MOVS R5, R5, LSR #1 BNE %BT10 MOV PC, R9 ; ***************************************************************************** ; ; RXByte - Receive a byte ; ; out: R0 = byte received ; Trashes r1,r2,r3,r4,r9,r11 ; ts_RXByte ROUT MOV R9, R14 MOV R3, #0 ; byte:=0 MOV R2, #IOC MOV R4, #7 MOV R0, #1 ; clock LO, data HI MOV R1, #0 BL ts_SetC1C0 10 MOV R0, #1 ; pulse clock HI MOV R1, #1 BL ts_SetC1C0CheckClock LDRB R1, [R2, #IOCControl] ; get the data from IOC AND R1, R1, #1 ADD R3, R1, R3, LSL #1 ; byte:=byte*2+(IOC?0)AND1 MOV R0, #1 ; return clock LO MOV R1, #0 BL ts_SetC1C0 SUBS R4, R4, #1 BCS %BT10 MOV R0, R3 ; return the result in R0 MOV PC, R9 LTORG END