;****************************************************************************** ;** ;** DESCRIPTION: ;** ;** This file contains general utility routines, written in the 80C51 assembly ;** language, which are used to interface the 80C51 to standard two-wire(IIC) ;** Serial Products. The interface between the 80C51 and IIC Device consists ;** of a clock (SCL) and a bidirectional data line (SDA). ;** The communication interface uses 2 pins from Port 1(P10 = SCL and P11 = SDA). ;** The following table lists all the subroutines in this file with a brief ;** description: ;** ;** Start: Generate the start condition ;** Stop: Generate the stop condition ;** ResetIIC: Issues the appropriate commands to force device reset ;** ProgPage: Transfer multible bytes from RAM buffer to IIC Device ;** ProgByte: Transfer byte from RAM buffer to IIC Device ;** SeqRead: Read multiple bytes, starting from current address pointer ;** RandomRead: Read a byte from a specific memory location ;** ACKPoll: Return when the write cycle completes. ;** OutACK: Process the acknowledge output cycle ;** GetACK: process the acknowledge from the slave device ;** ;** NOTE 1. These rountines can run at 12.0MHz, While IIC Maxspeed is 400K ;** 2. The IIC Device must based on 16-bits address, so the sequence: ;** ;** START Slave Address Address Data STOP ;** \XXXXXXXW AAAAAAAA AAAAAAAA DDDDDDDD / ;** ACK ACK ACK ACK ;** ;****************************************************************************** ;****************************************************************************** ;* PROGRAM CONSTANTS ;****************************************************************************** SDAbit EQU 00H ; PORT-1 BITS FUNCTIONING AS BIDIRECTIONAL SCLbit EQU 01H ; SERIAL DATA (SDA) AND SERIAL CLOCK OUTPUT (SCL) MaxDelay EQU 0FFH ; NUMBER OF TIMES TO CHECK ACKNOWLEDGE POLLING DeviceID EQU 6FH ; DEVICE SLAVE ADDRESS ; X1208\1209 SLAVE ADDRESS: 1101111B ;******************************************************************************* ;****************************************************************************** ;** Name: SeqRead ;** Description: Read sequentially from the IIC Device. ;** Function: This subroutine extracts contents of the IIC Device and stores ;** them into the specified RAM buffer. The total number of bytes to ;** read should be provided along with the buffer address. This ;** routine assumes that the address pointer has already been ;** initialized using the RandomRead routine. ;** !!!!!!!!!! RETURN FROM StopRead !!!!!!!!!! ;** ;** Calls: Start, SlavAddr, InByte, StopRead ;** Input: R0 = RAM Buffer Base Address ;** R1 = Number of bytes to read ;** Output: None ;** Register Usage: A, R0, R1 ;****************************************************************************** ORG 0400H ; IIC.ASM MAPPED IN: 400~4ACH SeqRead: acall Start ; START setb c ; [C=1] READ OPERATION BIT acall SlavAddr ; SEND THE SLAVE ADDRESS BYTE SeqReadLoop: acall InByte ; START READING FROM THE CURRENT ADDRESS mov @R0,A ; TOTAL NUMBER OF BYTES TO READ OUT OF inc R0 ; IIC Device djnz R1,SeqReadNxt ajmp StopRead ; END OF READ OPERATION SeqReadNxt: acall OutACK ; SEND AN ACKNOWLEDGE TO THE DEVICE ajmp SeqReadLoop ;****************************************************************************** ;** Name: RandomRead ;** Description: Reads content of the IIC Device at a specific location. ;** Function: This subroutine sends out the command to read the content of a ;** memory location specified in the DPTR. ;** !!!!!!!!!! RETURN FROM StopRead !!!!!!!!!! ;** ;** Calls: Start, InByte, SlavAddr, OutByte StopRead ;** Input: DPTR = Address of the byte ;** Output: A = Read value ;** Register Usage: A ;****************************************************************************** RandomRead: acall Start ; START clr C ; [C=0] WRITE OPERATION BIT acall SlavAddr ; SEND THE SLAVE ADDRESS BYTE mov A,DPH ; LOAD THE UPPER BYTE OF THE ADDRESS acall OutByte ; ADDRESS SHIFT OUT TO THE DEVICE mov A,DPL ; LOAD THE LOWER BYTE OF THE PAGE acall OutByte ; ADDRESS SHIFT OUT TO THE DEVICE acall Start ; START setb C ; [C=1] READ OPERATION BIT acall SlavAddr ; SEND THE SLAVE ADDRESS BYTE acall InByte ; SHIFT IN A BYTE FROM THE DEVICE ajmp StopRead ; END OPERATION ;****************************************************************************** ;** Name: StopRead ;** Description: Terminate read operation. ;** Function: This subroutine sends out the command to end reading content of a ;** IIC Device. ;** !!!!!!!!!! RETURN FROM Stop !!!!!!!!!! ;** Calls: ClockPulse, Stop ;** Input: None ;** Output: None ;** Register Usage: None ;****************************************************************************** StopRead: setb P1.SDAbit ; MAKE SURE THAT THE DATA LINE IS HIGH acall ClockPulse jmp Stop ; END OPERATION ;****************************************************************************** ;** Name: ProgPage ;** Description: Update a page of the Serial Memory. ;** Function: This subroutine transfers the contents of the given buffer to the ;** Serial Memory. The caller program must supply the page number ;** of the Serial Memory to update and the base address of the ;** RAM buffer. ;** !!!!!!!!!! RETURN FROM Stop !!!!!!!!!! ;** Calls: Start, SlavAddr, OutByte, Stop ;** Input: R0 = RAM Buffer Base Address, DPTR = Address of programm ;** R1 = Number of bytes to write ;** Output: None ;** Register Usage: A, R0, R1 ;****************************************************************************** ProgPage: acall Start ; START clr C ; [C=0] WRITE OPERATION BIT acall SlavAddr ; SEND THE SLAVE ADDRESS BYTE mov A,DPH ; LOAD THE HIGHER BYTE OF ADDRESS acall OutByte mov A,DPL ; LOAD THE LOWER BYTE OF ADDRESS acall OutByte ; AND SHIFT OUT TO THE DEVICE ProgPageNxt: mov A,@R0 ; TO THE Serial MEMORY acall OutByte ; R0 SHOULD BE POINTING TO THE BUFFER inc R0 ; TOTAL NUMBER OF BYTES TRANSFERRED djnz R1,ProgPageNxt ; TO THE Serial SHOULD NOT EXCEED ; THE PAGE SIZE ajmp Stop ; END OF THE OPERATION ;****************************************************************************** ;** Name: ProgByte ;** Description: Write a byte to IIC Device. ;** Function: This subroutine transfers the contents of Acc to the IIC ;** Device. The upper byte of the word address is contained in ;** (DPH) and the lower byte is contained in (DPL). A two byte ;** address is required for both page and byte write commands. ;** !!!!!!!!!! RETURN FROM Stop !!!!!!!!!! ;** ;** Calls: Start, SlavAddr, Outbyte, Stop ;** Input: Acc = byte to be written, DPTR = Address of programm ;** Output: None ;** Register Usage: B ;****************************************************************************** ProgByte: xch A,B ; SAVE DATA BYTE acall Start ; START clr c ; [C=0] WRITEOPERATION BIT acall SlavAddr ; SEND THE SLAVE ADDRESS BYTE mov A,DPH ; LOAD THE UPPER BYTE OF THE WORD ADDRESS acall OutByte ; SEND OUT THE LOWER BYTE OF THE ADDRESS mov A,DPL ; LOAD THE LOWER BYTE OF THE WORD ADDRESS acall OutByte ; SEND OUT THE LOWER BYTE OF THE ADDRESS xch A,B ; LOAD THE DATA TO BE SENT IN THE ACC acall OutByte ; SEND OUT THE DATA TO THE SERIAL MEMORY ajmp Stop ; END OF THE OPERATION ;******************************************************************************* ;** Name: SlavAddr ;** Description: Build the slave address for the IIC Device. ;** Function: This subroutine concatenates the bit fields for Device ID, ;** the high address bits and the command bit. The resultant ;** byte is then transmitted to the IIC Device. ;** !!!!!!!!!! RETURN FROM OutByte !!!!!!!!!! ;** Calls: OutByte ;** Input: C = COMMAND BIT (=0 WRITE, =1 READ) ;** Output: None ;** Register Usage: A ;******************************************************************************* SlavAddr: mov A,dID ; IF IS FIXED DEVICE USE:'#DeviceID' rlc A ; MERGE THE COMMAND BIT ajmp OutByte ; SEND THE SLAVE ADDRESS ;******************************************************************************* ;** Name: OutByte ;** Description: Sends a byte to the IIC Device ;** Function: This subroutine shifts out a byte, MSB first, through the ;** assigned SDA/SCL lines on port 1. ;** !!!!!!!!!! RETURN FROM GetACK !!!!!!!!!!! ;** Calls: ClockPulse, GetACK ;** Input: A = Byte to be sent ;** Return Value: None ;** Register Usage: A ;******************************************************************************* OutByte: setb C OutByteLoop: rlc A ; SHIFT OUT THE BYTE, MSB FIRST jnc OutByte0 setb P1.SDAbit ajmp OutByte1 OutByte0: clr P1.SDAbit OutByte1: acall ClockPulse ; CLOCK THE DATA INTO THE IIC Device cjne A,#10000000b,OutByteNxt ; SKIP IF NOT DONE jmp GetACK ; CHECK FOR AN ACK FROM THE DEVICE OutByteNxt: clr C ; LOOP IF ALL THE BITS HAVE ajmp OutByteLoop ; NOT BEEN SHIFTED OUT ;****************************************************************************** ;** Name: InByte ;** Description: Shifts in a byte from the IIC Device ;** Function: This subroutine shifts in a byte, MSB first, through the ;** assigned SDA/SCL lines on port 1. After the byte is received ;** an ACK bit is sent to the IIC Device. ;** Calls: ClockPulse ;** Input: None ;** Return Value: A = Received byte ;** Register Usage: A ;****************************************************************************** InByte: mov A,#00000001b setb P1.SDAbit ; SDA LINE FORCED HIGH InByteNxt: acall ClockPulse ; CLOCK THE Serial MEMORY AND SHIFT rlc A ; INTO ACC. THE LOGIC LEVEL ON THE SDA jnc InByteNxt ; LINE. THE DEVICE OUTPUTS DATA ON SDA ret ; MSB FIRST ;****************************************************************************** ;** Name: ClockPulse ;** Description: Generate a clock pulse ;** Function: This subroutine forces a high-low transition on the assigned SCL ;** pin of port 1. It also samples and returns the SDA line state ;** during high clock period. ;** Calls: None ;** Input: None ;** Return Value: C = SDA line status ;** Register Usage: None ;****************************************************************************** ClockPulse: nop setb P1.SCLbit ; BASED ON A 12MHz SYSTEM CRYSTAL THE nop ; BUS CYCLE TIME IS 1 MICROSEC. nop nop clr C ; jnb P1.SDAbit,ClockPulseLo ; setb C ClockPulseLo: clr P1.SCLbit ; LOWER THE CLOCK LINE ret ;****************************************************************************** ;** Name: OutACK ;** Description: Send out an ACK bit to the IIC Device ;** Function: This subroutine clocks an ACK bit to the IIC Device. ;** The ACK cycle acknowledges a properly received data by lowering ;** the SDA line during this period (9th clock cycle of a received ;** byte). ;** !!!!!!!!!! RETURN FROM CALL PARENT ROUTINE !!!!!!!!!!! ;** Calls: ClockPulse ;** Input: None ;** Return Value: None ;** Register Usage: None ;****************************************************************************** OutACK: clr P1.SDAbit ; MAKE SURE THAT THE DATA LINE IS LOW ... jmp ClockPulse ; CLOCK OUT THE ACK CYCLE ;****************************************************************************** ;** Name: GetACK ;** Description: Clock the IIC Device for ACK cycle ;** Function: This subroutine returns the sampled logic level on the SDA during ;** high clock cycle. The IIC Device holds the SDA line HIGH if ;** it does not receive the correct number of clocks or it's stuck in ;** a previously initiated write command. ;** Calls: ClockPulse ;** Input: None ;** Return Value: C = ACKnowledge bit ;** Register Usage: None ;****************************************************************************** GetACK: setb P1.SDAbit ; FORCE SDA LINE HIGH acall ClockPulse ; GENERATE ONE CLOCK PULSE ret ;****************************************************************************** ;** Name: ACKPoll ;** Description: Wait for an ACK from the IIC Device ;** Function: This subroutine monitors the IIC Device response ;** following a dummy write command. The program returns when it ;** either receives an ACK bit or the maximum number of tries is ;** reached. ;** Calls: Start, SlavAddr, Stop ;** Input: None ;** Return Value: C = ACKnowledge bit [=0 ACK ,=1 No ACK was received] ;** Register Usage: A, R1 ;****************************************************************************** ACKPoll: mov R1,#MaxDelay ; LOAD MAX NO. OF ACK POLLING CYCLE ACKPollnxt: acall Start ; START THE ACK POLL CYCLE AND clr C ; [C=0] WRITE OPERATION BIT acall SlavAddr ; SEND THE SLAVE ADDRESS. THEN ; MONITOR THE SDA LINE FOR AN ACK FROM ; THE IIC Device. TERMINATE THE acall Stop ; OPERATION BY A STOP CONDITION. jnc ACKPollExit ; EXIT IF THE ACK WAS RECEIVED djnz R1,ACKPollnxt ; LOOP WHILE THE MAXIMUM NO. OF CYCLES ; HAVE NOT EXPIRED. ELSE RETURN WITH C=1 ACKPollExit: ret ;****************************************************************************** ;** Name: Start ;** Description: Send a start command to the IIC Device ;** Function: This subroutine generates a start condition on the bus. The start ;** condition is defined as a high-low transition on the SDA ;** line while the SCL is high. The start is used at the beginning ;** of all transactions. ;** Calls: None ;** Input: None ;** Return Value: None ;** Register Usage: None ;****************************************************************************** Start: setb P1.SDAbit ; FORCE THE SDA LINE HIGH setb P1.SCLbit ; FORCE THE SCL CLOCK LINE HIGH nop nop nop clr P1.SDAbit ; BEFORE TAKING THE SDA LOW nop nop nop nop clr P1.SCLbit ; FORCE THE SCL LOW ret ;****************************************************************************** ;** Name: Stop ;** Description: Send stop command to the IIC Device ;** Function: This subroutine generates a stop condition on the bus. The stop ;** condition is defined as a low-high transition on the SDA ;** line while the SCL is high. The stop is used to indicate end ;** of current transaction. ;** Calls: None ;** Input: None ;** Return Value: None ;** Register Usage: None ;****************************************************************************** Stop: clr P1.SDAbit ; FORCE THE SDA LOW BEFORE TAKING setb P1.SCLbit ; THE SCL CLOCK LINE HIGH nop nop nop nop setb P1.SDAbit ; FORCE THE SDA HIGH (IDLE STATE) ret ;****************************************************************************** ;** Name: ResetIIC ;** Description: Resets the IIC Device ;** Function: This subroutine is written for the worst case. System interruptions ;** caused by brownout or soft error conditions that reset the main ;** CPU may have no effect on the internal Vcc sensor and reset ;** circuit of the IIC Device. These are unpredictable and ;** random events that may leave the IIC Device interface ;** logic in an unknown state. Issuing a Stop command may not be ;** sufficient to reset the IIC Device. ;** Calls: Start, Stop ;** Input: None ;** Return Value: None ;** Register Usage: R0 ;****************************************************************************** ResetIIC: mov R0,#0AH ; APPLY 10 CLOCKS TO THE DEVICE. EACH ResetNxt: acall Start ; CYCLE CONSISTS OF A START/STOP acall Stop ; THIS WILL TERMINATE PENDING WRITE djnz R0,ResetNxt ; COMMAND AND PROVIDES ENOUGH CLOCKS ret ; FOR REMAINING BITS OF A READ OPERATION ;****************************************************************************** ;** END OF IIC Device INTERFACE SOURCE CODE ;****************************************************************************** END