Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chapter 11 Inter-integrated Circuit (I 2 C) Interface.

Similar presentations


Presentation on theme: "Chapter 11 Inter-integrated Circuit (I 2 C) Interface."— Presentation transcript:

1 Chapter 11 Inter-integrated Circuit (I 2 C) Interface

2 The I 2 C Protocol Developed by Philips in late 1980s Version 1.0 published in 1992 –Supports standard (100 Kbps) and fast (400 Kbps) mode Version 2.0 published in 1998 –High-speed mode (3.4 Mbps) added Classifies devices into slave and master Allows multiple masters to be attached to the same bus The master device uses either a 7-bit or 10-bit address to specify the slave device as its partner of data communication. Supports bi-directional data transfer Allows multiple masters (microcontrollers) to share the same peripheral devices

3 I 2 C Signal Level Float high and driven low Use the SCL signal to carry clock signal to synchronize data transfer Use the SDA signal to carry data and address The SDA and SCL pins of I 2 C devices (masters and slaves) are open-drain and need external pull up resistors. The resistors 2.2 K  and 1 K  are recommended for 100 Kbps and 400 Kbps baud rate.

4

5 Signal Components I 2 C data transfer consists of 5 signal components: –Start (S) –Stop (P) –Repeated Start (R) –Data –Acknowledge (A)

6 Start Condition Used to indicate that a device would like to transfer data on the I 2 C bus Represented by the SDA line going low when the clock (SCL) signal is high Will initialize the I 2 C bus

7 Stop Condition A condition that a device wants to release the I 2 C bus Is represented by the SDA signal going high when the SCL signal is high Once the stop condition is complete, both the SCL and SDA signals are high. This is the idle bus.

8 Repeated Start (R) Condition A Start signal generated without first generating a Stop condition to terminate the communication Used by the master to communicate with another slave or change data transfer direction without releasing the bus Also referred to as Restart condition

9 Data It represents the transfer of eight bits of information. Data on the SDA line is considered valid only when the SCL signal is high. When the SCL signal is low, the data is allowed to change. The eight-bit data may be a control code, an address, or data.

10 Acknowledge (ACK) Condition Data transfer needs to be acknowledged either positively (A) or negatively (NACK). A device acknowledges a byte it receives positively by bringing the SDA line low during the ninth clock pulse of SCL. If the device allows the SDA line to float high, it is transmitting a negative acknowledge (NACK).

11 Synchronization (1 of 2) All masters generate their clocks on the SCL line to transfer messages on the I2C bus. A defined clock is needed for the bit-by-bit arbitration procedure to take place. Most microcontrollers generate the SCL clock by counting down a programmable reload value using the instruction clock signal. Clock synchronization occurs when multiple masters attempt to drive the I2C bus and before the arbitration scheme can decide which master is the winner. Clock synchronization is performed using the wired-AND connection of I2C interfaces to the SCL line. The high-to-low transition on the SCL line causes the devices concerned (masters) to start counting off their low period.

12 Synchronization (2 of 2) A master device that is counting off their low period will hold the SCL line low until the counter is count down to 0. At this point, the device will release the SCL line to high. If there are other devices holding the SCL low, then the SCL line will remain low until all master devices have counted down to 0. At this point, the SCL line will go high and all devices will start to count high. The SCL line will be held low by the device with the longest low period. By the same reasoning, the high period of the SCL signal is determined by the device with the shortest high period.

13 Handshaking The clock synchronization mechanism can be used as a handshake in data transfer. Slave device can hold the SCL line low after completion of one byte transfer (9 bits). Slave halts the bus until it gets ready for the next operation and then release the SCL line.

14 Arbitration In the event two or more master devices attempt to begin a transfer at the same time, an arbitration scheme is employed to force one or more masters to give up the bus. The master devices continue to transmit data until one master attempts to send a high while the other transmits a low. Since the SDA bus has open drain, the master device that attempts to send a high will detect a low. At this point, it will stop driving the bus. The arbitration process does not slow down the winning master’s transfer and no data gets lost.

15 I 2 C Addressing Methods I 2 C protocol allows master devices to use either the 7-bit and 10-bit address to specify the slave device for data communication. The 7-bit addressing uses the upper 7 bits of the address byte for address and the least significant bit to specify the data transfer direction. The format is shown in Figure The 10-bit addressing uses two bytes to carry the address information. –The bit 0 of the high byte is used to indicate the data transfer direction. –The upper 7 bits have the pattern of xx with xx representing the most significant two address bits of the slave. –The second byte carries the lower 8 address bits.

16 Data Transfer Format (7-bit Addressing) (1 of 2) Master transmitter to slave receiver – shown in Figure Master reads slave immediately after the first byte (address byte) – shown in Figure Combined format. A master may transfer some data to the slave and then generate a restart condition to read data from the slave or send/read data to/from other slave-- shown in Figure

17 Data Transfer Format (7-bit Addressing) (2 of 2)

18 Data Transfer Format—10-bit Addressing (1 of 3) Master transmitter transmits to slave receiver with a 10-bit address –Figure Master receiver reads slave transmitter with a 10-bit address –Figure Restart condition generated in this format Combined format – A master sends data to a slave and then reads data from the same slave. Shown in Figure Combined format – A master sends data to one slave and then transmit data to another slave. Shown in Figure Combined format – 10-bit and 7-bit addressing combined in one transfer. Shown in Figure

19 Data Transfer Format—10-bit Addressing (2 of 3)

20 Data Transfer Format—10-bit Addressing (3 of 3)

21 Overview of the HCS12 I 2 C Module Implements a subset of the I2C protocol Provides interrupts on start and stop bits in hardware to determine if the I 2 C bus is free Supports only 7-bit addressing Supports 100 Kbps baud rate but requires the user to limit the slow rate to no higher than 100 ns if the 400 Kbps baud is to be used Limit the maximum bus capacitance to 400 pF for all conditions. Use PJ7 (SCL) and PJ6 (SDA) pins to support the I 2 C communication. Use five registers to support its operation: –I 2 C Control Register (IBCR) –I 2 C status Register (IBSR) –I 2 C data I/O register (IBDR) –I 2 C Frequency Divider Register (IBFD) –I 2 C Address Register (IBAD)

22

23 Registers for I 2 C Operation I 2 C Address Register (IBAD) –Contains an address to which it will respond when the I 2 C module is configured as a slave device.

24 I 2 C Data Register (IBDR) In master transmit mode, a data transfer is started whenever this register is written into. The most significant bit is shifted out first. In master receive mode, reading this register initiates the reception of the next byte. (The master sends out nine clock pulses to shift in data bits and replies with an acknowledge.)

25 The I 2 C Control Register (1 of 2)

26 The I 2 C Control Register (2 of 2) When setting the MS/SL bit from 0 to1, a start signal is generated on the I 2 C bus and the master mode is selected. In the master mode, the Tx/Rx bit should be set according to the type of transfer required. The TxAK bit specifies the value driven onto the SDA line during data acknowledge cycles for both master and slave receivers. I 2 C module always acknowledges the address matches regardless of the value of TxAK. Writing a 1 to the RSTA bit will generate a Restart condition on the I 2 C bus.

27 The I 2 C Status Register (IBSR) (1 of 2) When a byte is being transferred, the TCF bit is cleared. When the I 2 C is configured as a slave and the address matches, then the IAAS bit will be set. The IBIF bit will be set under three circumstances: –Arbitration lost (IBAL bit is set) –Byte transfer complete (TCF bit is set) –Addressed as a slave (IAAS bit is set)

28 The I 2 C Status Register (IBSR) (2 of 2)

29 I 2 C Frequency Divider Register (IBFD) Four timing requirements to be met: –SCL divider –SDA hold time –SCL hold time for start condition –SCL hold time for stop condition

30 The Use of the IBFD Register (1 of 2) IBC7-IBC6: multiply factor (shown in Table 11.3) IBC5-IBC3: prescaler divider (shown in Table 11.4) IBC2-IBC0: shift register tap points (shown in Table 11.5)

31 The Use of the IBFD Register (2 of 2) Using Table 11.3, 11.4, and 11.5 is a laborious process. These three tables can be combined into the Table –With Table 11.6, finding values to be written into the IBFD register becomes a simple table look up. By dividing the intended baud rate into the bus clock, one can locate one or multiple rows in Table 11.6 with the same SCL divider value. One needs to verify that the SDA hold time, SCL hold time (start), and SCL hold time (stop) all satisfy the timing requirements set out in Table 11.2 before making the selection.

32 Example 11.1 Assuming that the HCS12 is running with a 24 MHz bus clock, compute the values to be written into the IBFD register to set the baud rate to 100 KHz and 400 KHz. Solution: Case 1: baud rate = 100 KHz SCL divider = 24 MHz  100KHz = 240 From Table 11.6, SDA hold time = 33 E clock cycles = ms < 3.45 ms SCL hold time (start) = 118 E clock cycles = 4.92 ms > 4.0 ms SCL hold time (stop) = 121 E clock cycles = 5.04 ms > 4.0 ms The computed value satisfies the timing requirement. Write the value $1F into the IBFD register at 100 KHz baud rate. Case 2: baud rate = 400 KHz SCL divider = 24 MHz  400KHz = 60 From Table 11.6, the corresponding IBC value is $45. SDA hold time = 18 E clock cycles = 0.75 ms < 0.9 ms SCL hold time (start) = 22 E clock cycles = ms > 0.6 ms SCL hold time (stop) = 121 E clock cycles = 1.33 ms > 0.6 ms The computed value satisfies the timing requirement. Write the value $45 into the IBFD register at 400 KHz baud rate.

33 ; parameters are passed in accumulator A (baud rate) and B (slave address) openI2CbsetIBCR,IBEN; enable I2C module staaIBFD; establish SCL frequency stabIBAD; establish I2C module slave address bclrIBCR,IBIE; disable I2C interrupt bsetIBCR,IBSWAI; disable I2C in wait mode rts void openI2C (char ibc, char i2c_ID) { IBCR |= IBEN;/* enable I2C module */ IBFD = ibc;/* set up I2C baud rate */ IBAD = i2c_ID;/* set up slave address */ IBCR &= ~IBIE;/* disable I2C interrupt */ IBCR |= IBSWAI;/* disable I2C in wait mode */ } Configuring the I 2 C Module Compute an appropriate value and write it into the IBFD register. Load a value into the IBAD register if the MCU may operate in slave mode. Set the IBEN bit of the IBCR register to enable I 2 C module. Modify the bits of the IBCR register to select master/slave mode, transmit/receive mode, and interrupt enable mode

34 sendSlaveIDbrsetIBSR,IBB,*; wait until I 2 C bus is free bsetIBCR,TXRX+MSSL; generate a start condition staaIBDR; send out the slave address brclrIBSR,IBIF,*; wait for address transmission to complete movb#IBIF,IBSR; clear the IBIF flag rts void sendSlaveID (char cx) { while (IBSR&IBB);/* wait until I 2 C bus is idle */ IBCR |= TXRX+MSSL;/* generate a start condition */ IBDR = cx;/* send out the slave address with R/W bit set to 1*/ while(!(IBSR & IBIF));/* wait for address transmission to complete */ IBSR = IBIF;/* clear IBIF flag */ } Programming the I 2 C Module Generating Start condition and send slave ID

35 Instruction sequence to send a byte in accumulator A staaIBDR brclrIBSR,IBIF,*; wait until IBIF flag is set to 1 movb#IBIF,IBSR; clear the IBIF flag C statements to send a byte to I 2 C bus IBDR = cx;/* send out the value cx */ while (!(IBSR & IBIF)); /* wait until the byte is shifted out */ IBSR = IBIF;/* clear the IBIF flag */ Instruction sequence to read a byte and acknowledge it bclrIBCR,TXRX+TXAK ; prepare to receive and acknowledge ldaaIBDR; a dummy read to trigger 9 clock pulses brclrIBSR,IBIF,*; wait until the data byte is shifted in movb#IBIF,IBSR; clear the IBIF flag ldaaIBDR; place the received byte in A and also initiate the ; next read sequence

36 C Statements to read a byte from the I 2 C bus IBCR &= ~(TXRX + TXAK);/* prepare to receive and acknowledge */ dummy = IBDR; /* a dummy read */ while(!(IBSR & IBIF));/* wait for the byte to shift in */ IBSR = IBIF;/* clear the IBIF flag */ buf = IBDR;/* place the received byte in buf and also initiate the next read sequence */ Instruction Sequence to Read a Byte, Send NACK, and Generate Stop Condition bclrIBCR,TXRX; prepare to receive bsetIBCR,TXAK; to send negative acknowledgement ldaaIBDR; dummy read to trigger clock pulses brclrIBSR,IBIF,*; wait until the byte is shifted in movb#IBIF,IBSR; clear the IBIF flag bclrIBCR,MSSL; generate a stop condition ldaaIBDR; place the received byte in A

37 C statements to Read a Byte, send NACK, and generate a Stop condition IBCR &= ~TXRX;/* prepare to receive */ IBCR |= TXAK;/* prepare not to acknowledge */ dummy = IBDR;/* a dummy read to trigger 9 clock pulses */ while(!(IBSR & IBIF));/* wait for a byte to shift in */ IBSR = IBIF;/* clear the IBIF flag */ IBCR &= ~MSSL;/* generate a stop condition */ buf = IBDR;/* place the received byte in buf */

38 I 2 C Data Transfer in Slave Mode After reset and stop condition, the I 2 C module is in slave mode. Once in slave mode, the I 2 C module waits for a start condition to come. Following the start condition, eight bits are shifted into the IBAD register. The value of the upper 7 bits of the received byte is compared with the IBAD register. If the address matches, the following events occur: –The bit 0 of the address byte is copied into the SRW bit of the IBSR register. –The IAAS bit is set to indicate the address match. –An ACK pulse is generated regardless of the value of the TXAK bit. –The IBIF bit is set.

39 brset IBSR,IAAS,addr_match ; is address matched? … addr_matchbrclr IBSR,SRW,slave_rd bsetIBCR,TXRX; prepare to transmit data movbtx_buf,IBDR; place data in IBDR to wait for SCL to shift it out brclrIBSR,IBIF,*; wait for data to be shifted out … slave_rdbclrIBCR,TXAK+TXRX; prepare to receive and send ACK brclrIBSR,IBIF,*; wait for data byte to shift in movb#IBIF,IBSR; clear the IBIF flag movbIBDR,rcv_buf; save the received data Instruction Sequence to Make Sure the Addresses Match and Take Appropriate Action

40 The Serial Real-Time Clock DS1307 Uses BCD format to represent the clock and calendar information Has 56 bytes to store critical information Clock calendar provides seconds, minutes, hours, day, date, month, and year information Operates in either the 24-hour or 12-hour format with AM/PM indicator Has built-in power sense circuit that detects power failure and automatically switches to the battery supply The SQW output frequency may be 1 Hz, 4 KHz, 8 KHz, and 32 KHz.

41 -Bit 6 of the hours register selects whether the 12-hour or 24-hour mode is used. -Bit 5 of the hours register selects whether the current time is AM or PM if 12-hour mode is selected. DS1307 Address Map

42 DS1307 Control Register Bit 7 controls the output level of the SQWOUT pin when the square output is disabled. The SQWE bit enables/disables the SQWOUT pin output. Bits 1 and 0 select the output frequency of the SQWOUT pin.

43 Data Transfer DS1307 supports standard mode (100 Kbps) of data transfer. The device address (ID) of the DS1307 is

44 Circuit Connection between the DS1307 and the HCS12

45 Example 11.3 Write a function to configure the DS1307 to operate with the following setting: -SQWOUT output enabled -SQWOUT output set to 1 Hz -SQWOUT idle high when it is disabled -Control byte passed in B Solution: openDS1307 ldaa#$D0; place device ID of the DS1307 in A jsrsendSlaveID brclrIBSR,RXAK,sndRegAdr ; did DS1307 acknowledge? ldab#$FF; return error code -1 rts sndRegAdrmovb#$07,IBDR; send out the control register address brclrIBSR,IBIF,*; wait until the register address is shifted out movb#IBIF,IBSR; clear the IBIF flag brclrIBSR,RXAK,sndok; did DS1307 acknowledge? ldab#$FF rts sndokstabIBDR; send out control byte brclrIBSR,IBIF,*; wait until the control byte is shifted out movb#IBIF,IBSR bclrIBCR,MSSL; generate a stop condition rts

46 char openDS1307(char ctrl) { sendSlaveID(0xD0); /* send out DS1307's ID */ if (IBSR & RXAK) /* if DS1307 did not acknowledge, send error code */ return -1; IBDR = 0x07; /* send out control register address */ while(!(IBSR & IBIF)); IBSR = IBIF; /* clear IBIF flag */ if (IBSR & RXAK) /* if DS1307 did not acknowledge, send error code */ return -1; IBDR = ctrl; /* send out control byte */ while(!(IBSR & IBIF)); IBSR = IBIF; if (IBSR & RXAK) /* if DS1307 did not acknowledge, send error code */ return -1; IBCR &= ~MSSL;/* generate a stop condition */ return 0; }

47 Example 11.4 Write a function to read the time and calendar information from the DIP switches and store them in a buffer to be sent to the DS1307. The DIP switches are driven by Port AD1. Solution: The procedure to enter a bye of information: Outputs a message to remind the user to enter a value. The user sets up a value using the DIP switches and presses the button connected to PJ0 pin to remind (interrupt) the MCU to read the value. MCU reads the value of DIP switches and sends it to the DS1307 treadyds.b1; a flag to indicate that data is ready getTimepshx pshy ldy#buf; Y is the pointer to the buffer movb#$FF,ATD1DIEN; enable Port AD1 for digital inputs bclrDDRJ,BIT0; enable PJ0 pin for input bsetPERJ,BIT0; enable pull-up or pull-down on PJ0 pin bclrPPSJ,BIT0; enable pull-down so that interrupt is rising edge triggered bsetPIEJ,BIT0; enable PJ0 interrupt cli; " movb#0,tready; clear the data ready flag to 0 ldaa#$80; set LCD cursor to the upper left corner jsrcmd2lcd; "

48 ldx#prompty; output the prompt "Enter year:" jsrputs2lcd; " waitytsttready; is new year info. ready? beqwaity;" movbPTAD1,1,y+; save year info. in buffer movb#0,tready ldaa#$80; set LCD cursor to the upper left corner jsrcmd2lcd; " ldx#promptm; output the prompt "Enter month:" jsrputs2lcd; " waitmtsttready; is new month info. ready? beqwaitm;" movbPTAD1,1,y+; save month info. in buffer movb#0,tready; clear the ready flag ldaa#$80; set LCD cursor to the upper left corner jsrcmd2lcd; " ldx#prompte; output the prompt "Enter date:" jsrputs2lcd; "

49 waitetsttready; is new date info. ready? beqwaite;" movbPTAD1,1,y+; save date info. in buffer movb#0,tready; clear the ready flag ldaa#$80; set LCD cursor to the upper left corner jsrcmd2lcd; " ldx#promptd; output the prompt "Enter day:" jsrputs2lcd; " waitdtsttready; is new day info. ready? beqwaitd;" movbPTAD1,1,y+; save day info. in buffer movb#0,tready ldaa#$80; set LCD cursor to the upper left corner jsrcmd2lcd; " ldx#prompth; output the prompt "Enter hours:" jsrputs2lcd; " waithtsttready; is new hour info. ready? beqwaith;" movbPTAD1,1,y+; save hour info. in buffer movb#0,tready ldaa#$80; set LCD cursor to the upper left corner jsrcmd2lcd

50 ldx#promptmi; output the prompt "Enter minutes:" jsrputs2lcd; " waitmitsttready; is new minute info. ready? beqwaitmi;" movbPTAD1,1,y+; save hour info. in buffer movb#0,tready ldaa#$80; set LCD cursor to the upper left corner jsrcmd2lcd; " ldx#prompts; output the prompt "Enter seconds:" jsrputs2lcd; " waitststtready; is new second info. ready? beqwaits;" movbPTAD1,1,y+; save second info. in buffer movb#0,tready puly pulx rts #include "c:\miniIDE\lcd_util_ SSE256.asm" #include "c:\miniIDE\delay.asm" promptsfcc"Enter seconds:" dc.b0 promptmifcc"Enter minutes:" dc.b0

51 promptmifcc"Enter minutes:" dc.b0 prompthfcc"Enter hours:" dc.b0 promptdfcc"Enter day:" dc.b0 promptefcc"Enter date:" dc.b0 promptmfcc"Enter month:" dc.b0 promptyfcc"Enter year:" dc.b0 ; interrupt service routine for PJ0 pin PJ_ISRmovb#1,tready; set tready flag to 1 movb#1,PIFJ; clear the PIFJ0 flag rti

52 Example 11.5 Write a function to send the time and calendar information to the DS1307. The time and calendar information is pointed to by X. The device ID and the starting register address are passed in A and B, respectively. X points to the value of year and the second’s value is located at [X]+6. Solution: sendTimejsrsendSlaveID ; send out device ID of the DS1307 brclrIBSR,RXAK,sndTimeOK1 ; did DS1307 acknowledge? ldab#$FF; return error code -1 if not acknowledged rts sndTimeOK1stabIBDR; send out register address for seconds brclrIBSR,IBIF,*; wait until seconds' address has been shifted out movb#IBIF,IBSR; clear the IBIF flag brclrIBSR,RXAK,sndTimeOK2 ; did 1307 acknowledge? ldab#$FF; return error code -1 if not acknowledged rts sndTimeOK2ldy#7; byte count tfrX,D; set X to point to second’s value addd#6;“ tfrD,X;“ sndloopmovb1,x-,IBDR; send out one byte and decrement pointer brclrIBSR,IBIF,* movb#IBIF,IBSR brclrIBSR,RXAK,sndTimeOK3 ; did DS1307 acknowledge?

53 ldab#$FF; return error code -1 if not acknowledged rts sndTimeOK3dbney,sndloop; continue until all bytes have been sent out bclrIBCR,MSSL; generate a stop condition. ldab#0; return normal return code 0 rts

54 char sendTime (char *ptr, char ID) { char i; sendSlaveID(0xD0); /* send ID to DS1307 */ if(IBSR & RXAK) /* did DS1307 acknowledge? */ return -1; IBDR = 0x00; /* send out seconds register address */ while(!(IBSR & IBIF)); IBSR = IBIF;/* clear IBIF flag */ if(IBSR & RXAK) return -1; for(i = 6; i >= 0; i--) {/* send year first, send second last */ IBDR = *(ptr+i); while(!(IBSR&IBIF)); IBSR = IBIF; if(IBSR & RXAK) return -1; } return 0; }

55 Example 11.6 Write a C function to read the time of day from the DS1307 and save it in the array cur_time[0…6]. Solution: char readTime(char cx) { char i, temp; sendSlaveID(0xD0); /* generate a start condition and send DS1307's ID */ if (IBSR & RXAK) return -1; /* if DS1307 did not respond, return error code * IBDR = cx; /* send address of seconds register */ while(!(IBSR & IBIF)); IBSR = IBIF; /* clear the IBIF flag */ if (IBSR & RXAK) return -1; /* if DS1307 did not respond, return error code */ IBCR |= RSTA; /* generate a restart condition */ IBDR = 0xD1; /* send ID and set R/W flag to read */ while(!(IBSR & IBIF)); IBSR = IBIF; if (IBSR & RXAK) return -1; /* if DS1307 did not respond, return error code */

56 IBCR &= ~(TXRX + TXAK); /* prepare to receive and acknowledge */ temp = IBDR; /* a dummy read to trigger 9 clock pulses */ for (i = 0; i < 5; i++) { while(!(IBSR & IBIF)); /* wait for a byte to shift in */ IBSR = IBIF;/* clear the IBIF flag */ cur_time[i] = IBDR; /* save the current time in buffer */ } /* also initiate the next read */ while(!(IBSR & IBIF)); /* wait for the receipt of cur_time[5] */ IBSR = IBIF;/* clear IBIF flag */ IBCR |= TXAK; /* not to acknowledge cur_time[6] */ cur_time[5] = IBDR; /* save cur_time[5] and initiate next read */ while (!(IBSR & IBIF)); IBSR = IBIF; IBCR &= ~MSSL; /* generate stop condition */ cur_time[6] = IBDR; return 0; }

57 Example 11.7 Write a function to format the time information stored in the array cur_time[0..6] so that it can be displayed on the LCD. Solution: -Store the converted time and calendar information in two arrays: hms[0…11] and mdy[0…11]. -hms[ ] holds hours, minutes, and seconds -mdy[ ] holds month, date, and year Time information display format for 24-hour mode: hh:mm:ss:xx mm:dd:yy Time information display format for 12-hour mode: hh:mm:ss:ZM xx:mm:dd:yy Z can be “A” or “P”, xx stands for day of week such as “SU”, “MN”, etc.

58 void formatTime(void) { char temp3; temp3 = cur_time[3] & 0x07;/* extract day-of-week */ if (cur_time[2] & 0x40) { /* if 12-hour mode is used */ hms[0] = 0x30 + ((cur_time[2] & 0x10) >> 4); /* tens hour digit */ hms[1] = 0x30 + (cur_time[2] & 0x0F); /* ones hour digit */ hms[2] = ':'; hms[3] = 0x30 + (cur_time[1] >> 4); /* tens minute digit */ hms[4] = 0x30 + (cur_time[1] & 0x0F);/* ones minute digit */ hms[5] = ':'; hms[6] = 0x30 + ((cur_time[0] & 0x70) >> 4); /* tens second digit */ hms[7] = 0x30 + (cur_time[0] & 0x0F);/* ones second digit */ hms[8] = ':'; if (cur_time[2] & 0x20) hms[9] = 'P'; else hms[9] = 'A'; hms[10] = 'M'; hms[11] = 0; /* terminate the string with a NULL */

59 switch(temp3) { /* convert to day of week */ case 1: mdy[0] = 'S'; mdy[1] = 'U'; break; case 2: mdy[0] = 'M'; mdy[1] = 'O'; break; case 3: mdy[0] = 'T'; mdy[1] = 'U'; break; case 4: mdy[0] = 'W'; mdy[1] = 'E'; break; case 5: mdy[0] = 'T'; mdy[1] = 'H'; break; case 6: mdy[0] = 'F'; mdy[1] = 'R'; break; case 7: mdy[0] = 'S'; mdy[1] = 'A'; break;

60 default: mdy[0] = 0x20; /* space */ mdy[1] = 0x20; break; } mdy[2] = ':'; mdy[3] = 0x30 + (cur_time[5] >> 4); /* month */ mdy[4] = 0x30 + (cur_time[5] & 0x0F); mdy[5] = ':'; mdy[6] = 0x30 + (cur_time[4] >> 4); /* date */ mdy[7] = 0x30 + (cur_time[4] & 0x0F); mdy[8] = ':'; mdy[9] = 0x30 + (cur_time[6] >> 4); /* year */ mdy[10] = 0x30 + (cur_time[6] & 0x0F); mdy[11] = 0; /* NULL character */ } else {/* 24-hour mode */ hms[0] = 0x30 + ((cur_time[2] & 0x30)>>4); /* hours */ hms[1] = 0x30 + (cur_time[2] & 0x0F); hms[2] = ':'; hms[3] = 0x30 + (cur_time[1] >> 4); /* minutes */ hms[4] = 0x30 + (cur_time[1] & 0x0F); hms[5] = ':';

61 hms[6] = 0x30 + ((cur_time[0] & 0x70)>>4); /* seconds */ hms[7] = 0x30 + (cur_time[0] & 0x0F); hms[8] = ':'; switch(temp3) { /* convert to day of week */ case 1: hms[9] = 'S'; hms[10] = 'U'; break; case 2: hms[9] = 'M'; hms[10] = 'O'; break; case 3: hms[9] = 'T'; hms[10] = 'U'; break; case 4: hms[9] = 'W'; hms[10] = 'E'; break; case 5: hms[9] = 'T'; hms[10] = 'H'; break; case 6: hms[9] = 'F'; hms[10] = 'R'; break;

62 case 7: hms[9] = 'S'; hms[10] = 'A'; break; default: hms[9] = 0x20; /* space */ hms[10] = 0x20; break; } hms[11] = 0; /* NULL character */ mdy[0] = 0x30 + (cur_time[5] >> 4); /* month */ mdy[1] = 0x30 + (cur_time[5] & 0x0F); mdy[2] = ':'; mdy[3] = 0x30 + (cur_time[4] >> 4); /* date */ mdy[4] = 0x30 + (cur_time[4] & 0x0F); mdy[5] = ':'; mdy[6] = 0x30 + (cur_time[6] >> 4); /* year */ mdy[7] = 0x30 + (cur_time[6] & 0x0F); mdy[8] = 0; /* NULL character */ }

63 Example 11.8 Write a function to display the current time and calendar information on the LCD. Solution: void displayTime (void) { cmd2lcd(0x83); /* set cursor to row 1 column 3 */ puts2lcd(hms); /* output hours, minutes, and seconds */ cmd2lcd(0xC3); /* set cursor to row 2 column 3 */ puts2lcd(mdy); /* output month, date, and year */ } Example 11.9 Write the interrupt service routine that reads the time from the DS1307, format the time and calendar information, and display them on the LCD. Solution: void INTERRUPT irqISR (void) { readTime(0x00); /* read all time registers starting from seconds */ formatTime(); /* format time info into two strings */ displayTime(); /* display the time on LCD */ }

64 Digital Thermometer and Thermostat DS1631A (1 of 2) Mainly used to warn the possible overheat of the embedded system to prevent system failure. When the ambient temperature exceeds the trip point, the DS1631A asserts the TOUT signal.

65 Digital Thermometer and Thermostat DS1631A (2 of 2) DS1631A converts temperature into 9-, 10-, 11-, or 12- bit readings over a range of -55ºC to 125ºC. T OUT is asserted whenever the converted ambient temperature is equal to or higher than the value stored in the T H register. Once asserted, the T OUT output will stay high until the temperature drops below the value stored in the T L register. Negative temperatures are represented in twos complement format.

66 DS1631A Registers Config, T H, T L, and Temperature are DS1631A internal registers. –The Config register is 8-bit. –The Config register can be read from and written into. –T H, T L, and Temperature registers are 16-bit.

67

68 Converting the Conversion Result to Temperature The conversion result cannot be higher than 0x7D00 or lower than 0xC900. Table 11.8 shows the a sample temperature reading. Positive Conversion Result –Step 1 Truncate the lowest four bits. –Step 2 Divide the upper 12 bits by 16. Negative Conversion Result –Step 1 Compute the twos complement of the conversion result. –Step 2 Truncate the lowest 4 bits. –Step 3 Divide the upper 12 bits of the twos complement of the conversion result by 16.

69 DS1631A Command Set Start Convert T (0x51) Stop Convert T (0x22) Read Temperature (0xAA) Access TH (0xA1) Access TL (0xA2) Access Config (0xAC) Software POR (0x54)

70 Circuit Connection

71 DS1631A Control Byte (Device ID) Example Write a function to configure the DS1631A in Figure to operate in continuous conversion mode and set the T OUT polarity to active high. Assume that the I 2 C has only one master and there is no possibility in getting bus collision. Solution: –Call the openDS1631 function on the next slide with the configuration byte of 0xE0: ldab#$E0 jsropenDS1631

72 openDS1631ldaa#$92 jsrsendSlaveID brclrIBSR,RXAK,openOK0 ; did DS1631A acknowledge? ldab#$FF; return error code -1 rts openOK0movb#$AC,IBDR; send the "Access Config" command brclrIBSR,IBIF,* movb#IBIF,IBSR; clear the IBIF flag brclrIBSR,RXAK,openOK1; did DS1316A acknowledge? ldab#$FF rts openOK1stabIBDR; sends configuration data brclrIBSR,IBIF,*; wait until the byte has been shifted out movb#IBIF,IBSR; clear the IBIF flag brclrIBSR,RXAK,openOK2; did DS1316A acknowledge? ldab#$FF rts openOK2bclrIBCR,MSSL; generate a stop condition ldab#0; normal return code rts

73 char openDS1631(char cy) { sendSlaveID(0x92); /* generate a start condition and send ID */ if (IBSR & RXAK) return -1; /* error code when DS1631 did not acknowledge */ IBDR = 0xAC; /* send command "Access Config" */ while(!(IBSR & IBIF)); IBSR = IBIF;/* clear the IBIF flag */ if (IBSR & RXAK) return -1; /* error code when DS1631 did not acknowledge */ IBDR = cy; /* send configuration byte */ while(!(IBSR & IBIF)); IBSR = IBIF; if (IBSR & RXAK) return -1; /* error code when DS1631 did not acknowledge */ IBCR&= ~MSSL; /* generate a stop condition */ return 0; /* normal return code */ } C Function to Initialize the DS1631A

74 Example Write a function to command the DS1631A to start temperature conversion. Solution: startConvldaa#$92 jsrsendSlaveID; generate a start condition and send DS1631's ID brclrIBSR,RXAK,startOK0; did DS1631A acknowledge? ldab#$FF; return error code -1 rts startOK0movb#$51,IBDR; send "Start Convert T" command brclrIBSR,IBIF,*; wait until the byte is shifted out movb#IBIF,IBSR; clear the IBIF flag brclrIBSR,RXAK,startOK1; did DS1631A acknowledge? ldab#$FF rts startOK1bclrIBCR,MSSL; generate a stop condition ldab#0; normal return code rts

75 Example Write a function to set the high thermostat temperature. The upper and lower bytes of the high thermostat temperatures are passed in stack. Solution: THhiequ2 THloequ3 setTHldaa#$92 jsrsendSlaveID brclrIBSR,RXAK,setTHok1; did DS1631A acknowledge? ldab#$FF ; return error code -1 rts setTHok1movb#$A1,IBDR; send out access TH command */ brclrIBSR,IBIF,*; wait until command is shifted out movb#IBIF,IBSR; clear IBIF flag brclrIBSR,RXAK,setTHok2; did DS1631A acknowledge? ldab#$FF rts setTHok2ldaaTHhi,sp; get the upper byte of TH from stack staaIBDR; send out TH high byte brclrIBSR,IBIF,* movb#IBIF,IBSR; clear the IBIF flag brclrIBSR,RXAK,setTHok3; did DS1631A acknowledge? ldab#$FF rts

76 setTHok3ldaaTHlo,sp; get the lower byte of TH from stack staaIBDR brclrIBSR,IBIF,* movb#IBIF,IBSR; clear the IBIF flag brclrIBSR,RXAK,setTHok4 ; did DS1631A acknowledge? ldab#$FF rts setTHok4bclrIBCR,MSSL; generate the stop condition ldab#0; normal return code rts Example Write a subroutine to read the converted temperature and return the upper and lower bytes in double accumulator D. Assume that the temperature conversion has been started but this function needs to make sure that the converted temperature value is resulted from the most recent “Start Convert T” command. Solution:

77 readTempldx#0; initialize return error code rdLoopjsrreadConf; is temperature conversion done yet? cmpb#-1; is there any error? beqrdErr; " andb#$80; check DONE bit bplrdLoop; conversion not done yet? ldaa#$92; generate a start condition and send out jsrsendSlaveID; the DS1631A ID brclrIBSR,RXAK,rdTempok1 ; did DS1631A acknowledge? ldx#-1 rts rdTempok1 movb#$AA,IBDR; sends "Read Temperature command" brclrIBSR,IBIF,*; movb#IBIF,IBSR brclrIBSR,RXAK,rdTempok2 ; did DS1631A acknowledge? ldx#-1 rts rdTempok2 bsetIBCR,RSTA; generate a restart condition movb#$93,IBDR; send DS1631A's ID with R/W set to 1 brclrIBSR,IBIF,* movb#IBIF,IBSR brclrIBSR,RXAK,rdTempok3 ; did DS1631A acknowledge? ldx#-1 rts

78 rdTempok3bclrIBCR,TXRX+TXAK; prepare to receive and ACK ldaaIBDR; perform a dummy read brclrIBSR,IBIF,*; wait for high byte of temperature to shift in movb#IBIF,IBSR bsetIBCR,TXAK; prepare send NACK for the last read ldaaIBDR; place the high byte of Temperature in A brclrIBSR,IBIF,*; wait for the low byte read to complete movb#IBIF,IBSR; clear the IBIF flag bclrIBCR,MSSL; generate a stop condition ldabIBDR; place the low byte of temperature in B ldx#0; correct return code rts rdErrldx#-1 rts

79 Serial EEPROM 24LC08B 1 KB capacity Divided into 4 blocks of 256 bytes I 2 C interface Baud rate 400 Kbps Address input A2, A1, and A0 are not used

80 24LC08B Device Address The B1 and B0 bits are block addresses of the location to be accessed. For any access, the master needs to send in the 8-bit address in addition to the EEPROM’s control byte. This address is an address pointer inside the 24LC08B.

81 Write Operation 24LC08B supports byte write and page write operations. The 24LC08B has an internal address pointer. The address pointer increments by 1 after each internal access operation.

82 Acknowledge Polling (1 of 2) The 24LC08B has a buffer to hold the data to be written into the memory. The 24LC08B initiates the internal write operation after the stop condition. Before the internal operation is complete, the 24LC08B will not accept any new write command. It will not acknowledge any control byte transfer. The user can send in the restart condition and the device ID to determine if the internal write operation is complete by checking the RXAK bit of the IBSR register. The algorithm is illustrated in Figure

83 Acknowledge Polling (2 of 2)

84 Read Operation There are three possible read operations: –Current address read –Random read –Sequential read

85 Current Address Read Allows the master to read the byte immediately following the location accessed by the previous read or write operation. On receipt of the slave address with R/W bit set to 1, the 24LC08B issues an acknowledgement and transmit an 8-bit data byte. The master does not acknowledge the transfer, but asserts a STOP condition and the 24LC08B discontinues transmission.

86 Random Read Allow the master to read any memory location in a random manner. The master must send the address of the memory location to be read in addition to the device ID.

87 The Procedure of Random Read Step 1 –Master asserts a START condition and control byte with the R/W bit set to 0 to the 24LC08B. Step 2 –The 24LC08B acknowledges the control byte. Step 3 –The master sends the address of the byte to be read to the 24LC08B. Step 4 –The 24LC08B acknowledges the byte address. Step 5 –The master asserts a Restart condition. Step 6 –The master sends the control byte with R/W = 1. Step 7 –The 24LC08B acknowledges the control byte and sends data to the master. Step 8 –The master asserts NACK to the 24LC08B. Step 9 –The master asserts the STOP condition.

88 Circuit Connection for the 24LC08B Example Write a function to read a byte from the 24LC08B. Pass the control byte and address in accumulators A and B to this subroutine. Return the data byte and error code in A and B, respectively. This function should check the error that the EEPROM did not acknowledge (implies that 24LC08B may have failed). Solution:

89 EErandomRead jsrsendSlaveID; send out 24LC08B ID and block address brclrIBSR,RXAK,ranRdok0; does EEPROM acknowledge? ldab#$FF; return -1, if EEPROM does not ack rts ranRdok0stabIBDR; send out EEPROM memory address brclrIBSR,IBIF,*; wait until the address is shifted out movb#IBIF,IBSR; clear IBIF flag brclrIBSR,RXAK,ranRdok1; does EEPROM acknowledge? ldab#$FF; return -1, if EEPROM does not ack rts ranRdok1bsetIBCR,RSTA; generate restart condition oraa#$01; set R/W bit for read staaIBDR; resend the device ID brclrIBSR,IBIF,*; wait until the EEPROM ID is sent out movb#IBIF,IBSR; clear the IBIF flag brclrIBSR,RXAK,ranRdok2; does EEPROM acknowledge? ldab#$FF; return -1, if EEROM does not ack rts

90 ranRdok2bsetIBCR,TXAK; prepare sent NACK bclrIBCR,TXRX; perform reception ldaaIBDR; dummy read to initiate reception brclrIBSR,IBIF,*; wait for a byte to shift in movb#IBIF,IBSR; clear the IBIF flag bclrIBCR,MSSL; generate a stop condition ldaaIBDR; get the data byte ldab#0; normal read status rts

91 char EErandomRead(char ID, char addr) { char dummy; SendSlaveID(ID); if (IBSR & RXAK) return -1; IBDR = addr; /* send out EEPROM address */ while(!(IBSR & IBIF)); /* wait until the address is shifted out */ IBSR = IBIF; /* clear IBIF flag */ The C Function to Perform Random Read to the 24LC08B (1 of 2)

92 if (IBSR & RXAK) return -1; IBCR |= RSTA; /* generate restart condition */ IBDR = ID | 0x01; /* prepare to read */ while (!(IBSR & IBIF)); IBSR = IBIF; if (IBSR & RXAK) return -1; IBCR |= TXAK; /* prepare to send NACK */ IBCR &= ~TXRX; /* perform reception */ dummy = IBDR; /* dummy read to trigger 9 clock pulses */ while(!(IBSR & IBIF)); /* wait for data to shift in */ IBSR = IBIF; IBCR &= ~MSSL; /* generate a stop condition */ return IBDR; } The C Function to Perform Random Read to the 24LC08B (2 of 2)

93 Example Write a subroutine that writes a byte into the 24LC08B. The device ID, memory address, and data to be written are passed to this routine in the stack. Solution: EE_IDequ5; stack offset for EE_ID EE_addrequ4; stack offset for EE_addr EE_datequ3; stack offset for EE_data EEbyteWritepsha ldaaEE_ID,sp; get the EEPROM ID from stack jsrsendSlaveID; generate start condition, send EEPROM ID brclrIBSR,RXAK,bywriteok1; does EEPROM acknowledge? ldab#$FF; return -1 as the error code pula rts bywriteok1ldaaEE_addr,sp; get the address to be accessed from the stack staaIBDR; send address to I2C bus brclrIBSR,IBIF,*; wait until address is shifted out movb#IBIF,IBSR; clear the IBIF flag brclrIBSR,RXAK,bywriteok2; does EEPROM acknowledge? ldab#$FF; return -1 as the error code pula rts

94 Assembly subroutine to perform byte write (continued) bywriteok2ldaaEE_dat,sp; get the data byte to be written from the stack staaIBDR; send out the data byte brclrIBSR,IBIF,*; wait until data byte is shifted out movb#IBIF,IBSR; clear the IBIF flag brclrIBSR,RXAK,bywriteok3; does EEPROM acknowledge? ldab#$FF; return -1 as the error code pula rts bywriteok3bclrIBCR,MSSL; generate stop condition ldab#0; return error code 0 pula rts

95 char EEbyteWrite(char ID, char addr, char data) { SendSlaveID(ID); if (IBSR & RXAK) /* error if EEPROM does not respond */ return -1; IBDR = addr; /* send out address of the location to be written */ while(!(IBSR & IBIF)); IBSR = IBIF; /* clear the IBIF flag */ if (IBSR & RXAK) /* error if EEPROM does not respond */ return -1; IBDR = data; /* send out the data byte */ while(!(IBSR&IBIF)); IBSR = IBIF; /* clear the IBIF flag */ if (IBSR & RXAK) /* error if EEPROM does not respond */ return -1; IBCR &= ~MSSL; /* generate a stop condition */ return 0; /* normal write code */ } C function to Perform Byte Write to 24LC08B

96 Example Write a function that performs a pagewrite operation. The control byte, starting address of destination and the pointer to the data in RAM to be written are passed to this function. Solution: -It writes a block of up to 16 bytes of data to the 24LC08B. -The block of data to be written is pointed to by X. -The 24LC08B control byte is passed in A. -The starting address of the page is passed in B. -The number of bytes to be written is passed in Y. -The error code is returned in B. EEpageWrite jsrsendSlaveID; generate start condition and send out slave ID brclrIBSR,RXAK,pwriteok1; does the EEPROM acknowledge? ldab#$FF; return error code -1 rts pwriteok1stabIBDR; send out the starting address to be written brclrIBSR,IBIF,*; wait until the byte is shifted out movb#IBIF,IBSR; clear the IBIF flag brclrIBSR,RXAK,w_loop; does the EEPROM acknowledge? ldab#$FF; return error code -1 rts

97 w_loopcpy#0 beqdone_EEwrite; byte count is 0, done movb1,x+,IBDR; send out one byte brclrIBSR,IBIF,*; wait until the byte is shifted out movb#IBIF,IBSR; clear the IBIF flag brclrIBSR,RXAK,okNxt; receive ACK? ldab#$FF rts okNxtdey; decrement byte count braw_loop done_EEwrite bclrIBCR,MSSL; generate a stop condition ldab#0; return error code 0 rts

98 char EEpageWrite(char ID, char addr, char ByteCnt, char *ptr) { SendSlaveID(ID); /* send out EEPROM ID */ if (IBSR & RXAK) return -1; /* return -1 if EEPROM did not respond */ IBDR = addr; /* send out starting address of page write */ while(!(IBSR & IBIF)); /* wait until the address is shifted out */ IBSR = IBIF; /* clear IBIF flag */ if (IBSR & RXAK) return -1; /* return -1 if EEPROM did not respond */ while(ByteCnt) { IBDR = *ptr++; /* send out one byte of data */ while(!(IBSR & IBIF)); IBSR = IBIF; if (IBSR & RXAK) return -1; /* return -1 if EEPROM did not respond */ ByteCnt--; } IBCR &= ~MSSL; /* generate a stop condition */ return 0; }

99 Example Write a C function to implement the algorithm described in Figure Solution: This function will poll the 24LC08B until it completes the internal write operation before it returns. void eeAckPoll (char ID) { SendSlaveID(ID); while(IBSR & RXAK){ IBCR |= RSTA; /* generate a restart condition */ IBDR = ID; /* send out EEPROM ID */ while(!(IBSR & IBIF)); IBSR = IBIF; /* clear the IBIF flag */ } ; /* continue if EEPROM did not acknowledge */ IBCR &= ~MSSL;/* generate a stop condition--indispensable */ }


Download ppt "Chapter 11 Inter-integrated Circuit (I 2 C) Interface."

Similar presentations


Ads by Google