Introduction
I frequently have to fool around with new IC’s. However, since a large number of modern day IC’s use the I2C bus, it would be inconvenient and wasteful to build a controller on each and every circuit I prototype for component evaluation. Instead, I built a tool that translates RS232 UART commands into I2C commands. Then, using a program in Java to control my RS232 port from a computer, I can have full access to all the IC’s in one simple bus.
Hardware
This project requires several hardware components. They include the following:
-LP2985-3.3 – Voltage regulator for providing 3.3V to all the digital circuits
-PIC24HJ32GP204 – Microcontroller for translating the UART to I2C and vise-versa
-MAX208 – RS232 Transceiver. RS232 voltage level might blow out of PIC!, so use this to change the voltage levels
-FXO-HC735-10 – 10Mhz Oscillator for 50ppm accuracy (or inaccuracy)
-various connectors, resistors and capacitors
Circuit Notes
Below are the various circuit and sub-circuits for the UART based I2C Controller
Top Level Circuit – Subcircuit connections to connectors
PIC Subcircuit – Physical connections for the PIC24
MAX208 Subcircuit – Physical connections for the MAX208
Regulator Subcircuit – Physical connections for the LP2985-3.3
Oscillator Subcircuit – Physical connections for the FXO-HC735-10 Oscillator
I used a USB connector to provide power. Since the total circuit probably won’t take more than 100mA, it is well withing the 500mA power capacity of a single USB connector from a computer. That way I don’t have to get a AC-DC power supply for the circuit.
The MAX208 (and all MAX200 series of transceivers) uses 5V input voltage. The PIC and the oscillator uses 3.3V! Make sure you get it right or something might blow, or might not work.
Since the EDID chips in monitors and video devices uses I2C, I have included a high density DB15 connector (VGA). This is to facilitate EDID programming for various work related tasks. You don’t need to included if you only want to fool around with I2C chips. Those tasks are done with a 1.25 mm 3 position header.
PIC program
Here’s a .rar file with all the project and program files for this project.
Engscope PIC Controler
Please read the disclaimer before downloading.
You should find an “h” folder with all the headers, as well as the project folder. Just open it with MPLABs 8.10 or higher.
Program Brief
The program is pretty easy to understand. I’ll go over the main.c file, and the pic.c file.
main.c main loop
i2c_init(100); //Initiate I2C channel
UART1Init(15); //Initiate UART1 to 19200 at 10MHz
DelaymSec(1000);
//Main Program Loop, Loop forever
while(1)
{
//process data
PICCProcessEvents();
}
After initiating the ports, an infinite loop is created, and calls the function PICCProcessEvents(). This function takes care of all the receiving and sending on the I2C and the UART ports.
pic.c main function
//main processing event routine
void PICCProcessEvents(void)
{
//get first character
temp = UART1GetChar();
data = 0;
unsigned char addr;
unsigned char subaddr;
unsigned char value;
unsigned char valuehigh;
unsigned char valuelow;
//first char determines command
switch(temp)
{
//Ping Command
case 200:
UART1PutChar(‘1');
UART1PutChar(‘2');
UART1PutChar(‘3');
break;
//Poll Command
case 201:
addr = UART1GetChar();
data = I2Cpoll(addr);
UART1PutChar(data);
break;
//Write I2C
case 210:
addr = UART1GetChar();
subaddr = UART1GetChar();
value = UART1GetChar();
I2Cwrite(addr, subaddr, value);
break;
//Write I2C double byte
case 211:
addr = UART1GetChar();
subaddr = UART1GetChar();
valuelow = UART1GetChar();
valuehigh = UART1GetChar();
I2Cwritedouble(addr, subaddr, valuelow, valuehigh);
break;
//Read I2C
case 220:
addr = UART1GetChar();
subaddr = UART1GetChar();
data = I2Cread(addr, subaddr);
UART1PutChar(data);
break;
//Read I2C double byte
case 221:
addr = UART1GetChar();
subaddr = UART1GetChar();
tempdouble = I2Creaddouble(addr, subaddr);
UART1PutChar(tempdouble.x);
DelaymSec(2);
UART1PutChar(tempdouble.y);
break;
default:
break;
}
}
Here, several functions can be selected through a case statement. First the UART1GetChar() function is called. This function waits for the computer to send a command. If the command is 200 (0xC8), it is a ping command, and simply writes back to the UART a “1,2,3″ character. If the command is 201 (0xC9), then it poll the I2C address. This is done by waiting for the next UART1GetChar() returned value, and using it as the address for the I2C polling. In this manner, all I2C capabilities can be accessed through a computer with a serial port.
Usage
Since there’s been quite a few requests for example code, the project should quell a lot of people. It utilizes both the I2C as well as the UART capabilities of the PIC. When properly constructed, it looks something like this:

As you can see, the circuit connects to my various evaluation circuit with the IC’s that I want to fool around with. I etched the circuit myself and soldered everything on there. The last part to the project is the computer side software. For this you can pretty much use anything that’ll take advantage of the serial port on a computer.
I like to use a program called Terminal (which has been discontinued I think, can’t find the URL anymore), which is very programmable and allows you to send all values through the serial port, not just characters and numbers. However any terminal program will work. RealTerm for example is an excellent free serial terminal program. However, in the end, I ended up writing my own terminal program because I wanted more control over the I2C ports (custom programmability, script execution so I can run 200 I2C commands in sequence over and over again, etc).
Once you have successfully connected to the circuit, and everything is working, you can send your first message to your controller. The first command you should send is the “PING” command, value 200 (0xC8) to see if your circuit works. Once this happens, you should receiver a “1, 2, 3″ values on your terminal software’s receive window (or even just watch it on the oscilloscope).
From then on, just send whatever you like. You can review the I2C and the UART protocols in the tutorial. If for example I want to write to device 0xA0, at sub-address 0×30 the value 0×99, I would have to send the I2C sequence 0xA0 (write), 0×30, 0×99. To send the sequence on my I2C port, I need to send the following UART sequence to my microcontroller: command 210, address 0xA0, subaddress 0×30, value 0×99. In other words, I have to send 4 bytes in order 0xD2, 0xA0, 0×30, 0×99 on the computer’s serial port.
Reading is the similar, to read device 0xA0, sub-address 0×30, I need to send the I2C sequence 0xA1 (read), 0×30, then wait for the read value. To send the sequence I need to send the following UART sequence to my microcontroller: command 220, address 0xA0 (read bit automatically added in the pic24h_i2c.c file), sub-address 0×30 and wait for the read value to come back. After sending 0xDC, 0xA0, 0×30 through the serial port, you should have the value at sub-address 0×30 display on your terminal screen.
That’s basically how it works. There are some other functions in the program, but I’m sure you can figure those out on your own. Happy playing with the toy. Please leave a comment if you have questions!
-J