AN1937 APPLICATION NOTE
I²C Device Driver for DK33xx
The PSD33xx family, from ST, consists of Flash programmable system devices with a 8032 Microcontroller Core, and a complete implementation of the I²C hardware directly on the chip. This application note describes an I²C device driver, and a demonstration program, that has been written for the DK33xx hardware demonstration kit (incorporating a PSD33xx device). The I²C device driver, for the PSD33xx I²C interface, is completely written in the C programming language, and supports both master and slave message transfers in the Interrupt I/O mode. The driver has been tested as thoroughly as possible, but STMicroelectronics cannot guarantee that this I²C driver is flawless in all applications.
DEFINITIONS
The possible operation status of the I²C block in the PSD33xx has been defined in Table 1.. These definitions can be used as return values of the API function, to indicate the current status of the I²C and to control the program flow of the developer's application. Table 1. Status Definition of I²C
Symbol I2 C_MX I2C_MX_END I2C_SX I2C_SX_END I2 C_MR I2C_MR_END I2C_TIME_OUT I2C_SR I2C_SR_END I2C_NACK I2C_BUSLOST I2C_SX_APP Value (decimal) 3 4 5 6 7 8 9 10 11 13 14 15 Co mme nt Indicate I²C device is transmitting in master mode Indicate a transmission has been finished in master mode Indicate I²C device is transmitting in slave mode Indicate a transmission has been finished in slave mode Indicate I²C device is receiving in master mode Indicate a receiving has been finished in master mode Indicate I²C overtime Indicate I²C device is receiving in slave mode Indicate a receiving has been finished in slave mode Indicate I²C no acknowledge Indicate I²C bus lost Indicate I²C slave is required to transmit data to master
April 2004
1/16
AN1937 - APPLICATION NOTE
TABLE OF CONTENTS
DefinitionS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Table 1. Status Definition of I²C. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 External Application Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 The upsd_i2c_init Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 The upsd_i2c_Master_Xmit Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 The upsd_i2c_Master_Recv Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 The upsd_i2c_Slave_Xmit Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 The upsd_i2c_Slave_Recv Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Figure 1. Initialization Flow Chart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Master Transmit Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Figure 2. Master Transmit Mode Flow Chart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Figure 3. Master Transmit Mode ISR Flow Chart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Master Receive Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Figure 4. Master Receive Mode Flow Chart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Figure 5. Master Receive Mode ISR Flow Chart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Slave Receive and Transmit Modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Figure 6. Slave Receive Mode and Slave Transmit Mode Flow Charts . . . . . . . . . . . . . . . . . . . . . 10 Figure 7. Slave Receive Mode and Slave Transmit Mode ISR Flow Chart . . . . . . . . . . . . . . . . . . 11 Demonstration application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Table 2. List of Header Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Table 3. List of C Source Files. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 APPENDIX A.DemonsTration code for Master . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 APPENDIX B.DemonsTration code for Slave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Revision History. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Table 4. Document Revision History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2/16
AN1937 - APPLICATION NOTE
EXTERNAL APPLICATION INTERFACE
The PSD33xx I²C device driver provides five application interface functions for the developer:
upsd_i2c_init upsd_i2c_Master_Xmit upsd_i2c_Master_Recv upsd_i2c_Slave_Xmit upsd_i2c_Slave_Recv
The upsd_i2c_init Function The upsd_i2c_init function performs the initialization, and must be called before any other interface function is called. unsigned char upsd_i2c_init ( unsigned int Bus_Freq, unsigned char Slave_Addr ) This function is used to for the basic configuration of the I²C IP block, using three argument parameters: Bus_Freq specifies the I²C bus frequency Slave_Addr specifies the slave address of the I²C device A `0' is returned if the I²C block has been initialized successfully; otherwise, a `1' is returned. The upsd_i2c_Master_Xmit Function The upsd_i2c_Master_Xmit function handles the data transmission for the bus master. unsigned char upsd_i2c_Master_Xmit ( unsigned char Slave_Addr, unsigned char* Data_Ptr, unsigned char N) The slave address of target I²C device, the pointer to the transmission data buffer and the length of the transmission data buffer are controlled by setting the three parameters: Slave_Addr is the slave address of the I²C device being addressed Data_Ptr is a pointer to the transmission data buffer N is the length of the transmission data buffer The possible return values are: I2C_MX_END, I2C_TIME_OUT, I2C_NACK and I2C_BUSLOST. See Table 1. for descriptions of these return values. The upsd_i2c_Master_Recv Function The upsd_i2c_Master_Recv function handles data reception for the bus master. unsigned char upsd_i2c_Master_Recv ( unsigned char Slave_Addr, unsigned char* Data_Ptr, unsigned char N) The slave address of target I²C device, the pointer to the reception data buffer and length of receiving data buffer are controlled by setting three parameters: Slave_Addr is the slave address of the I²C device Data_Ptr is a pointer to the reception data buffer N is the length of the reception data buffer
3/16
AN1937 - APPLICATION NOTE
The possible return values are: I2C_MR_END, I2C_TIME_OUT, I2C_NACK and I2C_BUSLOST. See Table 1. for descriptions of these return values. The upsd_i2c_Slave_Xmit Function The upsd_i2c_Slave_Xmit function is used, by a slave device, to transmit data to the bus master after the slave has been addressed by a READ command from the bus master. unsigned char upsd_i2c_Slave_Xmit( unsigned char* Data_Ptr, unsigned char* N_Ptr) The two parameters are as follows: Data_Ptr is a pointer to the transmission data buffer N_Ptr is a pointer to a variable for writing the length of the transmission data buffer The possible return values are: I2C_SX_END, I2C_TIME_OUT, I2C_NACK and I2C_BUSLOST. See Table 1. for descriptions of these return values. The upsd_i2c_Slave_Recv Function The upsd_i2c_Slave_Recv function is used to decode commands, as they are received on the I²C bus. unsigned char upsd_i2c_Slave_Recv( unsigned char* Data_Ptr, unsigned char* N_Ptr) If a WRITE command is received on the I²C bus, the slave will subsequently receive data from the I²C bus master. If a READ command is received from the I²C bus, the slave will start up a transmission to reply with the requested data. Data_Ptr is a pointer to the reception data buffer N_Ptr is a pointer to a variable for writing the length of the reception data buffer The possible return values are: I2C_SR_END, I2C_TIME_OUT, I2C_NACK, I2C_BUSLOST and I2C_SX_APP. See Table 1. for descriptions of these return values.
4/16
AN1937 - APPLICATION NOTE
INITIALIZATION
Some pre-configuration is required to initialize pins P3.6 and P3.7 of the PSD33xx as a I²C interface. This includes the alternate function configuration on Port 3, and setting the I²C pre-scaler, the Start/Stop detection time, the I²C interrupt and the own slave address. The Start/Stop detection time configuration and slave address is necessary for an I²C slave. Figure 1. shows the flow chart for the initialization process for the I²C unit of the PSD33xx. Figure 1. Initialization Flow Chart
Start
Configure P3.6, P3.7 as I2C bus P3SFS |= 0xC0;
Enable I2C interrupt on high priority level IPA |= 0x02; IEA |= 0x02; Set up slave address S1ADR=Slave_Addr; Set AA bit; S1CON |= AA;
Bus freq > 833 ? No
Yes
Calculate and set I2C clock prescaler S1CON |= prescaler; Set Start and Stop detection time S1SETUP=0x80; return(1);
return(0);
End
AI09707
5/16
AN1937 - APPLICATION NOTE
MASTER TRANSMIT MODE
The PSD33xx I²C driver supports both Master Transmit and Master Receive modes, with a simple functional interface. In the Master Transmit mode, the status of BUS LOST and NACK need to be handled when the slave address or byte of data has been transmitted in the ISR. For initializing the I²C state machine, a time-out reset has been implemented. Figure 2. and Figure 3. show the flow charts. Figure 2. Master Transmit Mode Flow Chart
Start
EA=0; S1CON |= ENI; Initialize address pointer of transmit buffer and update I2C status to master transmit mode I2C_MX i2c_xmit_buf=Data_Ptr; i2c_data_len=N; i2c_master=1; i2c_xmitr=1; i2c_data_index=0; i2c_state=I2C_MX; Generate a Start condition and transmit a Slave address with a Write bit S1DAT = Slave_Addr; S1CON &= ~STO; S1CON |= STA; S1CON &= ~AA; EA=1; Wait I2C interrupt for a period that is acceptable for I2C master i2c_state = I2C_MX ? Yes Accumulate wait time Toggle++; No
No
Toggle > Max_time ? Yes S1CON &= ~STA; Reset I2C unit; Update I2C current status i2c_state=I2C_TIME_OUT;
return(i2c_state);
AI09708
6/16
AN1937 - APPLICATION NOTE
Figure 3. Master Transmit Mode ISR Flow Chart
I2C ISR Entry
Store S1STA register and clear interrupt flag i2c_sta = S1STA; S1STA &= ~INTR; toggle = 0;
Handle master transmission
Dummy read and update the I2C status to Yes I2C bus lost? I2C_BUSLOST (i2c_sta&BLOST) dummybyte=S1DAT; !=0? i2c_state=I2C_BUSLOST; No Stop transfer and update the I2C status to I2C_NACK S1CON |= STO; S1DAT=dummy; i2c_state=I2C_NACK;
Yes I2C no ACK? (i2c_sta&_ACKREP) !=0? No
Transmit last data with Stop condition and update the I2C status to Yes I2C_MX_END Last byte of data? S1CON |= STO; S1DAT=dummy; i2c_state-I2C_MX_END; No Transmit data and transmit data pointer increment S1DAT=i2c_xmit_buf[i2c_data_index]; i2c_data_index++;
ISR return
AI09722
7/16
AN1937 - APPLICATION NOTE
MASTER RECEIVE MODE
In the Master Receive mode, a NACK must be returned to the slave when the last byte of data has been received in the ISR. For initializing the I²C state machine, a time-out reset has been implemented. Figure 4. and Figure 5. show the flow charts. Figure 4. Master Receive Mode Flow Chart
Start
EA=0; S1CON |= ENI; Initialize address pointer of receive buffer and update I2C status to master receive mode I2C_MR i2c_rcv_buf=Data_Ptr; i2c_data_len=N; i2c_master=1; i2c_xmitr=0; i2c_data_index=0; i2c_state=I2C_MR; Generate a Start condition and transmit a Slave address with a Read bit S1DAT = (Slave_Addr | 0x01); S1CON &= ~STO; S1CON |= STA; S1CON &= ~AA; EA=1; Wait I2C interrupt for a period that is acceptable for I2C master i2c_state = I2C_MR ? Yes Accumulate wait time Toggle++; No
No
Toggle > Max_time ? Yes S1CON &= ~STA; Reset I2C unit; Update I2C current status i2c_state=I2C_TIME_OUT;
return(i2c_state);
AI09709
8/16
AN1937 - APPLICATION NOTE
Figure 5. Master Receive Mode ISR Flow Chart
I2C ISR Entry Handle master reception
IR for address field? Yes
No
I2C no ACK? (i2c_sta & _ACKREP) != 0? Yes
No
Last byte of data?
No
Prepare to receive data dummybyte=S1DAT; i2c_data_index++;
Yes Receive data and receive data pointer increment i2c_rcv_buf[i2c_data_index] =S1DAT; i2c_data_index++;
Yes
Only receive one byte of data? No No Receive data and update the I2C status to I2C_MR_END S1CON |= STO; i2c_rcv_buf[i2c_data_index] =S1DAT; i2c_state-I2C_MR_END; i2c_data_index= i2c_data_len? Yes
Stop transfer and update the I2C status to I2C_NACK S1CON |= STO; dummybyte=S1DAT; i2c_state=I2C_NACK;
S1CON |= AA;
S1CON &= ~AA;
ISR return
AI09721
9/16
AN1937 - APPLICATION NOTE
SLAVE RECEIVE AND TRANSMIT MODES
The PSD33xx I²C driver supports both Slave Transmit and Slave Receive modes, via two interface functions: i2c_Slave_Recv and i2c_Slave_Xmit. For the Slave Transmit mode, the i2c_Slave_Recv function needs to be called first, to detect the READ command from the bus master. Then the i2c_Slave_Xmit function can be called, to transmit data. Figure 6. shows the flow chart for the Slave Receive mode, on the left hand side, and the Slave Transmit mode, on the right. Figure 6. Slave Receive Mode and Slave Transmit Mode Flow Charts
Start Start
EA=0; S1CON &= ~ENI; Initialize address pointer of receive buffer and update I2C status to slave receive mode I2C_SR i2c_rcv_buf=Data_Ptr; i2c_master=0; i2c_xmitr=0; i2c_data_index=0; i2c_state=I2C_SR;
EA=0;
Initialize address pointer of transmit buffer and update I2C status to slave transmit mode I2C_SX i2c_xmit_buf=Data_Ptr; i2c_master=0; i2c_xmitr=1; i2c_data_index=0; i2c_state=I2C_SX;
Enable I2C unit to prepare for receiving S1CON |= ENI;
Fill first data into shift register S1DAT S1DAT=i2c_xmit_buf[i2c_data_index]; i2c_data_index++;
EA=1; Wait I2C interrupt for a period that is acceptable for I2C slave i2c_state = I2C_SR ? Yes Accumulate wait time Toggle++; No
EA=1; Wait I2C interrupt for a period that is acceptable for I2C slave i2c_state == I2C_SX ? Yes Accumulate wait time Toggle++; No
No
Toggle > Max_time ? Yes Disable I2C unit to isolate slave from I2C bus S1CON &= ~ENI;
No
Toggle > Max_time ? Yes
Return the length of received data stream *N_Ptr=i2c_data_index;
Disable I2C unit to isolate slave from I2C bus S1CON &= ~ENI;
Return the length of received data stream *N_Ptr=i2c_data_index;
Update I2C current status i2c_state=I2C_TIME_OUT;
Update I2C current status i2c_state=I2C_TIME_OUT;
return(i2c_state);
return(i2c_state);
AI09710
10/16
AN1937 - APPLICATION NOTE
There are several states that need to be handled in interrupt service routine for slave operation:
A STOP interrupt occurs when a STOP condition has been detected by the slave An Address Field interrupt occurs when the "own slave address" has been received A Data interrupt occurs when a byte of data has been received or transmitted by the addressed slave
Figure 7. shows a flow chart for the overall Slave Operation ISR. Figure 7. Slave Receive Mode and Slave Transmit Mode ISR Flow Chart
I2C ISR Entry Handle slave transfer
Stop? (i2c_sta&STOP) !=0? Yes No Addressed? i2c_slave_addressed =1? Yes
No
Address field? ((S1CON&ADDR!=0)& (S1CON&AA)!=0)? Yes No Clear ADDR flag and set addressed flag S1CON &= ~ADDR; i2c_slave-addressed=1;
No
Slave receiving? i2c_xmitr=0? Yes
Addressed? i2c_slave_addressed =1? Yes
No
Mark as unaddressed and update I2C status to I2C_SR_END i2c_slave-addressed=0; i2c_state=I2C_SR_END; Disable I2C unit to isolate slave from I2C bus S1CON &= ~ENI;
Slave receiving? i2c_xmitr=0? Yes
No
Slave receiving? i2c_xmitr=0? Yes
No
No
I2C no ACK?
Release SCL line S1DAT=dummy;
Yes Release SCL line S1DAT=dummy;
Mark as unaddressed and update I2C status to I2C_SX_END i2c_slave-addressed=0; i2c_state=I2C_SX_END; Disable I2C unit to isolate slave from I2C bus S1CON &= ~ENI;
Receive data and receive buffer pointer increment Update I2C status to I2C_SX_APP; i2c_state=I2C_SX_APP; i2c_rcv_buf[i2c_data_index] =S1DAT; i2c_data_index++;
Transmit data and transmit buffer pointer increment S1DAT= i2c_xmit_buf[i2c_data_index]; i2c_data_index++;
ISR return
AI09711
11/16
AN1937 - APPLICATION NOTE
DEMONSTRATION APPLICATION
For demonstration of this driver, for both master and slave modes, a simple demonstration program is supplied, based on the I²C driver. It consists of the following files: Table 2. List of Header Files
Name uPSD3300.H Turbo_HARDWARE.H Turbo_I2C.H Turbo_TIMER.H Turbo_LCD.H Description The main header with definition of all PSD registers, areas and basic types Short header with definition of PSD and LCD block start address as well as PSD's oscillator Header of I²C driver Header of Timer0 driver Header of LCD driver
Table 3. List of C Source Files
Name MAIN.C Turbo_I2C.C Turbo_TIMER.C Turbo_LCD.C The main routine(s) I²C driver, I²C ISR Timer0 driver LCD driver Description
The I²C demonstration program performs the following: 1. The master transmits 255 bytes of data to the slave. If successful, the message "Transmit OK" is shown on the LCD for the master, and "Received FF bytes" is shown on the slave's LCD. 2. The master asks the slave for 255 bytes of data. The slave returns the 255 bytes that it received in step1. If successful, the message "Receive OK" is shown on the master's LCD, and "Sent FF bytes" is shown on the slave's. 3. The master checks if they are the same as the data bytes that it transmitted. If so, the message "Match OK" is shown on the LCD of the master (or "No match", if not). 4. The program loops back to step1. To run this demonstration, two DK3300 boards are required: one to be programmed as the I²C Master, and the other as the I²C Slave. They need to be connected on an I²C bus, consisting of three wires:
C ON 1 . 7 - S C L C ON 1 . 8 - S D A G ND
CONCLUSION
This document gives the user an idea of how simple it is to work with the I²C interface of the PSD33xx, using the given device driver. The demonstration program helps to illustrate how simple it is to use the device driver.
12/16
AN1937 - APPLICATION NOTE
APPENDIX A. DEMONSTRATION CODE FOR MASTER
/*-----------------------------------------------------------------------------Demo for I2C Master ------------------------------------------------------------------------------*/ #include "upsd3300.h" #include "Turbo_hardware.h" #include "Turbo_i2c.h" #include "Turbo_timer.h" #include "Turbo_LCD.h" #define I2C_ADDR 0x88 #define buf_len 255 xdata unsigned char temp_xmit_buf[255]; xdata unsigned char temp_rcv_buf[255]; xdata PSD_REGS PSD8xx_reg _at_ PSD_REG_ADDR;
// message xmit buffer // message rcv buffer
bit match_buf(unsigned char* a, unsigned char* b, unsigned char length) { unsigned char i; for(i=0;i
13/16
AN1937 - APPLICATION NOTE
} }
APPENDIX B. DEMONSTRATION CODE FOR SLAVE
/*-----------------------------------------------------------------------------Demo for I2C Slave mode ------------------------------------------------------------------------------*/ #include #include #include #include #include "upsd3300.h" "Turbo_hardware.h" "Turbo_I2C.h" "Turbo_timer.h" "Turbo_LCD.h"
#define I2C_ADDR 0x88 xdata unsigned char temp_xmit_buf[255]; xdata unsigned char temp_rcv_buf[255]; xdata PSD_REGS PSD8xx_reg _at_ PSD_REG_ADDR; main() { unsigned char i,k,temp; static unsigned char *temp_data_len,r; PSD8xx_reg.VM |= 0x80; timer0_init(); lcd_init(); printfLCD("I2C slave_V0.2"); upsd_i2c_init (833,I2C_ADDR); // initialize timer0 interrupt // initialize LCD //display on LCD // initiate I2C interface // I2C xmit buffer // I2C rcv buffer
while(1){ k++; temp=upsd_i2c_slave_Recv(temp_rcv_buf,temp_data_len); if(temp==I2C_SR_END){ r=*temp_data_len; printfLCD("\nReceived %x byte\n",r);delay_1sec(); } else if(temp==I2C_SX_APP) { for(i=0;i
14/16
AN1937 - APPLICATION NOTE
REVISION HISTORY
Table 4. Document Revision History
Date 26-Apr-2004 Version 1.0 First Issue Revision Details
15/16
AN1937 - APPLICATION NOTE
If you have any questions or suggestions concerning the matters raised in this document, please send them to the following electronic mail addresses: ask.memory@st.com (for general enquiries) Please remember to include your name, company, location, telephone number and fax number.
Information furnished is believed to be accurate and reliable. However, STMicroelectronics assumes no responsibility for the consequences of use of such information nor for any infringement of patents or other rights of third parties which may result from its use. No license is granted by implication or otherwise under any patent or patent rights of STMicroelectronics. Specifications mentioned in this publication are subject to change without notice. This publication supersedes and replaces all information previously supplied. STMicroelectronics products are not authorized for use as critical components in life support devices or systems without express written approval of STMicroelectronics. The ST logo is a registered trademark of STMicroelectronics. All other names are the property of their respective owners. 2004 STMicroelectronics - All rights reserved STMicroelectronics GROUP OF COMPANIES Australia - Belgium - Brazil - Canada - China - Czech Republic - Finland - France - Germany Hong Kong - India - Israel - Italy - Japan - Malaysia - Malta - Morocco - Singapore Spain - Sweden - Switzerland - United Kingdom - United States www.st.com
16/16
|