Digchip : Database on electronics components
 
Member, Distributor  
Log In
Email:
Password:


Part: AN433

Category:

Description:

Company:

Datasheet: Download AN433 datasheet     File size : 50 kB

Request For quote: Find where to buy AN433



Datasheet text preview:
Philips Semiconductors Microcontroller Products

Application note

I2C slave routines for the 83C751
Author: Greg Goodhue
The S83C751/S87C751 Microcontroller combines in a small package the benefits of a high-performance microcontroller with on-board hardware supporting the Inter-Integrated Circuit (I2C) bus interface. The 8XC751 can be programmed both as an I2C bus master, a slave, or both. An overview of the I2C bus and description of the bus support hardware in the 8XC751 microcontrollers appears in application note AN422, "Using the 8XC751 Microcontroller as an I2C Bus Master." That application note includes a programming example, demonstrating a bus-master code. Here we show an example of programming the microcontroller as an I2C slave. The code listing demonstrates communications routines for the 8XC751 as a slave on the I2C bus. It compliments the program in AN422 which demonstrates the 8XC752 as an I2C bus master. One may demonstrate two 8XC751 devices communicating with each other on the I2C bus, using the AN422 code in one, and the program presented here in the other. The examples presented here and in AN422 allow the 751 to be either a master or a slave, but not both. Switching between master and slave roles in a multimaster environment is described in application note AN435. The software for a slave on the bus is relatively simple, as the processor plays a relatively passive role. It does not initiate bus transfers on its own, but responds to a master initiating the communications. This is true whether the slave receives or transmits data--transmission takes place only as a response to a bus master's request. The slave does not have to worry about arbitration or about devices which do not acknowledge their address. As the slave is not supposed to take control of the bus, we do not demand it to resolve bus exceptions or "hangups". If the bus becomes inactive the processor simply withdraws, not interfering with the master (or masters) on the bus which should (hopefully) try to resolve the situation. The 8XC751 has a single bit I2C hardware interface where the registers may directly affect the levels on the bus, and the software interacting with the hardware registers takes part in the protocol implementation. The hardware and the low level routines dealing with the registers are tightly coupled. We repeat here the warning from the 751 bus-master application note: one should take extra care if trying to modify these lower level routines. The service routine for the I2C slave is interrupt driven per message. This allows for master communication requests which are not synchronized with the application program running on the slave. It is possible to write simple slave application programs which will not be interrupt driven, taking care not to lose master transmissions while doing something else, but the user should be discouraged from doing so. As the slave should respond to asynchronous requests of masters on the bus, an interrupt driven service routine makes sense--and, as the code demonstrates, is simple to implement.

AN433

will "hang" in a wait loop at this label, simply waiting for an I2C interrupt to occur. When there is an I2C bus request there will be an interrupt, the service routine will be executed and we shall return to the MainLoop label. If the service routine receives new data, it sets a flag, DatFlag, signalling that data has been updated. This flag will allow us to leave the MainLoop label, and execute a short routine copying the updated input buffer to the output (transmit) buffer. If a new bus interrupt comes before overwriting of the old read buffer data is completed, and an undesirable "mix" of old and new data might occur. This type of situation is avoided by disabling the I2C interrupts (clearing the IE2 bit in the Interrupt Enable Register) just before copying the data to the transmit buffer, and re-enabling the interrupts when the copy operation is completed. When the copy routine is completed the DatFlag is cleared and we jump back to MainLoop, waiting for the next interrupt to occur. If the interrupt is for data transmission the service routine will not set DatFlag, and upon return we shall remain at the MainLoop label.

DEMONSTRATION CODE
The main program operation, intended for demonstration only, is simple. There are two data buffers, one for data reception and one for data transmission. When new data has been received from the I2C bus into the receive buffer, the program writes it into the transmit buffer. The first and second bytes of received data are also copied to Port 1 and Port 3, respectively. When a bus master requests to read data, Port 1 and Port 3 will be returned for the first two bytes of requested data, while the remaining bytes will come from the transmit buffer. This allows for simple testing of a master and slave system by having the master compare data received to data sent. This scheme also allows the 8XC751 to be used as a two-byte I2C I/O port. The program begins at address 0, where the microprocessor begins execution after a hardware reset. This location contains a jump instruction to the main program, which starts at the label Reset (towards the end of the listing). Upon reset, the program initializes the stack pointer, the I2C address of the slave processor (MyAddr) and clears the data buffers and software flags. In this program the receive and transmit buffers are each eight bytes long--the maximum number of bytes is defined by the label MaxBytes. One may easily change the program to handle longer messages by changing the value of MaxBytes and allocating more data memory to the buffers. The I2C interface is configured to operate as a slave by setting the msb of register I2CFG. This is done simultaneously with loading the appropriate value of CTVAL--bits CT0 and CT1, which are determined by the frequency of the microprocessor's crystal. The interface hardware is explicitly instructed to get into the slave idle mode by setting the appropriate bit in the I2CON register. Timer I, which operates as a "watchdog" timer detecting bus hangups, is activated and its interrupts are enabled. After the initialization, the program gets to the label MainLoop. Most of the time the program

THE INTERRUPT SERVICE ROUTINE
The service routine is interrupt driven with respect to the start of each I2C frame, but within each frame the interaction with the hardware is based on polling. An occurrence of a Start on the bus will cause an interrupt that will initiate the service routine which starts at address 23H. After saving registers, all interrupts except the I2C interrupt itself are enabled, as we want to allow response to other interrupts during the routine. The philosophy behind this is that the I2C may be a lower priority than some other operations in the system. Since the I2C hardware will stretch the clock until the program responds, an interrupt of reasonable duration will not have a harmful effect on the data transfer. Since we intend to react to the I2C hardware by polling the ATN flag in wait loops, we do not want the expected changes on the bus to take us again to the beginning of the routine. Therefore, the EI2 flag is cleared, masking further I2C interrupts even when interrupts are re-enabled (by the ACALL to a RETI instruction). At the label Slave, the routine starts receiving the address on the bus. Each new address bit is read after a software wait loop detects that the ATN flag is set by the hardware. Note that with the single bit implementation of the

December 1990

1

Revision date: June 1993

Philips Semiconductors Microcontroller Products

Application note

I2C slave routines for the 83C751

AN433

I2C port on the 8XC751 the software must closely support the hardware: for example, we need to explicitly clear the Start status before we enter a wait loop for the next bit. If the software does not clear the Start flag, the hardware will stretch the low period of the clock (SCL line) on the bus--and the first address bit will simply not occur. (Such a state will not go on forever--eventually the processor will release the bus as a result of a Timer I timeout.) Reception of the eight bits of Address + R/W is completed using part of the receive byte subroutines. The address received is compared to MyAddr, the address of this specific slave. If the address is different the processor goes idle and leaves the service routine. If the message is intended for this processor (received address matches MyAddr) the Read/Write bit is tested, and the program jumps to the appropriate labels. When the R/W bit is low the master requests a Write--and this slave should receive the data written into it. When the R/W bit is high the master is requesting a Read and this slave should transmit the data (at code label Read). For "Master Write" we send an acknowledge for the address byte and proceed with receiving the data bytes, responding with an acknowledge for each and transferring them into the receive buffer. For long messages, when the buffer is full (we have received MaxByte bytes) we read from the bus one additional byte and then send a negative acknowledge, letting the master know it

should stop sending us data. Then we set DatFlag to signal the mainline program that new data has been received, and jump to MsgEnd. At the MsgEnd label we wait for the next Stop or Repeated Start. On a Stop we resume the idle mode (GoIdle) and return from the service routine. On a Restart the slave process starts again with reception of the new address at the label Slave. If the message is short enough so that the receive buffer is not filled up, the RcvByte subroutine (called after WrtLoop) will return due to the Stop condition, DRDY will not be set, and we shall exit the loop via label WLEx--setting the DatFlag and proceeding to MsgEnd. For "Master Read" the transmit buffer is sent on the bus byte by byte in the RdLoop, using the XmitByte subroutine. We exit the loop when all the buffer is transmitted, or the Master does not respond with an acknowledge. Note that lack of acknowledgement for slave transmission does not necessarily indicate a problem or that the receiving master is busy. This could very well be a normal operation of the protocol, which defines that a receiving master signals the transmitting slave to end its message by explicitly transmitting a negative acknowledge as a response to the last byte the master is interested in. The protocol does not include inherent means for specifying in advance the length of a requested message.

SUBROUTINES
The lower level subroutines closely interact with the hardware and the activity on the bus. The XmitByte subroutine transmits one byte and receives the acknowledge bit that comes in response. The byte receive routine, which one may use from different entry points, receives a data or an address byte, and takes care of acknowledgements. When a Start or Stop is detected the subroutine returns immediately--the calling routine is expected to check the flags to determine whether a whole byte has been received (DRDY will be set), or a Start or a Stop condition has occurred. Close inspection of RcvByte code shows that a total of nine bits are being read off the bus. The first bit does not belong to the received byte, but is the acknowledge this processor sent in response of the former byte or address. Reading the Ack bit from the I2DAT register clears the Transmit Active state and DRDY, thus releasing SCL and allowing the bus activity to proceed to the next data bit. Upon return the Ack bit is left in the Carry flag, and the actual data byte received is returned in the Acc register. Upon Timer I interrupt code execution commences at address 1BH, where there is a jump to the service routine TimerI. This interrupt is caused by the watchdog timer, as a result of an I2C bus that is "hanging" without activity in the middle of a transmission for too long a period of time. The slave simply clears the bus interface, and starts all over again at the label Reset.

December 1990

2

Philips Semiconductors Microcontroller Products

Application note

I2C slave routines for the 83C751

AN433

;***************************************************************************** ; ; ; ; ; ; ; ; ; ; ; ; Sample I2C Slave Routines for the 8XC751 and 8XC752 This program demonstrates I2C slave functions for the 8XC751 and 8XC752 microcontrollers. The program uses separate transmit and receive data buffers that are each eight bytes deep. The sample main program copies received data to the transmit buffer such that transmitted data can be read back by a bus master. Buffer addresses 0 and 1 are mapped to port 1 and 3 respectively, such that an I2C write will affect the port outputs, and an I2C read will return port pin data. The 751 will accept only eight data bytes in any one I2C transmission, additional bytes will not be acknowledged. Similarly, only eight data bytes may be read from the 751 in any one I2C transmission. This program does not support subaddressing for buffer access.

;***************************************************************************** $TITLE(8XC751 I2C Slave Routines) $DATE(11/23/92) $MOD752 ;*****************************************************************************

; Value definitions. CTVAL MaxBytes EQU EQU 02h 8 ; CT1, CT0 bit values for I2C. ; Maximum # of bytes to be sent or ; received.

; Masks for I2CFG bits. BTIR BMRQ EQU EQU 10h 40h ; Mask for TIRUN bit. ; Mask for MASTRQ bit.

; Masks for I2CON bits. BCXA BIDLE BCDR BCARL BCSTR BCSTP BXSTR BXSTP EQU EQU EQU EQU EQU EQU EQU EQU 80h 40h 20h 10h 08h 04h 02h 01h ; ; ; ; ; ; ; ; Mask Mask Mask Mask Mask Mask Mask Mask for for for for for for for for CXA bit. IDLE bit. CDR bit. CARL bit. CSTR bit. CSTP bit. XSTR bit. XSTP bit.

; RAM locations used by I2C routines. RcvDat DATA 10h ; I2C receive data buffer (8 bytes). ; addresses 10h through 17h. ; I2C transmit data buffer (8 bytes). ; addresses 18h through 1Fh. ; I2C software status flags. ; Holds negative acknowledge flag. ; Tells whether an I2C write operation ; has occurred. ; ; ; ; I2C bit counter. Send/receive byte counter. Temporary holding register. Holds address of THIS slave.

XmtDat

DATA

18h

Flags NoAck DatFlag

DATA BIT BIT

20h Flags.7 Flags.6

BitCnt ByteCnt TDAT MyAddr AdrRcvd RWFlag

DATA DATA DATA DATA DATA BIT

21h 22h 23h 24h 25h AdrRcvd.0

; Holds received slave address + R/W. ; Slave read/write flag. 3

December 1990

Philips Semiconductors Microcontroller Products

Application note

I2C slave routines for the 83C751

AN433

;***************************************************************************** ; Begin Code

;***************************************************************************** ; Reset and interrupt vectors. AJMP Reset ; Reset vector at address 0.

; A timer I timeout usually indicates a 'hung' bus. ORG AJMP 1Bh TimerI ; Timer I (I2C timeout) interrupt.

; I2C interrupt is used to detect a start while the slave is idle. ORG PUSH PUSH CLR ACALL 23h PSW ACC ES ClrInt ; ; ; ; ; I2C interrupt. Save status. Save accumulator. Disable I2C interrupt. Re­enable interrupts.

;***************************************************************************** ; Main Transmit and Receive Routines

;***************************************************************************** Slave: MOV JNB MOV ACALL MOV CLR CJNE JB MOV MOV WrtLoop: ACALL ACALL JNB MOV INC DJNZ ACALL ACALL MOV JNB SETB SJMP MOV MOV ACALL MOV CJNE MOV CJNE MOV INC ACALL JB DJNZ I2CON,#BCARL+BCSTP+BCSTR+BCXA ; Clear start status. ATN,$ ; Wait for next data bit. BitCnt,#7 ; Set bit count. RcvB2 AdrRcvd,A ACC.0 A,MyAddr,GoIdle RWFlag,Read R0,#RcvDat ByteCnt,#MaxBytes SendAck RcvByte DRDY,WLEx @R0,A R0 ByteCnt,WrtLoop SendAck RcvByte I2DAT,#80h ATN,$ DatFlag MsgEnd R0,#XmtDat ByteCnt,#MaxBytes SendAck A,@R0 R0,#XmtDat,RdL1 A,P1 R0,#XmtDat+1,RdL2 A,P3 R0 XmitByte NoAck,RLEx ByteCnt,RdLoop ; Get remainder of slave address. ; Save received address + R/W bit. ; Enter idle mode if not our address. ; Read or Write? ; Set up receive buffer pointer. ; Max 4 bytes can be received. ; ; ; ; ; ; ; ; ; ; ; ; Send acknowledge. Get data byte from master. Must be end of frame? Save data. Advance buffer pointer. Back to receive if buffer not full. Send acknowledge. Get, but do not store add'l data. Send negative acknowledge. Wait for acknowledge sent. Flag main that data has been received. Buffer full, enter idle mode.

WLEx:

Read:

; Set up transmit buffer pointer. ; Max bytes to be sent. ; Send address acknowledge. ; Get data byte from buffer. ; Return port 1 value instead of buffer ; data if this is buffer address 0. ; Return port 3 value instead of buffer ; data if this is buffer address 1. ; ; ; ; Advance buffer pointer. Send data byte. Exit if NAK. Back if more data requested & avail.

RdLoop:

RdL1:

RdL2:

December 1990

4

Philips Semiconductors Microcontroller Products

Application note

I2C slave routines for the 83C751

AN433

RLEx: MsgEnd:

SJMP JNB JB

MsgEnd ATN,$ STR,Slave

; Done, enter idle mode. ; Wait for stop or repeated start. ; If repeated start, go to slave mode, ; else enter idle mode.

GoIdle:

MOV POP POP SETB RET

I2CON,#BCSTP+BCXA+BCDR+BCARL+BIDLE ; Enter slave idle mode. ACC ; Restore accumulator. PSW ; Restore status. ES ; Re­enable I2C interrupts.

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

;***************************************************************************** ; Byte transmit routine. ; Enter with data in ACC. XmitByte: XmBit: MOV MOV RL JNB DJNZ MOV JNB MOV RET BitCnt,#8 I2DAT,A A ATN,$ BitCnt,XmBit I2CON,#BCDR+BCXA ATN,$ Flags,I2DAT ; ; ; ; ; ; ; ; Set 8 bits of data count. Send this bit. Get next bit. Wait for bit sent. Repeat until all bits sent. Switch to receive mode. Wait for acknowledge bit. Save acknowledge bit.

; Byte receive routines. ; SendAck : sends an I2C acknowledge. ; RcvByte : receives a byte of data. ; RcvB2 : receives a partial byte of I2C data, used to allow reception of ; 7 bits of slave address information. ; Data is returned in the ACC. SendAck: MOV JNB RET I2DAT,#0 ATN,$ ; Send receive acknowledge. ; Wait for acknowledge sent.

RcvByte: RcvB2: RBit:

MOV BitCnt,#8 ; Set bit count. CLR A ; Init received byte to 0. ORL A,I2DAT ; Get bit, clear ATN. RL A ; Shift data. JNB ATN,$ ; Wait for next bit. JNB DRDY,RBEx ; Exit if not a data bit. DJNZ BitCnt,RBit ; Repeat until 7 bits are in. MOV C,RDAT ; Get last bit, don't clear ATN. RLC A ; Form full data byte. RBEx: RET ; Timer I timeout interrupt service routine. TimerI: SETB MOV MOV ACALL AJMP RETI CLRTI ; Clear timer I interrupt. I2CFG,#0 ; Turn off I2C. I2CON,#BCXA+BCDR+BCARL+BCSTR+BCSTP ; Reset I2C flags. ClrInt ; Clear interrupt pending flag. Reset ; Return to mainline.

ClrInt:

December 1990

5




Others parts begin by an
AN-1   AN-2   AN-3   AN-4   AN-5   AN-6   AN-7   AN-8