Introduction
In this article, we describe how the I2C protocol could be simulated in a Visual Studio C# application. I2C is a widely used device low end communication protocol. Various computer peripherals comply with I2C protocols, for example: memories, PDAs, cell phones etc. Usually, to access these peripherals, computers require an additional microcontroller/microprocessor. This significantly increases the cost of the device product. This article presents a possible solution to this problem; it describes how a C# application running on a Windows® OS can access an I2C peripheral.
Background
The I2C peripheral interface was invented by Philips Electronics NV. This protocol is popularly used in processors’ communication with memory devices, PDAs, cell phones, etc.
And, C# is a horse power language supported by Microsoft Visual Studio; C# is a kind of language that equips the programmer with versatile features inherited from Java as well as C++. From the evolution of C# it has been an issue of controversy that it is a direct travesty of Java, but features like LINQ and safe switching to pointers prove C# as more advanced compared to its counterparts. Applications built on C# are equally efficient in data acquisition process as are MATLAB and Labview. In C# we don’t need any kind of extras like ActiveX or mscomm objects as in VB6 or VC++ 6.0. The SerialPort
class in C# is enough to support simple hardware at a variety of baud rates.
Usually, a C# application communicates with I2C using a bridge microcontroller. This type of communication scheme is shown in Fig 1.
Fig 1: A usually followed scheme for communicating an I2C device through a C# application.
There are certain disadvantages to this scheme and we are going to discuss these disadvantages in the next section.
Demerits of indirect communication
The scheme (shown in figure 1) suffers with following disadvantages:
Dm = d1 + d2 …………………….(1)
This delay will be significant in applications demanding quick data acquisition (it is always desirable to have less delay). The usual value of d1= 20ms (at 9600 baud).
- As we can observe there is a two stage communication involved; the first application communicates with a microcontroller, then it communicates with the I2C device. Let d1 and d2 be delays involved in these stages, respectively. The total delay in the communication process will be :
- Secondly, microcontroller cost is also an undesirable factor in peripheral manufacturing. Microcontrollers (having RS232 as well as I2C) are available at a variety of costs (usually ranging from $9 to $30). And a costly microcontroller can substantially increase the final cost of the prototype.
Undoubtedly, eradication of microcontrollers from the scheme (shown in figure 1) would be advantageous in terms of low processing time as well as in cost reduction of the final device.
Emulation as a possible solution
Since, in C#, a programmer is equipped with the SerialPort
class (this class contains lots of methods for sending and receiving ), serial port is an easy interface for applications built in C# to communicate with the outside world. These pins on the serial port could be directly accessed from the application. These pins are: RTS , DTR and CTS (Refer to figure 2). RTS and DTR are output pins, i.e., a C# software application can write these pins with a boolean value which it wants. While CTS is an input pin, a software application can read a boolean value from this pin.
With these pins, can we emulate the I2C protocol? Of course, yes. Actually, I2C devices communicate with a microcontroller with two pins, SCL and SDA. A sample I2C device is shown (in figure 3). If we reference the ground levels, the RS232 port of PC and I2C devices are the same, and we follow connections given in table 1, I2C could be easily emulated, rendering the microcontroller of the scheme (shown in figure 1) as redundant. It might look strange, but the application can write a bit for the SDA pin; while, simultaneously, the application can read a bit value from SDA with the help of CTS. The only complexity is to implement the whole of the I2C protocol in C# code. Once the required code library is ready, C# programmers can perform operations like: data acquisition (I2C sensor ICs like DS1621), memory access, communication with cellphones, etc., in a hassle free manner. Moreover, there will be no overload of firmware programming in microcontrollers.
Fig 2: RS 232 DB9 Pinout
Fig 3: DS1621(an I2C device) pinout
I2C Protocol at Glance
Fig 4: Timing diagram of I2C bus (please zoom it to see properly)
The I2C is a bidirectional 2-wire bus. A device that sends data is identified as a transmitter, and a device receiving the data is identified as a receiver. It is responsibility of the master device to generate an SCL (clock signal). Usually, connections between these devices (SDA and SCL lines) are made via the open-drain bidirectional lines. The following bus protocol has been defined (see Figure 4):
- Data is initiated when the bus is idle.
- The data line (SDA) must remain stable when the clock line (SCL) is HIGH. In case there is a transition in SDA while SCL is high, it would be interpreted as a control signal.
Important bus conditions:
- When SCL and SDA both are high, bus is idle.
- Transition of SDA from high to low, while the clock is high, defines a START.
- Transition of SDA from low to high, while the clock is high, defines a STOP.
- After START, state of SDA defines data bit (1 or 0) for SCL=1(high). Each bit of data is transmitted in one clock pulse. Data transmission is terminated with a STOP or another START (abandoning previous transmission and start of a new one). Any number of bytes could transferred between START and STOP conditions The information is transferred byte-wise, and it is an obligation for receiver to acknowledge with a ninth-bit. The master device is responsible for generation an extra clock pulse which is associated with this acknowledge bit. A device that acknowledges, makes SDA line low, and this must remain low when SCL is high (for acknowledgement clock pulse).
- To end the data transmission slave puts the data line to high, so that the master could generate the STOP.
If R/W bit (in Figure 4) is 1, data is transferred from master to slave. In this first byte master first sends address of slave, and slave returns an acknowledgement for this.
On the other hand, if R/W bit is 0, data flow is from slave to master. Here also, master first sends the slave’s address, slave returns an acknowledge bit. After this, slave sends the data bytes to the master. Master returns an acknowledgement when it receives all the bytes expect the last one. When last byte is received , a ‘not acknowledge’ is returned by master.
In the next section we will see C-sharp implementation of this protocol. It should be noted that this section just mentioned some peripheral details of I2C protocol.
C# Emulation of I2C
In this article, DS1621( a temperature sensor IC, please refer [9] for its specifications) is used as an example of an I2C device. Emulation is divided in following two parts:
Fig 4: Schematic of hardware used for the emulation
- Hardware: Figure 5 shows schematic of hardware used for emulation. It could be seen from schematic that no microcontroller is used, for interfacing RS232 with DS1621. Schematic consists of couple of 5.1 V zeners and couple of 470 ohm resistances. These resistances and zeners are used to protect circuitry against high RS232 voltages. A LED with resistance is provided to indicate power supply in the system. A popular voltage converter LM7805 is used to provide 5V stable DC output from a 9V DC power jack. Please refer to figure 2. for corresponding pin names (DTR, CTS and RTS) of RS232 to pin numbers given in schematic. We see can that connections are in accordance with as described in third section of this paper. (Hardware PCB files are in supplementary material provided with this paper click here).
- Software: This is the C-sharp application for emulation of I2C protocol. To maintain understandability of code. I have made this application as console (no GUI). Methods used in this code are detailed in table 1.
Table 1: Functions in code and their brief descriptions.
Methods
|
Description
|
spinit
|
This function initializes a ‘serial port’ object. It also sets initial SCL and SDA states
|
sample
|
This function samples SDA state, whenever SCL =1(High).
|
startcmd
|
This provides START in I2C protocol.
|
stopcmd
|
This provides STOP in I2C protocol.
|
tx_1
|
This function transmits 1 to I2C device.
|
tx_0
|
This function transmits 1 to I2C device.
|
tx_byte
|
This method transmits a byte to I2C device.
|
rx_bit
|
Through this method application reads a bit coming from I2C device.
|
rx_byte
|
Through this method application reads a byte from I2C device.
|
one_shot_mode
|
This method is specific for DS1621; it starts one shot mode temperature conversation.
|
Start_convert_temperature
|
This method is specific for DS1621; it starts temperature conversion sequence.
|
read_temperature
|
This method reads temperature in 2 byte format.
|
issue_read_temp
|
This method implements the read_temperature method with proper initiation.
|
Main
|
This method is code entry point method.
|
The main method first calls spinit
for required initialization of ‘serialport’ (this class provides interface with RS232 in C#) instance. Then after, main calls issue_read_temp
.
issue_read_temp
provides a sequence to read temperature from DS1621 using I2C protocol.
The application runs with a console window. It first asks its user to provide port number to which I2C device is connected. When user provides the required information (port number), application takes some time, and if everything goes well (no runtime trouble), application successfully calculates the temperature and delivers it to the user interface.
It was verified that temperature values given by application are correct (by means of comparing temperature values with simple mercury thermometer readings).
Hence, we can say, that application successfully emulates I2C protocol. Using this scheme we are successful in elimination of microcontroller in C# applications dealing with I2C devices.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
namespace ConsoleApplication8
{
class Program
{
public static SerialPort sp;
public static void spinit(int sn) {
sp =new SerialPort("COM"+sn);
Console.WriteLine("openning the port..........");
try{
sp.Open();
}
catch(Exception ex){
Console.WriteLine("Cannot open port following exception occured:" + ex.Message.ToString());
}
sp.RtsEnable = true;
sp.DtrEnable = true;
}
public static bool sample()
{
return sp.CtsHolding;
}
public static void startcmd()
{
sp.DtrEnable= true;
sp.DtrEnable= true;
sp.RtsEnable = true;
sp.DtrEnable = false;
}
public static void stopcmd()
{
sp.DtrEnable =true;
sp.DtrEnable = false;
sp.RtsEnable = true;
sp.DtrEnable = true;
}
public static void tx_1()
{
sp.RtsEnable = false;
sp.DtrEnable=true;
sp.DtrEnable = true;
sp.RtsEnable = true;
sp.RtsEnable= false;
}
public static void tx_0()
{
sp.RtsEnable = false;
sp.DtrEnable= true;
sp.DtrEnable = false;
sp.RtsEnable = true;
sp.RtsEnable = false;
}
public static bool tx_byte(string b)
{
foreach (char c in b)
{
if (c == '0')
tx_0();
else if (c == '1')
tx_1();
}
return rx_bit();
}
public static bool rx_bit()
{
bool temp;
sp.DtrEnable = true;
sp.RtsEnable = false;
sp.RtsEnable = true;
temp = sample();
sp.RtsEnable = false;
return temp;
}
public static int rx_byte(bool ack)
{
int i;
int retval=0;
for(i = 0;i <=7;i++)
{
retval = retval * 2;
if(rx_bit())
retval = retval + 1;
}
if(ack)
tx_0();
else
tx_1();
return retval;
}
public static void one_shot_mode()
{
startcmd(); tx_byte("10010000");
tx_byte("10101100");
tx_byte("00000001");
}
public static void Start_convert_temperature()
{
startcmd();
tx_byte("10010000"); tx_byte("11101110"); stopcmd();
}
public static double read_temperature()
{
int temperature_MSB;
int temperature_LSB;
startcmd();
tx_byte("10010000");
tx_byte("10101010");
startcmd();
tx_byte("10010001");
temperature_MSB = rx_byte(true); temperature_LSB = rx_byte(false); stopcmd();
double temp = ((temperature_MSB * 256 + temperature_LSB))/256;
if (temperature_MSB >= 128)
temp = temp - 256;
return temp;
}
public static double issue_read_temp()
{
stopcmd();
one_shot_mode();
return read_temperature();
}
static void Main(string[] args)
{
Console.WriteLine("Enter the COM port number where Hardware is connected :");
spinit(int.Parse(Console.ReadLine()));
Console.WriteLine("Temperature Value of DS1621 is :");
int i = 0;
Console.WriteLine(issue_read_temp());
while (i < 20)
i++;
Console.ReadKey();
}
}
}
Fig 5: A screen shot of application run.
Conclusion
This article presents a novel approach for communication of a C# application with an I2C device. Conventionally, C# applications first communicate with microcontrollers using a serial communication protocol, and then it is the microcontroller which is responsible for communication with the I2C device. In contrast, this paper presents a scheme in which there is no need of microcontroller for a C# application to communicate with an I2C device. In this scheme, the C# application emulates I2C protocol directly over the RS232 port (DB9 serial). Since there is no need of microcontroller in this scheme, it eliminates firmware overhead and the final cost associated with prototyping. Moreover, unnecessary delay of data processing by microcontroller is also avoided. To verify the proposed scheme, it was successfully demonstrated by emulation of I2C by a C# console application over DS1621 (an example I2C device).
References
- [1]The I2C-bus and how to use it (including specifications), Philips Semiconductors, 1995 updated
- [2] Wylie Wong (2002). "Why Microsoft's C# isn't". CNET: CBS Interactive. Retrieved November 14, 2009.
- [3] C# Language Specification (4th ed.). Ecma International. June 2006 . Retrieved January 26, 2012.
- [4] Vyas, Nakul; , "A pragmatic carbon tax billing regime," Wireless and Optical Communications Networks (WOCN), 2012 Ninth International Conference on , vol., no., pp.1-7, 20-22 Sept. 2012
- [5] Visual Basic: MSComm Control, Microsoft Developers Network (MSDN), Library
- [6] SerialPort Class, Microsoft Developers Network (MSDN), Library
- [7] EIA standard RS-232-C: Interface between Data Terminal Equipment and Data Communication Equipment Employing Serial Binary Data Interchange. Washington: Electronic Industries Association. Engineering Dept. 1969.
- [8] D-sub 9 Connector Pinout
- [9] Datasheet: Atmel ATMega32 L
- [10] Datasheet: Maxim DS1621
Note: Please use the PCB file here (to open this file you will need a free version of DIPTRACE Software) attached with this project for quick development of the prototype.