I2C x-Box code from Jarin the Penguin
Jarin the Penguin posted the following code to XBOXHACKER, which
is interesting as it exposes the I2C controller footprint in the X-Box IO
space and shows how to use it. (You should note this code has a subtle
bug, smalldelay() will be return immediately occasionally when it is called
just as GetTickCount() is going to be updated after the first line. Also,
at least on a PC, the resolution of GetTickCount() is 20 or 50 mS units
at a time typically, the scheduler timeslice size). Just in case I
wasn't clear enough, this is not my code, it is in the public domain now
and we can thank Jarin the Penguin for sharing it.
/////////////////////////////////////////////// // Jarin The Penguin's Xbox LED/SMBus example.
#include <xtl.h> #include <conio.h> // LED states // Cx means cycle stage x // e.g. to get the green LED to flash every other cycle, use LED_GREEN_C0|LED_GREEN_C2 #define LED_RED_C0 0x80 #define LED_RED_C1 0x40 #define LED_RED_C2 0x20 #define LED_RED_C3 0x10 #define LED_GREEN_C0 0x08 #define LED_GREEN_C1 0x04 #define LED_GREEN_C2 0x02 #define LED_GREEN_C3 0x01
// delay for 1ms void smalldelay(int count) { u32 before = GetTickCount(); s32 diff; do { diff = GetTickCount() - before; } while(diff < count); }
// write a command to the SMBus void WriteSMBusCommand(u8 SlaveAddress, u8 CommandCode, bool WriteWordValue, u16 DataValue) { u16 val; _outp(0xc004, SlaveAddress&0xfe); _outp(0xc008, CommandCode); _outpw(0xc006, DataValue); val = _inpw(0xc000); _outpw(0xc000, val); // Do we use WriteByte or WriteWord mode? _outp(0xc002, (WriteWordValue) ? 0x1b : 0x1a); }
// Set the Xbox LEDs to the given state sequence. void SetLEDs(u8 states) { WriteSMBusValue(0x20, 8, false, states); smalldelay(1); // these delays may not be necessary, but it was flaky without them. WriteSMBusValue(0x20, 7, false, 1); smalldelay(1); }
void __cdecl main() { // Set funky flashing sequence. SetLEDs(LED_RED_C0|LED_GREEN_C1|LED_RED_C2|LED_GREEN_C2); // Halt CPU while(true) { } }
|
I2C traffic analysis
Dissatisfied with my old logic analyser's efforts, today I wrote some
new VHDL to turn an existing platform I designed for another purpose (using
a Virtex 400e) into a specialized I2C snooper with 512K clock memory and
connection to a PC.
My first important discovery was that X-box software people and I2C hardware
people use different nomenclature for I2C addresses. When visor tells
me that the PIC appears at I2C address 20h, he means that the seven bit address
of the PIC is 0010 000, which you may express in an 8-bit byte as 0010 0000
(20h). The I2C world (including all the datasheets, etc) refers to
that address as 10h, ie, (x)001 0000. So you should take note that
I2C addresses appearing here are all in I2C format, and you may need to shift
them one bit left if you are used to X-Box addresses.
Here are the textual dumps of the traffic. the format is <I2c
address> <r|w> { payload traffic ... }
- ( a further eight startups for comparison 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 )
<-- new 2002-06-16
Obviously the most interesting ones are the startup ones. They are
of the same length (3 thru 10 have a additional set of background noise
at the end, but they are the same up to then), but some individual bytes
are different (maybe RTC-related, I haven't time to look at them now). You
can see the entire contents of my EEPROM being brought across in the block
of accesses to/from address 54h. In fact I see only four I2C addresses
in use:
54h
|
EEPROM
|
10h
|
PIC
|
45h
|
Conextant Video encoder
|
4Ch
|
ADM1032 System temperature monitor
|
It is suspected some interesting watchdog type traffic is issued during
the startup sequence, which should now be available in these dumps for people
to try. Remember, these addresses need doubling to conform to x-Box
terminology. (thanks again to visor for describing 45h and 4Ch devices)
Note on safety
Your X-Box floats - it doesn't have an earth connection. There
is quite a difference in potential between a standard X-Box and earth ground;
I can make little sparks by touching the chassis of the X-box with my eath-ground
scope probe ground clip. You will likely damage your PC if you attempt
to connect it without ensuring that the X-Box agrees with your PC about the
relative potentials of 0V and Earth Ground.
For a while I clipped a couple of scope probe ground clips to the chassis
and made do. But today I was indirectly connecting my beloved laptop
to the X-Box, so I took a precaution I strongly recommend to anyone doing
the same.
I cut off the mains plug from the X-Box power lead and substituted my
own non-moulded one, then added a thick wire from the earth pin of the mains
plug, neatly tie-wrapped to the mains cable, and bolted the other bared end
on to the chassis of the X-Box. (If you are not sure which pins are
which in a mains plug, please do not experiment, go get someone else who does
know to do it for you). Take care to bolt the wire in such a way that
it cannot fall into the switchmode powersupply, ie, on the outside of the
chassis, not the inside.
PIC examination
The PIC is a 28-pin SOIC marked PIC16LC63A. I got ahold of
the datasheet from Microchip Technology.
Before we get on to the I2C traffic, I examined what happened if I connected
each non-powerail pin to ground and 3.3V.
pin
|
name
|
when set to
|
action
|
1, 12, 16, 18
|
nMCLR,
|
0V
|
X-box powers down
|
13
|
|
0V
|
Processor fan runs for duration
|
21
|
RB0/INT
|
0V
|
Crashes X-Box, with dynamic video noise overlaid
on last video image (presumably by overflowing the stack with interrupt requests)
|
22
|
|
3.3V
|
blanks video for duration
|
23, 24
|
|
0V
|
Video blanks for one second, and then shows
X-Box logo. Note that if these pins are grounded while the intro movie
is playing, the movie is aborted, and after one second we go straight to
the X-Box logo display
|
14/15 (I2C)
|
SCL, SDA
|
0V
|
See below
|
The PIC takes the I2C bus signal SCL and SDA in on its bottom two pins,
p14 and p15.
I got out my old HP1650A logic analyser and hooked it up. It was
hard work as it is too old (1987!) to reassemble the serial data and had
to be decoded by hand. I ran up the X-Box two times. Note that
the I2C protocol allows an arbitrary number of data bytes to follow
an address.
<bogus values removed 2002-06-13 to avoid
confusion>
I couldn't make much sense of it, I would suggest that my interpretation
of the data is at fault, but there was very good correspondance with the
ACK/NACK bits. These were captured from startup, perhaps there was crap
or multiple startups as the power came up. If I have time later I will
look at them again.
Despite a not very satisfactory attempt to snoop the I2C, Just by monitoring
SDA and SCL with a 'scope while the X-Box sits on its language selection
display I can see that there is no activity on the I2C bus at all while it
is sitting there waiting for someone to press something. So the idea
that there is a watchdog in the PIC that needs stroking over I2C is demonstrably
wrong.
Here is a look at the PIC while sitting on that display: (low means
static 0V level, high means static 3.3V)
1
|
high
|
2
|
high
|
3
|
low
|
4
|
high
|
5
|
high
|
6
|
high
|
7
|
high
|
8
|
low
|
9 (clk in)
|
clock - 10MHz 3.3V
|
10
|
10MHz sawtooth from crystal tank circuit
|
11
|
low
|
12
|
high
|
13
|
high
|
14
|
high
|
15
|
high
|
16
|
high
|
17
|
low
|
18
|
high
|
19
|
0V
|
20
|
3.3V
|
21
|
high
|
22
|
low
|
23
|
high
|
24
|
high
|
25
|
high
|
26
|
low
|
27
|
low
|
28
|
low
|
Its clear from this that if the bios code watchdog is active while sitting
on the language select screen, then the bios code watchdog does NOT live
in the PIC, not a single pin was changing state.
LPC investigations
This is the 16-pin connector that is not fitted to a retail X-Box, but
has the space for it reserved on the motherboard. These are very
friendly pads, standard 0.1" pitch pins which most people would be able
to solder without problems.
LPC is a 33MHz 4-bit parallel bus protocol designed (by Intel) to replace
the old ISA bus, with its huge clunky connector, by a bus with far fewer
pins (as little as 12). It has similar performance to the ISA bus,
so while its useful for many things it won't be replacing PCI or AGP.
It was suggested to me that if you boot the X-Box while holding flash
pin D0 to ground, that the X-Box would attempt to execute code from a ROM
on the LPC header. I found this hard to credit, but to my surprise it
seems to be true; at least, I monitored interesting things happening in that
circumstance.
When you power up an X-Box normally, I observed that it issues an LPC
IO Write of the value 55h to IO address 2Fh. I believe this is something
to do with PnP type initialization, in case there are any such devices on
the LPC bus.
When you hold pin D0 on the flash bus low during power up, you instead
get an LPC read of memory address FF00007x (the x is where I ran out of
space on my scope display). This is quite encouraging. I was
looking this hard in order to determine that the X-Box was not using LPC
DMA to get the memory, which would have been considerably more complex.
How the X-box controls the flash enable signals
The X-Box does not attempt to drive nCE, nOE and nWE; instead it
pulls them to 0V, 0V and 5V respectively via individual 10K resistors.
So it is simple for Milksop to connect to these signals and drive
them to the desired levels.
Note also that as shipped, the X-Box CPU cannot perform write or
erase actions to the flash; there is a small jumper on the reverse
of the motherboard which is shipped open, disabling the write
capability.
X-box behaviour without IDE drives
With the X-Box hard-drive and DVD-Rom drive unplugged, using
the original flash BIOS, the X-Box powers up to display its introductory
animation, and then sits there. After 23 seconds, it times
out and displays a ''Your X-Box needs servicing'' message on the
display device.
The flash device experiences a burst of read accesses shortly after
power-up, and is left in a fixed state during the opening animation
and subsequently until the power is removed., which is at address
offset 0xF805F. This is not useful for our purposes, as we would
find it impossible to defeat all those n-channel transistors driving the
signals low without serious heating of the X-Box driver chip and perhaps
disturbance of its local 0V level.
Forcing the X-Box into a 'warm reset'
|
However, applying 0V to pin 5 of the LPC connector (LRST#,
or system reset signal) has a dramatic effect. If you do this during
the opening animation, it freezes where it got to and sits there. If
you do it in the ''servicing'' display, the screen is filled with a light
grey rectangle and the X-Box continues to sit there. But either
way, the result of this partial reset is that now the Flash Address bus
is set to 0xFFFFF, that is, all of the Flash address lines are set to
3.3V. My X-Box has been in this state for several hours without
any signs of distress, I believe it is not at all dangerous to its health.
Because the P-channel transistors in CMOS (resposible for
driving high) normally have a significantly higher on-resistance
than the N-channel transistors (responsible for driving low), we
are able to override this static state externally by selectively
forcing signals low, and so program the chip in-situ. This
is how Milksop works.
|
Experiment confirming we are able to override signal driven high
by X-Box using XC95108 IO
I confirmed we will be able to successfully override the address
lines with our design by hooking a low-drven output from a existing XC95108
design I have here on to the high-driven flash address pin. It reduced
the level on the pin to 0.8V. On the face of it this is barely adequate,
because the flash device in my x-box (an ST M29F080A) features TTL-level
inputs, which specify Vin <= 0.8V as a low, and >= 2.0V as
a high.
Experiment confirming overriding address line to 0.8V is adequate
However, the following experiment leads me to believe this is not
a problem in practice. I warm reset the system as described above,
and monitored the flash D6 signal and the flash A2 signal on a dual-channel
'scope. As described, A2 is being driven to 3.3V by the X-Box as
are the rest of the address lines. D6 is being driven high by the
flash because the byte at address FFFFFF in the flash has b6 set. I
chose D6 and A2 because I noted that by forcing A2 to 0V, and so selecting
flash address FFFFB, this caused the flash to drive D6 low, because the
byte in the flash at address FFFFB has b6 clear. In this way I can
see if the flash believes I am giving it a high or low level on A2.
I then loaded A2 with three resistors to 0V in turn, monitoring
the effect on A2 and D6.
Resistor from A2
to 0V
|
A2 voltage
|
D6
|
So flash understood
A2 as...
|
none
|
3.31V
|
5V
|
high
|
100R
|
2.43V
|
5V
|
high
|
47R
|
1.83V
|
5V
|
high
|
30R
|
1.49V
|
0V
|
low
|
Its clear then that in fact on the chip I looked at, the transition
between 0 and 1 takes place between 1.49V and 1.83V, leading me to believe
that driving to 0.8V is in fact perfectly adequate, in fact it gives >
0.7V margin on the chip I looked at.
Estimation of X-Box P-channel Rdson
Considering the 100R case above, the p-channel X-Box driver is dropping
0.88V with a load of 100R to 0V, while there is 2.43V across the resistor.
This shows that the X-Box driver P-channel Rdson is ~35R.
Estimation of excess current caused by forcing X-Box address line
low via XC95108
We saw that the XC95108 IO driving low was able to bring the X-Box-driven
address line from 3.31V to 0.8V. Now we know the driver has an Rdson
of 35R, this shows that the XC95108 N-channel Rdson is ~11R.
Also, this same scenario shows that the X-Box driver is dropping
2.5V across 35R, which shows ~70mA of current per overridden pin is being
dissipated in the X-Box driver chip, or 175mW.
So considering the worst case, when we are overriding all 20 address
lines, necessary for accessing address 00000, we will be causing 20 x
70mA = 1.4A to dissipate in the X-Box driver chip, or 3.5W..
(nb similar current flows in the CPLD doing the forcing: 0.8V
through 11R being 72mA)
Note on 2002-06-11: I have changed to
using 74LVXC4245 buffers to drive, which have a 5.5R Vdson, and I have followed
them with a 10R series resistor. So the aggregated Rdson will be approximately
15.5R, instead of 11R, reducing the current somewhat.
Duty cycle averaging
Although the numbers sound frighteningly large, they ignore the fact
that our CPLD is smart enough only to drive the busses for the minimum
time needed to perform the flash bus cycle. For a program operation
this consists of a 150nS period of forcing the X-Box address bus followed
by 8uS typ waiting for the flash to complete the program operation. So
on average, even if we were sat there repeatedly programming the worst
case address 00000, to find the average current we can divide the peak
current by a factor of 8uS/150nS = 53, or a more manageable 26mA
/ 66mW. And in practice on average half of the bits will be high
and so not being driven low.
Its a similar story for the read operation, the CPLD issues a single
flash bus cycle of 150nS and then time is spent transferring the data
back to the PC in two nybbles. This will easily take longer than
the 8uS per byte programming time.
Because the timing and control of the Milksop bus cycles are issued
by dedicated hardware in the CPLD independent of the PC, we need not consider
problems like OS scheduler taskswapping, where our application goes dead
for 50mS at a time, perhaps at an inconvenient moment, yet another reason
not to rely too much on a PC application.
So because of the low duty cycle of the high-current operations, the
average current is reasonably low. The main point to watch is that
the decoupling capacitors on the Milksop are capable to provide these
high momentary currents without causing the main power supply rail to
droop.
(NB In fact until I performed these experiments tonight, the VHDL for
the CPLD would sit in a loop reading from the flash after a program or erase
operation waiting for the flash to complete. I will be changing this
to use the status toggle technique that will allow flash reads from FFFFF
to be used, involving no high-current actions and so being able to exploit
the low duty-cycle).
X-Box specific considerations
Two important notes on X-box compatability:
- The X-box ground 'floats', as there is no connection through
to the mains Earth pin. As we will be connecting it to
the PC, which does have a true Earthed ground, it is important
that this is done while the X-box is powered down and not disconnected
until the X-box is once again powered down.
- The X-box appears to drive the flash nRP pin with a normal
digital level. This pin can be used to temporarily unprotect
the flash blocks, by bringing the pin to 12V. Obviously
that will not be possible while the flash is soldered in the
X-Box. For this reason, assuming MS wanted to leave the
door open to upgrading their flash, I assume that the flash
blocks are not protected, and so Milksop does not have the capacity
to drive nRP to 12V.
TSOP Header hack
As the TSOP header is on a four-week lead time, I decided to hack
an electrical equivalent together on an X-Box (according to Bunnie's pinout
diagram) so the whole project would not be delayed:
I have to say I don't know how these random people who are using
the first generation modchips are doing so well fitting them - I have been
soldering for a quarter of a century - I regularly solder by hand 0.5mm
pin pitch surface mount devices - and I had to take the utmost care and
attention.
|