Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Easiest/Cheapest way to snoop I2C traffic?

Status
Not open for further replies.

toodles

New Member
I'm trying to get more information on how the Classic Controller peripheral talks with a 'Wii-mote' for my UPCB project. All of the information I've found so far talks about the memory addresses inside the Wiimote that stores the status of the connected peripheral, and nothing about the communication except that it is a 400KHz I2C bus. The only place I've seen any traffic sniffed is here:
**broken link removed**
The short transmission and language barrier make it not very helpful.

I found the 'cheapi2c' from http://warmcat.com/milksop/cheapi2c.html, however after going through all of the hassle of making the hardware and booting into Linux, I discover that the program doesn't work with 400KHz speed busses, and the reported information was entirely jibberish.

Are there recommendations on ways to snoop the I2C traffic going over this bus? I have a number of PICs here at my disposal (18F2550's, 18F4550's, 16F88's) , and a decently stocked bits bin. If I need to order other chips, I'd be happy to do so. Is there any way to setup the PIC to sniff i2c traffic and store it, preferably in the program flash where there's tons of room? Is there any code out there to use a PIC as a logic analyzer?

Any input is appreciated.
 
any of the pics you have on hand should be plenty fast to "record" i2c transactions, for you to later inspect. if you run those 18f with their pll enabled yielding 40mhz (10 mips), you'll even have time to decode the transactions

I bet there is lots of pic logic analyzer code out there, google can help you find it :)

The only tricky part I foresee analyzing i2c is that the SDA is both rx and tx, so figuring out if it is a master talking or a slave talking will be the real challenge.
 
justDIY said:
The only tricky part I foresee analyzing i2c is that the SDA is both rx and tx, so figuring out if it is a master talking or a slave talking will be the real challenge.
That's why the "monitor" or the middle man is having separate SDA & SCK lines, one set for master and one set for all others slaves. Of course the master/slaves don't know about that.
 
In the simple case of only 2 devices, sender and receiver should be pretty obvious. In the case of more than 2, it shouldn't be too hard to sort things out though you may need to understand the higher level protocol (application layer).
 
justDIY said:
any of the pics you have on hand should be plenty fast to "record" i2c transactions, for you to later inspect. if you run those 18f with their pll enabled yielding 40mhz (10 mips), you'll even have time to decode the transactions
In theory :) My attempt at a simple logic analyzer, just recording the high or low levels of two lines isn't working out so great. I'll post the code in the next post.

justDIY said:
I bet there is lots of pic logic analyzer code out there, google can help you find it :)
I'd be willing to take that bet. The closest I've found in some Atmel code for, luckily enough, doing the exact thing I'm doing. Here: **broken link removed**
Absolutely none for PIC, and I don't think my google-fu is weak.
justDIY said:
The only tricky part I foresee analyzing i2c is that the SDA is both rx and tx, so figuring out if it is a master talking or a slave talking will be the real challenge.
Only one master and only one slave, from what I've read, so just sorting it out should be easy.

eblc1388 said:
That's why the "monitor" or the middle man is having separate SDA & SCK lines, one set for master and one set for all others slaves. Of course the master/slaves don't know about that.
Umm, how would I do that? The SDA and SCK line have to be connected between the master and slave; or are you suggesting I have one PIC pin connected to mastre SDA, one connected to slave SDA, check their status to see who pulled it low, record it, and then set the other to match, and the same for SCK? Hmm. With only two devices, I don't think sorting it out who's sending what will be difficult.
 
Code:
#include <p18cxxx.h>
#include <delays.h>

#pragma config PLLDIV = 5 
#pragma config CPUDIV = OSC1_PLL2 
#pragma config USBDIV = 2 
#pragma config FOSC = HSPLL_HS 
#pragma config IESO = OFF 
#pragma config PWRT = OFF 
#pragma config BOR = ON 
#pragma config VREGEN = ON 
#pragma config WDT = OFF 
#pragma config WDTPS = 1 
#pragma config MCLRE = ON 
#pragma config LPT1OSC = OFF 
#pragma config PBADEN = OFF 
#pragma config CCP2MX = OFF
#pragma config STVREN = OFF 
#pragma config LVP = OFF 
#pragma config XINST = OFF 
#pragma config DEBUG = OFF
#pragma config CP0 = OFF 
#pragma config CPB = OFF 
#pragma config WRT0 = OFF 
#pragma config WRTB = OFF 
#pragma config EBTR0 = OFF 
#pragma config EBTRB = OFF


#define INPUT 				1
#define OUTPUT				0
#define mInitAllLEDs()      TRISCbits.TRISC1=OUTPUT; TRISCbits.TRISC2=OUTPUT;
#define mLED_1              LATCbits.LATC1
#define mLED_2              LATCbits.LATC2
#define mLED_1_On()         mLED_1 = 1;
#define mLED_2_On()         mLED_2 = 1;
#define mLED_1_Off()        mLED_1 = 0;
#define mLED_2_Off()        mLED_2 = 0;
#define mLED_1_Toggle()     mLED_1 = !mLED_1;
#define mLED_2_Toggle()     mLED_2 = !mLED_2;

#define BUFFSIZE 256

#define DISABLE_INTERRUPTS() {while(INTCONbits.GIE) INTCONbits.GIE=0;}  
#define ENABLE_INTERRUPTS() {INTCONbits.GIE=1;}  
		

#pragma udata
unsigned char buff[BUFFSIZE];

#pragma code
void EEpromPut(unsigned char addr, unsigned char data) 
{ 
	unsigned short temp;
	
	
	EEADR = addr;
	EEDATA = data; 
	EECON1bits.EEPGD = 0; 
	EECON1bits.CFGS = 0; 
	EECON1bits.WREN = 1; 

	DISABLE_INTERRUPTS();
	_asm
	MOVLW 0x55
	MOVWF EECON2,0
	MOVLW 0xAA
	MOVWF EECON2,0
	_endasm
	EECON1bits.WR=1;
	while (EECON1bits.WR == 1);
	ENABLE_INTERRUPTS();

	EECON1bits.WREN = 0; 
} 

unsigned char EEpromGet(unsigned char addr) 
{ 
	volatile unsigned char eepTemp; 
	EEADR = addr; 
	EECON1bits.EEPGD = 0; 
	EECON1bits.CFGS = 0; 
	EECON1bits.RD = 1; 
	eepTemp = EEDATA; 
	return eepTemp; 
} 

void main(void)
{
	int counter;
	unsigned char current3, current4;
	
	ADCON1 |= 0x0F; //set all input as digital. 
	TRISB=0x00; // default PORTB to output

	//only ports currently interested in are 3 and 4
	TRISBbits.TRISB3=1;
	TRISBbits.TRISB4=1;
	INTCON2bits.RBPU=0; //enable PORTB internal pull ups
	LATB=0xFF;  //make sure the output PORTB pins are high
	mInitAllLEDs(); //enable output LEDs
	mLED_2_On();
	mLED_1_Off();
	
	
	for(counter=0;counter<BUFFSIZE;counter++)
	{
		current3 = PORTBbits.RB3;
		current4 = PORTBbits.RB4;
		buff[counter] = PORTB; //stash it in the buffer
		while((current3==PORTBbits.RB3) && (current4==PORTBbits.RB4)); //sit and spin until it changes.
	}

	mLED_1_On();
	for(counter=0;counter<BUFFSIZE;counter+)
	{
				EEpromPut(counter, buff[counter]);
	}
	
	while(1)
	{ //blink the light to show us its done
		Delay10KTCYx(250);
		Delay10KTCYx(250);
		Delay10KTCYx(250);
		Delay10KTCYx(250);
		Delay10KTCYx(200); 
		mLED_1_Toggle();
		mLED_2_Toggle();
	
	}
	
	
}

There's the code I'm currently using. Even though it shouldn't, I get repeated bytes written to the EEPROM. It should never write the same byte twice in a row to the EEPROM, yet it does. A series of FF's mostly, and sometimes others. If I leave the probes floating, it will stay there, correctly waiting for one of the lines to go low. If I barely touch them to ground, like 3 quick taps, it will finish and the EEPROM will show repeated repeated patterns. The internal pullups on PORTB are enabled, and the lines are also pulled high on the board with a 10k resistor. Yes, I have a probe connecting the PIC ground to the Wiimote and peripheral ground.

Schematic description:
PIC 18LF2550
20 MHz crystal, 2x 22pf caps and 1M Ohm resistor on the OSC lines.
Powered by a 9 volt battery through a 7805. 10uF cap between 9v and ground, 10uf cap and 2 .1uf caps between the +5 and ground in different places, another .1uf cap right next to the VCC and GND pins of the PIC
220 ohm resistor and LED between +5 and ground
LED between C1 and ground
LED between C2 and ground
10k pullup resistors on RB0 through RB7
10k pullup resistor on MCLR, along with a reset switch between MCLR and ground.
22 ohm resistors on D+ and D- going to a USB plug. USB is not being using because I can't get the USB bootloader to work on the 2550.
.47uF cap between Vusb pin and ground

Using three hook probes, one connected to ground, one on RB4 and one on RB3.


Using the pullup resistors and checking the state of the RB3 and RB4 lines seemed the way to do it. If there is a better way, pleade enlighten me.
 
I'm happy to replace the pullups; I just grabbed the same resistors I've always used for pull ups, but that's always been for tactile switches and the like. If the resistance of the pull up, or the combination with the internal pull-ups, can play a factor, please let me know and I'll be happy to change them. I do know from personal experience that the internal pullups alone can't be trusted.
 
So, let's say I were to start from scratch, and was willing to do the translation to i2c by hand.

What is the best method for snooping digital traffic from another system? I saw some information in one of William's posts about using a 12F675 as a logic probe, and a bit about how he used the analog input to determing if the probe was floating, high or low; but I never saw any code for it or truly understood how it was working.

If any of you were to try and make a logic analyzer using a PIC, how would you go about the detection of the logic levels? Using direction connections tied high doesn't seem at all reliable. What would be a reliable way?
 
I suggest you google for some help, and simply use a PC to do the monitoring (after all you need a PC to display the data), there have been various I2C parallel port interfaces for PC's and monitoring software over the years.
 
As Nigel said the web is a good source for this info. Currently I am waiting on an install so I can give you some background as I understand it.

To determine if a line is floating you need to drive it to some known value. Use two resistors to form a voltage divider. The resistors need to be large enough (ohms) such that they have little effect on a driven line but will pull a floating line to the voltage dividers voltage.

Instead of using VCC and VSS/Gnd to power the voltage divider you could use two PIC pins configured as outputs. Drive one low and one high. When not actually measuring the line the two outputs should be configured as inputs.

I think (not sure) that it is a bad thing to drive the line into the region that is neither a zero or one. To be safe pick a value that is on the high size of the zero range or the low side of the 1 range. Esp if you hardwire the voltage divider to VCC and Gnd.
 
You can figure out which one is driving by inserting a resistor (100 ohms should be good) in the SDA and SCL lines. Place a comparator across that resistor (be sure comparator includes Vcc in its common mode range.) Each device gets a pullup of 2R (where R is your nominal pullup).

When your monitor senses a 'low' on a signal, query the comparator to see who did it.
 
Nigel Goodwin said:
I suggest you google for some help, and simply use a PC to do the monitoring (after all you need a PC to display the data), there have been various I2C parallel port interfaces for PC's and monitoring software over the years.
Really? Name one. Link me to one. Only one that I've found after extensive googling is the cheapi2c project I mentioned in the beginning, which has the fatal flaw of not being able to work with 400Khz speeds; even with 1usec sampling rate on the parallel port (best I got with the old 'digitrace' program was 1.2 usec), its just not enough to accurately analyze data at that speed. If there's a ton of them, please, point them out.

I'm all for the JFGI answer, except I have been googling it, quite a bit. I gave this exact same answer to justDIY, who said the same thing, and like you, no links. Please, fine me ONE project outside of the massive bitscope project, that snoops i2c traffic at 400KHz, or even a regular logic analyzer that will accurately record rates that fast. If google's just chock full of these, it should be an easy find.
 
3v0 said:
As Nigel said the web is a good source for this info. Currently I am waiting on an install so I can give you some background as I understand it.
That's three JFGI answers after repeated statements that I have been. Again, no links.
3v0 said:
To determine if a line is floating you need to drive it to some known value. Use two resistors to form a voltage divider. The resistors need to be large enough (ohms) such that they have little effect on a driven line but will pull a floating line to the voltage dividers voltage.
I understand this part just fine, but I do have a question about the resistor values. The post from nickleflipper implies that different resistances will be needed/or have an affect on different frequency ranges. Do you have any suggestions on where I might find more information on this?
 
Some of then used to be on the Philips website, as the inventers of I2C, including opto-isolated PC interface circuits. I don't know if they still are, or if they were 400KHz compliant?.
 
Interesting link indeed, so twisted pair with grounds for noise immunity. Seen this mentioned before someplace. Wonder if cat5 with no grounds would work as well?

Toodles: the resistor vs. speed recommendation is from a Microchip tutorial called "I2C Master Mode". Must have got this from a device info page like the 16f87X.

Using two seperate proto boards with a foot of plain hookup wire for the I2C bus, a baud of 400kbs seemed reliable. Because each board had there own pullups, the combined R was a little over 1K. Seemed like when experimenting with higher baud rates like 800-900kbs things got sketchy. If you could possibly solder in a dip socket, then pullup experimentation would be easy.

For the most part, if the Pics got locked up, it was because of my crappy coding.
 
toodles, cool project! What is your ultimate goal with this project? I don't know what UPCB is.

I did a little more reading on the subject and found out that the data is actually encrypted by subtracting 0x17 and XORing it with 0x17. That is interesting, I wounder who/how they found out that is the encryption algorithm?
 
Last edited:
Thankes Mike. Unless I'm missing something, I don't think it would work though. For 2 or more channels, the sample time listed is 2us. At 400KHz, or 2.5us per bit, wouldnt that make the reading unusable? You wouldn't be able to see the quick transition points like START, ACK, and STOP.
nickelflippr said:
Interesting link indeed, so twisted pair with grounds for noise immunity.
D'oh, I didnt even think of using that. Thank you.
nickelflippr said:
Toodles: the resistor vs. speed recommendation is from a Microchip tutorial called "I2C Master Mode". Must have got this from a device info page like the 16f87X.
Thanks, I will definitely look that doc up.


Fred.Amoson said:
toodles, cool project! What is your ultimate goal with this project? I don't know what UPCB is.
You can read about it here: **broken link removed**
(And also see some of my current frustrations getting Gamecube working.)
Fred.Amoson said:
I did a little more reading on the subject and found out that the data is actually encrypted by subtracting 0x17 and XORing it with 0x17. That is interesting, I wounder who/how they found out that is the encryption algorithm?
From what I understand, the XOR 0x17 +0x17 is only used when the slave device is initialized with a 0x00 byte. Again, there's lots of data available, but it all seems to be from the viewpoint of those communicating with the wiimote from a PC bluetooth device, with very little to no information on the actual transmissions over the i2c bus. Lots of information for hooking i2c stuff up to the wiimote and controlling or reading it from a PC, but nothing except for my project looking into emulating the way the existing classic controller communicates for the sake of emulating it.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top