The U-force! ------------ 090107 K.Horton -- Aah the U-Force. I called it the U-Farce. This piece of hardware was a fairly unique infra-red (IR) controller that opens up like a book. On it are no less than 9 IR emitter detector pairs! Inside it, however, the thing is a freaking mess. It is composed of 4 PCB's, one large board that takes up the entire bottom half of the case, and three smaller boards in the top portion, all connected via a ton of ribbon cables. There's bunches of hot melt glue holding the wiring in place. To "calibrate" the sensors, they had groups of no less than 8 resistors in parallel. To perform the "calibration", they would cut out some of the resistors! As you can imagine, this is a mess. Some of the resistors had been re-soldered and re-cut in cases to make it operate properly. I fully traced the circuitry of this thing out and I cannot believe it functions. The design is pretty terrible and needed alot of hand tweaking to make it function, as evidenced by capacitors (up to three) paralleled in places. The caps range in value from 50 to 100 pf or so. These things must have been a nightmare to make in any kind of production volumes due to all this hand tweaking required. There's a COP320 microcontroller made by National Semi that runs at 20MHz. Also included is a 74HC373 octal latch, feeding the 4021 like you'd find on any normal NES controller. There is also an LM324 quad op-amp to amplify the analog feedback from the sensors, which is then fed into an 8 pin ADC0831 made by National Semiconductor also. Without further ado, let's get on with the show! On the front are 6 slide switches and 2 pushbuttons. (top) /------sensor 1-------\ | | |sens. 2 sens. 3| | | | | | | | | |sens. 4 sens. 5| | | | | *********************** *********************** | | |sens. 6 dummy | | | | | | | | | |sens. 7 sens. 8| | | | switches | | | \------sensor 9-------/ (bottom) Here's my poor rendering of the sensor locations. The 9 sensors are listed. The position marked "dummy" does not have a sensor present. Switches: Included on the unit are 6 slide switches marked "Turbo A" "Turbo B" and "Game switches 1 through 4". Also included are two push buttons marked "Start" and "Select". Game switches 1 through 3 being in the down position puts the device into analog mode. Any other combination results in a digital mode. The digital modes are the only modes that got used on games, as far as I know, except for the "U-Force Power Games" prototype cart. Game switch 4 selects between two of the sensors. Sensor 5 (up) and 9 (down). Sensors 5 and 9 are mutually exclusive- only one can be used at a time, and it varies depending on which position it is in. --- In the following explaination, the first 4 digit number is the switch positions. 1 = up, 0 = down for switches 1 through 4, respectively. Below that are the 9 sensors, and what function on the standard controller they perform. If there's more than 1 entry for a sensor, that means distance plays a role in how it functions. i.e. if there are three values marked 9.0 through 9.2: 9.0 = farthest away 9.1 = closer 9.2 = closest 0010 ---- 1 - start 2.0 - up + down + left 2.1 - up + down 2.2 - up + down + right 3.0 - up + down + left 3.1 - up + down 3.2 - up + down + right 4 - 5 - 6 - 7 - B (only works if sensor 8 is covered) 8 - A 9 - st- start sl - select Note: Sensors 2 and 3 have an effect on each other. Below are all the interactions that can occur. 2.0 + 3.0 - left 2.0 + 3.1 - nothing 2.0 + 3.2 - nothing 2.1 + 3.0 - left 2.1 + 3.1 - nothing 2.1 + 3.2 - right 2.2 + 3.0 - nothing 2.2 + 3.1 - nothing 2.2 + 3.2 - right 0100 ---- 1 - up + down 2 - left 3 - 4 - right (note: left/right are mutually exclusive) 5 - 6 - B 7 - A 8 - 9 - up + down st- start sl- select 0110 ---- 1 - start 2 - B + up + down 3 - A + up + down 4 - B 5 - 6 - 7 - left (note: left/right are mutually exclusive) 8 - right 9 - A st- start sl- select + up + down 1000 ---- 1 - 2 - start 3 - start 4.0 - B + up + down 4.1 - B 5 - 6 - 7 - left 8 - right 9.0 - A + up + down 9.1 - A 9.2 - A + up + down st- start sl- select + up + down Note: left/right are mutually exclusive. 1010 ---- 1 - up + down 2.0 - right 2.1 - up + down + right 3.0 - left 3.1 - up + down + left 4 - 5 - 6 - 7 - B (only works if sensor 8 is covered) 8 - A 9 - st- start sl- select 1100 & 1110 ----------- 1 - start 2 - up + down + left 3 - up + down + right 4 - 5 - 6 - 7 - B (only works if sensor 8 is covered) 8 - A 9 - st- start sl- select Note: if both sensors 2 and 3 are covered, output is up + down only ---------- The two turbo switches control turbo for A and B like you'd suspect. They appear to toggle at around a 10Hz rate when enabled. ----------- U-force analog mode ------------------- clicking the first 3 game select switches down puts it into analog mode. In this special mode, the controller will spit out the analog results of reading the sensors. It only seems to update around 10Hz or so, and you must poll it and wait until it's ready to give you results. The controller returns to you 9 bytes of data in this form: 00: synch/start/select buttons (bit0 = start, bit1 = select) 01: sensor 7 02: sensor 8 03: sensor 5 / 9 (depends on switch 4 position as noted above) 04: sensor 6 05: sensor 4 06: sensor 2 07: sensor 3 08: sensor 1 To read the device, you first must read bytes from the controller port until a value between 00h and 03h is received. If the value is greater than this, discard it and continue to poll. Once a value of 00h to 03h is received, save it. The lower two bits contain the start (bit 0) and select (bit 1) button states. Now, read 8 more bytes from the controller port. These 8 bytes will reflect the analog readings of the 8 sensors. The analog output values are 5 bits long, with a "presence" bit. The presence bit goes low when the sensor is being covered by the user. It goes high when the sensor is uncovered. 7 bit 0 AAAA xxP0 --------- A: upper 4 analog data bits x: lower analog data bit (both are the same value at all times) P: presence bit. 1 = sensor fully uncovered, 0 = sensor covered 0: always 0. The 5 bit analog output is in 2's complement form- 11111b is the lowest reading, while 00001b is the highest. A reading of 00000b is not possible because it would be seen as a synchronization byte. Moving your hand closer to the sensor results in a LOWER reading. The game ROM inverts the bits before storing them, which is a good idea. It properly inverts the readings so they read "true". If you invert the bits, they become: 7 bit 0 AAAA AxP0 --------- A: analog value (varies between 00h and 1eh. closer = higher number). P: presence bit. 1 = sensor covered, 0 = sensor uncovered. ----- Here is my U-force reading routine. It is shorter and more efficient than theirs. Because of this, I had to add delays into the code so that the device would function properly. This code returns the start/select state in ufdat+00h, and then the 8 sensors in ufdat+01h through ufdat+08h. Note that they are read last to first, sensor 1 appears at ufdat+01h. readuf2: jsr readit sta ufdat+00h ;store the start/select button here clc adc #0fch bcs readuf2 ;wait for FCh-FFh ldy #07h ;8 bytes of data rloop2: jsr readit eor #0ffh sta ufdat+01h,y dey bpl rloop2 rts readit: ldx #009h stx 04016h nop ;required dex stx 04016h rloop1: lda 04016h lsr a rol ufdat+09h php ;these two instructions waste alot of cycles plp ;they are required also dex bne rloop1 lda ufdat+09h rts ---------- And this is the routine that the U-force power games(tm) prototype cart uses. It stores the results into a buffer in memory. ufdat+00h holds the state of the start/select buttons (1 = pushed) ufdat+01h through 08h hold the analog values of the sensor readings. readuf: jsr read1 ;synch up with u-force & read start/select jsr read2 ;read analog values from u-force rts read1: ldy #08h - lda ufdat+00h,y ;copy previous bytes to secondary memory sta ufdat+0bh,y dey bpl - - jsr read3 cmp #0fch ;read until byte > FBh bcc - eor #0ffh ;invert sta ufdat+00h eor ufdat+0bh and ufdat+00h sta ufdat+0bh ;store changed buttons only rts read2: ldy #07h ;read 8 bytes worth of data - jsr read3 sta ufdat+01h,y dey bpl - rts ;reads 1 byte from controller port & inverts result(very poorly) read3: lda #001h sta 04016h lda #000h sta 04016h jsr read4 lda ufdat+09h rts read4: lda #000h sta ufdat+09h ldx #008h clc - lda 04016h eor #0ffh and #001h ora ufdat+09h sta ufdat+09h asl ufdat+09h dex bne - ror ufdat+09h rts