Category : Assembly Language Source Code
Archive   : SIG8051.ZIP
Filename : I2CBITS.ASM

 
Output of file : I2CBITS.ASM contained in archive : SIG8051.ZIP

;****************************************************************************

; Software Implemented I2C Drivers

; These routines allow an 80C51 based microcontroller to drive the I2C bus
; as a single master. The main program at the end demonstrates writing and
; reading several types of devices:

; PCF8570 256 byte static RAM.
; PCF8574 8-bit I/O expander.
; SAA1064 4 digit LED display driver.


; Written by G.Goodhue, Philips Components-Signetics

;****************************************************************************


$Title(I2C Routines for 80C51)
$Date(08/14/90)
$MOD51
$DEBUG


;****************************************************************************
; Definitions
;****************************************************************************


; Addresses of several I2C devices as connected on the Signetics I2C
; Evaluation Board.

I2CRAM EQU 0AEh ;Slave address for PCF8570 RAM chip.
I2CIO EQU 4Eh ;Slave address for PCF8574 I/O expandor.
I2CLED EQU 76h ;Slave address for SAA1064 LED driver.


; Data storage locations

BitCnt DATA 8h ;Bit counter for I2C routines.
ByteCnt DATA 9h ;Byte counter for I2C routines.
SlvAdr DATA 0Ah ;Slave address for I2C routines.

XmtDat DATA 10h ;I2C transmit buffer, 8 bytes max.
RcvDat DATA 18h ;I2C receive buffer, 8 bytes max.
AltRcv DATA 20h ;Alternate I2C receive buffer, 8 bytes max.

Flags DATA 28h ;Location for bit flags
NoAck BIT Flags.0 ;I2C no acknowledge flag.
BusFault BIT Flags.1 ;I2C bus fault flag.
I2CBusy BIT Flags.2 ;I2C busy flag.


; I2C connections.

SCLPin BIT P0.0 ;I2C serial clock line.
SDAPin BIT P0.1 ;I2C serial data line.


;****************************************************************************
; Reset and Interrupt Vectors
;****************************************************************************


ORG 0
AJMP Reset


;****************************************************************************
; Subroutines
;****************************************************************************


ORG 30h

; BitDly - insures minimum high and low clock times on I2C bus.
; This routine must be tuned for the actual oscilator frequency used, shown
; here tuned for a 12MHz clock. Note that the CALL instruction that invokes
; BitDly already uses 2 machine cycles.

BitDly: NOP ;NOPs to delay 5 microseconds (minus 4
; machine cycles for CALL and RET).
RET


; SCLHigh - sends SCL pin high and waits for any clock stretching peripherals.

SCLHigh: SETB SCLPin ;Set SCL from our end.
JNB SCLPin,$ ;Wait for pin to actually go high.
RET


; SendStop - sends an I2C stop, releasing the bus.

SendStop: CLR SDAPin ;Get SDA ready for stop.
ACALL SCLHigh ;Set clock for stop.
ACALL BitDly
SETB SDAPin ;Send I2C stop.
ACALL BitDly
CLR I2CBusy ;Clear I2C busy status.
RET ;Bus should now be released.


; SendByte - sends one byte of data to an I2C slave device.
; Enter with:
; ACC = data byte to be sent.

SendByte: MOV BitCnt,#8 ;Set bit count.

SBLoop: RLC A ;Send one data bit.
MOV SDAPin,C ;Put data bit on pin.
ACALL SCLHigh ;Send clock.
ACALL BitDly
CLR SCLPin
ACALL BitDly
DJNZ BitCnt,SBloop ;Repeat until all bits sent.

SETB SDAPin ;Release data line for acknowledge.
ACALL SCLHigh ;Send clock for acknowledge.
ACALL BitDly
JNB SDAPin,SBEX ;Check for valid acknowledge bit.
SETB NoAck ;Set status for no acknowledge.
SBEX: CLR SCLPin ;Finish acknowledge bit.
ACALL BitDly
RET


; GoMaster - sends an I2C start and slave address.
; Enter with:
; SlvAdr = slave address.

GoMaster: SETB I2CBusy ;Indicate that I2C frame is in progress.
CLR NoAck ;Clear error status flags.
CLR BusFault
JNB SCLPin,Fault ;Check for bus clear.
JNB SDAPin,Fault
CLR SDAPin ;Begin I2C start.
ACALL BitDly
CLR SCLPin
ACALL BitDly ;Complete I2C start.
MOV A,SlvAdr ;Get slave address.
ACALL SendByte ;Send slave address.
RET

Fault: SETB BusFault ;Set fault status
RET ; and exit.


; SendData - sends one or more bytes of data to an I2C slave device.
; Enter with:
; ByteCnt = count of bytes to be sent.
; SlvAdr = slave address.
; @R0 = data to be sent (the first data byte will be the
; subaddress, if the I2C device expects one).

SendData: ACALL GoMaster ;Acquire bus and send slave address.
JB NoAck,SDEX ;Check for slave not responding.

SDLoop: MOV A,@R0 ;Get data byte from buffer.
ACALL SendByte ;Send next data byte.
INC R0 ;Advance buffer pointer.
JB NoAck,SDEX ;Check for slave not responding.
DJNZ ByteCnt,SDLoop ;All bytes sent?

SDEX: ACALL SendStop ;Done, send an I2C stop.
RET


;RcvByte - receives one byte of data from an I2C slave device.
; Returns:
; ACC = data byte received.

RcvByte: MOV BitCnt,#8 ;Set bit count.

RBLoop: ACALL SCLHigh ;Read one data bit.
ACALL BitDly
MOV C,SDAPin ;Get data bit from pin.
RLC A ;Rotate bit into result byte.
CLR SCLPin
ACALL BitDly
DJNZ BitCnt,RBLoop ;Repeat until all bits received.

PUSH ACC ;Save accumulator
MOV A,ByteCnt
CJNE A,#1,RBAck ;Check for last byte of frame.
SETB SDAPin ;Send no acknowledge on last byte.
SJMP RBAClk

RBAck: CLR SDAPin ;Send acknowledge bit.
RBAClk: ACALL SCLHigh ;Send acknowledge clock.
POP ACC ;Restore accumulator
ACALL BitDly
CLR SCLPin
SETB SDAPin ;Clear acknowledge bit.
ACALL BitDly
RET


;RcvData - receives sends one or more bytes of data from an I2C slave device.
; Enter with:
; ByteCnt = count of bytes to be sent.
; SlvAdr = slave address.
; Returns:
; @R0 = data received.

; Note: to receive with a subaddress, use SendData to set the subaddress
; first (no provision for repeated start).

RcvData: INC SlvAdr ;Set for READ of slave.
ACALL GoMaster ;Acquire bus and send slave address.
JB NoAck,RDEX ;Check for slave not responding.

RDLoop: ACALL RcvByte ;Recieve next data byte.
MOV @R0,A ;Save data byte in buffer.
INC R0 ;Advance buffer pointer.
DJNZ ByteCnt,RDLoop ;Repeat untill all bytes received.

RDEX: ACALL SendStop ;Done, send an I2C stop.
RET


;****************************************************************************
; Main Program
;****************************************************************************


Reset: MOV SP,#2Fh ;Set stack to start at 30h.

MOV XmtDat,#0 ;Initialize transmit data area.
MOV XmtDat+1,#37h
MOV XmtDat+2,#0AAh
MOV XmtDat+3,#055h
MOV XmtDat+4,#33h
MOV XmtDat+5,#0CCh
MOV XmtDat+6,#0FFh
MOV XmtDat+7,#0BBh


TestLoop: MOV SlvAdr,#I2CIO ;Write data to PCF8574 I/O expandor.
MOV R0,#XmtDat+2 ;Start of data.
MOV ByteCnt,#1 ;Send one data byte.
ACALL SendData

MOV SlvAdr,#I2CIO ;Read back data from PCF8574 I/O expandor.
MOV R0,#AltRcv ;Start of data.
MOV ByteCnt,#1 ;Read one data byte.
ACALL RcvData
INC XmtDat+2 ;Advance data to next value.

MOV SlvAdr,#I2CLED ;Write data to SAA1064 LED driver.
MOV R0,#XmtDat ;Start of data.
MOV ByteCnt,#6 ;Send 6 bytes (subaddress, control, data).
ACALL SendData

MOV SlvAdr,#I2CRAM ;Write data to PCF8570 RAM.
MOV R0,#XmtDat ;Start of data.
MOV ByteCnt,#8 ;Send 8 bytes (subaddress + 7 data bytes).
ACALL SendData

MOV SlvAdr,#I2CRAM ;Write subaddress to PCF8570 RAM.
MOV R0,#XmtDat ;Start of data.
MOV ByteCnt,#1 ;Send one byte (subaddress).
ACALL SendData
MOV SlvAdr,#I2CRAM ;Read back data from PCF8570 RAM.
MOV R0,#RcvDat ;Start of data.
MOV ByteCnt,#7 ;Read 7 data bytes.
ACALL RcvData

AJMP TestLoop ;Repeat operation for scope watchers.

END


  3 Responses to “Category : Assembly Language Source Code
Archive   : SIG8051.ZIP
Filename : I2CBITS.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/