GC+ for STM32

jefflongo

Broke BitBuilt
Staff member
.
.
Joined
Dec 15, 2016
Messages
956
Likes
1,291
Location
Santa Barbara, CA
Portables
1
For awhile now I've been interesting in implementing something like GC+ to the STM32 platform. I was bored over the school break so I decided to get cracking on this using a NUCLEO-G431KB development board I was using for my Wii Pocket firmware (I will get back to that soon, I promise..). I implemented the serial interface using a timer + DMA, dynamically switching from PWM output with variable duty cycle for the bit encoding to transmit, and input capture for measuring low signal time to receive. I learned more about the fine details of timers and DMA than I bargained for. I implemented the basics of the controller-console protocol today, and the controller is successfully detected!

I will likely design a development board next to implement the actual controls. Feel free to check out the code here: https://github.com/jefflongo/gcplus-stm32

20210104_224015.jpg
 

jefflongo

Broke BitBuilt
Staff member
.
.
Joined
Dec 15, 2016
Messages
956
Likes
1,291
Location
Santa Barbara, CA
Portables
1
Seem to have sorted out the stability issues, my breadboard setup connection to the controller cable was janky.

Analog functionality is working well. I also hooked up a logic analyzer to a stock controller to learn about the behavior. Some notes and a couple interesting points to notice when comparing to other online documentation:

- startup behavior of the controller is poll with the 0x00 byte, a get origins command, and then polling in mode 3 (the default mode)
- some well-known documentation online lists the ID command as responding with 0x09, 0x00, and 0x03 in that order. The first two bytes (0x09 and 0x00) give information about the controller type (wired, wireless, rumble capable, etc) while the last byte are some unknown flags. I noticed on my controller the last byte is 0x20 and not 0x03. Probably doesn't matter though.
- the get origins command gives the controller status in the same format as polling mode 3, followed by two bytes: both of which are 0x02. Probably analog a/b values that aren't used, or some deadzone information.
- the get origin bit (in byte 0 of the status/get origin packet) is cleared before the origin packet is written on the bus
- the x+y+start button combo behavior is as follows: 3 seconds of holding down x+y+start causes the controller to no longer respond to polls on the bus. After the console detects the inactivity, it starts polling for a controller with the 0x00 byte again. On releasing the x+y+start button combo, the behavior is exactly the same as plugging in a controller (id, get origins, then polling). Originally I thought this would trigger a calibrate (0x42) command, but this is not the case

I only tested in Melee and Nintendont, but I have yet to see a calibrate command, a long status (0x43) command, or any other polling mode used besides mode 3. I'm sure there are other games that take advantage of these extra commands.
 
Last edited:

Aurelio

ᕕ( ᐛ )ᕗ
Staff member
.
.
.
.
.
.
Joined
Mar 3, 2016
Messages
2,073
Likes
2,732
Portables
2
Not all games use mode 3. Luigi's mansion uses mode 1 iirc. Note that Nintendont will always use mode 3 because it has an additional layer between games and SI, unless you enable native SI.
I haven't seen any reference to command 0x43 in games codes, where did you get that from?
The reset combo literally resets the controller, it's not handled by the software in any way. In GC+ I simply handle this by not clearing the WDT if the combo is held.
 

jefflongo

Broke BitBuilt
Staff member
.
.
Joined
Dec 15, 2016
Messages
956
Likes
1,291
Location
Santa Barbara, CA
Portables
1
Not all games use mode 3. Luigi's mansion uses mode 1 iirc. Note that Nintendont will always use mode 3 because it has an additional layer between games and SI, unless you enable native SI.
I haven't seen any reference to command 0x43 in games codes, where did you get that from?
The reset combo literally resets the controller, it's not handled by the software in any way. In GC+ I simply handle this by not clearing the WDT if the combo is held.
Yeah, I figured the polling mode was game dependent. I noticed the 0x43 command in this project, which seems to be the most accurate controller emulator I've found thus far: https://github.com/extremscorner/gba-as-controller/blob/gc/controller/source/main.iwram.c
His implementation of the command sends regular status + the two extra analog a/b bytes.
 

Aurelio

ᕕ( ᐛ )ᕗ
Staff member
.
.
.
.
.
.
Joined
Mar 3, 2016
Messages
2,073
Likes
2,732
Portables
2

jefflongo

Broke BitBuilt
Staff member
.
.
Joined
Dec 15, 2016
Messages
956
Likes
1,291
Location
Santa Barbara, CA
Portables
1
It seems to me like he handled it the same way as the recalibrate command?
Yes. Presumably the recalibrate command would have the same format as the get origin command. The "long status" command would happen to be this format as well: all analog values get a full byte. If his implementation is correct, the output would effectively be the same, but interpretation the console makes of it would be different (update the calibration info vs just reading the controller status).
 

Aurelio

ᕕ( ᐛ )ᕗ
Staff member
.
.
.
.
.
.
Joined
Mar 3, 2016
Messages
2,073
Likes
2,732
Portables
2
Yes. Presumably the recalibrate command would have the same format as the get origin command. The "long status" command would happen to be this format as well: all analog values get a full byte. If his implementation is correct, the output would effectively be the same, but interpretation the console makes of it would be different (update the calibration info vs just reading the controller status).
Yeah though I just don't see any reference to it in games. Maybe just ask Extrems?
 

jefflongo

Broke BitBuilt
Staff member
.
.
Joined
Dec 15, 2016
Messages
956
Likes
1,291
Location
Santa Barbara, CA
Portables
1
Yeah though I just don't see any reference to it in games. Maybe just ask Extrems?
Update: got a response from Extrem:

"
It's only used by the GameCube Service Disc.



[5:58 AM]
It makes sense you don't see it, because hardware polling is fixed to 3/8 bytes.



[5:59 AM]
This was discovered through fuzzing the controller, by the way.
"
 

Aurelio

ᕕ( ᐛ )ᕗ
Staff member
.
.
.
.
.
.
Joined
Mar 3, 2016
Messages
2,073
Likes
2,732
Portables
2
Update: got a response from Extrem:

"
It's only used by the GameCube Service Disc.



[5:58 AM]
It makes sense you don't see it, because hardware polling is fixed to 3/8 bytes.



[5:59 AM]
This was discovered through fuzzing the controller, by the way.
"
Ah neat
 

jefflongo

Broke BitBuilt
Staff member
.
.
Joined
Dec 15, 2016
Messages
956
Likes
1,291
Location
Santa Barbara, CA
Portables
1
Designed a new version of my adapter board to sit on the GameCube controller ASIC's footprint using the STM32 controller instead of the PIC controller for GC+. The routing was much more difficult this time because I optimized the pin allocation for code performance instead of PCB layout. I also decided to use a flex PCB from OshPark ($2 for 3 boards shipped? Sounds good!) because the rigid PCB method didn't work as well as I would have liked last time.

4.png 1.png 2.png 3.png
 

jefflongo

Broke BitBuilt
Staff member
.
.
Joined
Dec 15, 2016
Messages
956
Likes
1,291
Location
Santa Barbara, CA
Portables
1
PCBs are in, so far I've got a fully working GameCube controller. The ADC isn't working perfectly, so I'll need to do some digging there. But I'm quite happy with the current progress.

EDIT: I think I've resolved the ADC issue. I noticed the ADC readings were lower than expected. ADCs can be modelled by a sampling capacitor. If the signal is being sampled fast, the reading can be low if the capacitor is still charging. I increased the ADC cycle time per conversion and I'm getting better results now.

20210204_152451.jpg
20210204_154451.jpg
 
Last edited:

Stitches

2 and a Half Dollarydoos
Staff member
.
.
Joined
Feb 5, 2017
Messages
1,772
Likes
1,535
Location
Banana Bender Land, Australia
Portables
6
This feels like brain surgery
 
Top