

Usb controller-32
A USB HID gamepad controller built on the PIC32MX250F128B microcontroller.
- Size
- 194.3 × 109.2 mm
- Copper layers
- 2
- Thickness
- 1.6 mm
- Parts
- 93
- Nets
- 77
- Pads
- 301
- Tracks, vias
- 554, 5,349
- Pours
- 2
- Routed
- Yes
- KiCad
- KiCad 10.0 (file 20260206)
- Created
- 16 Mar 2026
- Updated
- 6 Jun 2026
Overview
Usb controller-32 is an open-source printed circuit board by jcksnvllxr80, from the jcksnvllxr80/usb-controller-32 repository on GitHub. It is a 2-layer board of 194.3 × 109.2 mm with 93 parts on 77 nets, routed with 554 tracks and 5,349 vias.
It is built around the PIC32MX250F128B-I/SS and MAX3232ID. Its parts include 38 resistors, 27 capacitors, 18 switches, 3 ICs and 3 connectors. It belongs with the keyboards and input boards and the PIC boards of this library.
Main components
2PIC32MX250F128B-I/SS
SSOP-28-208mil-40℃~+85℃ 10bit 128KB 19 2.3V~3.6V 32 Bit 32KB 40MHz Built-in FLASH MIPS32 M4K SSOP-28-208mil Microcontrollers (MCU/MPU/SOC) ROHSMicrochip TechnologyMicrocontrollers (MCU/MPU/SOC)MAX3232ID
SOIC-16-40℃~+85℃ 2 2 250Kbps 300uA 3V~5.5V Short-Circuit Protection Transceiver Yes ±15kV SOIC-16 RS232 ICs ROHSTexas InstrumentsRS232 ICs
README
README.mdUSB Controller 32
A USB HID gamepad controller built on the PIC32MX250F128B microcontroller. The firmware reads button inputs from GPIO pins, two potentiometers on the PIC32 ADC, and an MCP23017 I2C I/O expander, then reports them to a host PC as a standard USB HID gamepad. The board-level serial path uses a MAX3232 level shifter, and the MCU clock is provided by a 20 MHz crystal. Built with MPLAB Harmony 3, FreeRTOS, and C++.

Features
- USB HID gamepad with 18 button inputs (2 direct GPIO + 16 via MCP23017)
- 8-byte HID input report with 18 buttons, hat switch, and two live analog axes
- MCP23017 I2C I/O expander with interrupt-driven input detection
- MAX3232-backed debug serial / RS-232 path
POT_1andPOT_2sampled onAN4/AN5forZandRz- Send-on-change HID reports for buttons and potentiometer axes
- Rate-limited serial logging for potentiometer changes with
POT_1/POT_2identification - FreeRTOS-based task scheduling
- UART debug logging and USB/HID diagnostics
- Green and red status LEDs
Hardware Used
Main ICs and timing parts on this design:
PIC32MX250F128B- main microcontroller, USB device controller, ADC, GPIO, I2C, and UARTMCP23017- 16-bit I2C GPIO expander for the additional button inputsMAX3232- UART level shifter for the board's serial / RS-232 debug path20 MHz crystal- external clock source for the PIC32MX250F128B (load capsC17/C18must be 20 pF — see Crystal Load Capacitors)2x linear potentiometers- analog controls forPOT_1andPOT_2, mapped to HIDZandRzMini USB breakout- USB connector breakout for the device port, such as the small Adafruit mini USB breakout the board is using
Hardware Notes
- Crystal load capacitors
C17/C18must be 20 pF. A 0.1 µF value stops the 20 MHz crystal from oscillating on the PCB (the board powers up briefly, then drops off USB). It only appeared to work on the breadboard because the long jumper wires masked the oversized caps. Full explanation: Crystal Load Capacitors.
Architecture

UML Class Diagram

State Machine

Pin Assignment Table
PIC32MX250F128B Direct I/O
| Signal | Pin | Port | Direction | Description |
|---|---|---|---|---|
| MCLR | 1 | — | Input | Master clear (active-low reset); 10k pull-up to VDD; PICkit 5 pin 1 (VPP) |
| PGED1 | 2 | RA0 | Programming | ICSP data (PICkit 5 pin 4) |
| PGEC1 | 3 | RA1 | Programming | ICSP clock (PICkit 5 pin 5) |
| GREEN_LED | 4 | RB0 | Output | Green status LED |
| RED_LED | 5 | RB1 | Output | Red status LED |
| POT_1 | 6 | RB2 / AN4 | Input | Analog potentiometer mapped to HID Z axis |
| POT_2 | 7 | RB3 / AN5 | Input | Analog potentiometer mapped to HID Rz axis |
| VSS | 8 | — | Power | Ground |
| OSC1 | 9 | RA2 | Input | 20 MHz crystal input |
| OSC2 | 10 | RA3 | Output | 20 MHz crystal output |
| U1TX | 11 | RB4 | Output | UART1 transmit (debug) |
| U1RX | 12 | RA4 | Input | UART1 receive (debug) |
| VDD | 13 | — | Power | 5V supply |
| INTERRUPT_A | 14 | RB5 | Input | MCP23017 Port A interrupt (active-low) |
| VBUS | 15 | — | Power | USB 5V bus voltage; connected to VCC |
| INTERRUPT_B | 16 | RB7 | Input | MCP23017 Port B interrupt (active-low) |
| SCL1 | 17 | RB8 | Output | I2C1 clock to MCP23017 |
| SDA1 | 18 | RB9 | Bidirectional | I2C1 data to MCP23017 |
| VSS | 19 | — | Power | Ground |
| VCAP | 20 | — | Power | Internal core regulator output; 0.1µF cap to VSS |
| D+ | 21 | — | Bidirectional | USB data plus |
| D− | 22 | — | Bidirectional | USB data minus |
| VUSB3V3 | 23 | — | Power | USB 3.3V supply; decoupling capacitors to GND |
| RB13 | 24 | RB13 | NC | Not connected |
| BUTTON_1 | 25 | RB14 | Input | Direct button input 1 |
| BUTTON_2 | 26 | RB15 | Input | Direct button input 2 |
| AVSS | 27 | — | Power | Analog ground |
| AVDD | 28 | — | Power | 5V analog supply |
MCP23017 I/O Expander (I2C address 0x20)
| Port | Pins | Direction | Pull-ups | Interrupt | Description |
|---|---|---|---|---|---|
| Port A | GPA0–GPA7 | Input | Enabled | Enabled (interrupt-on-change) | 8 button inputs |
| Port B | GPB0–GPB7 | Input | Enabled | Enabled (interrupt-on-change) | 8 button inputs |
Input/Output Summary
| Type | Count | Source | Details |
|---|---|---|---|
| Button inputs (direct) | 2 | PIC32 GPIO | RB14, RB15 |
| Button inputs (expanded) | 16 | MCP23017 Port A & B | GPA0–7, GPB0–7 |
| Analog inputs | 2 | PIC32 ADC | POT_1 on AN4 drives HID Z, POT_2 on AN5 drives HID Rz |
| LED outputs | 2 | PIC32 GPIO | Green (RB0), Red (RB1) |
| USB HID | 1 | USB peripheral | 18 buttons, hat switch, X/Y centered, live Z/Rz in an 8-byte report |
| Debug UART | 1 | UART1 via MAX3232 | 115200 baud debug/serial path (TX: RB4, RX: RA4) |
| I2C bus | 1 | I2C1 | MCP23017 at 0x20 |
Getting Started
Prerequisites
- MPLAB X IDE or the MPLAB Extension for VS Code
- XC32 Compiler (v4.x or later)
- PIC32MX DFP v1.6.369
- PICkit 5 (or compatible Microchip programmer/debugger)
- Git
Install MPLAB for VS Code
- Open VS Code (or VS Code Insiders).
- Go to the Extensions view (
Ctrl+Shift+X). - Search for "MPLAB" and install the Microchip MPLAB extension pack.
- The extension will prompt you to install the XC32 compiler and required device packs if they are not found. Follow the prompts.
- Restart VS Code after installation.

Clone and Build
git clone https://github.com/jcksnvllxr80/usb-controller-32.git
cd usb-controller-32- Open the folder in VS Code.
- The MPLAB extension should detect the project automatically via the CMake configuration in the
cmake/directory. - Select the usb-controller-32 project and the default configuration from the MPLAB project view.
- Click Build (or press
Ctrl+Shift+B).
Program the Device
- Connect the PICkit 5 to the ICSP header on your board (ensure correct pin 1 orientation).
- In the MPLAB extension, select PICkit 5 as the hardware tool.
- Set the programming speed to Low if you encounter connection issues.
- Click Program to flash the
.hexfile to the PIC32MX250F128B.
Warning: Use a native USB 2.0 port when connecting this controller to the PC. On some machines, USB 3.x ports/controllers can fail enumeration or produce a Windows Code 10 error with this hardware. If your machine does not have a USB 2.0 port, connect the controller through a USB 2.0 hub.
Verify Operation
- After programming, the device should enumerate as a USB HID gamepad on the host PC.
- Open Set up USB game controllers (Windows) or a gamepad tester to confirm button presses and
Z/Rzpotentiometer movement are registered. - Connect a serial terminal (115200 baud, 8N1) to UART1 to view debug logs, potentiometer change logs, and issue commands.
UART Diagnostics
Helper scripts:
powershell -ExecutionPolicy Bypass -File .\tools\uart_query.ps1powershell -ExecutionPolicy Bypass -File .\tools\uart_cmd.ps1 -cmd "status"
Useful commands:
status- GPIO, USB, and LED summaryusb- USB device state and register dumpenum- enumeration counters and last setup requesthid- HID readiness, send counters, and current report bytesusblog- recent USB transaction logusbdbg- toggle live USB debug loggingusbreset- soft detach/reattach to force re-enumeration
Automatic serial logs:
- Potentiometer changes are logged automatically as
[POT] POT_1 axis=...and/or[POT] POT_2 axis=... - Logs are only emitted when the scaled axis value changes
- Pot logs are rate-limited to 5 lines per second total
Firmware Notes
- GPIO and MCP23017 interrupts only latch state. HID reports are built and sent from
APP_Tasks(). POT_1andPOT_2are polled inAPP_Tasks(), scaled from 10-bit ADC samples to 8-bit HID axis values, and mapped to HIDZandRz.- Potentiometer state is cached, so a new HID report is only queued when a button changes or when the last-sent
Z/Rzbyte changes. - Potentiometer serial logs identify which input changed (
POT_1,POT_2, or both), skip repeated values, and are rate-limited to 5 lines per second. - HID reports are only queued when button or axis state changes, which keeps traffic and debug noise down.
Project Structure
usb-controller-32/
├── cmake/ # CMake build configurations
├── docs/ # Datasheets, block diagram, images
├── tools/ # Flash and UART helper scripts
├── usb-controller-32/
│ ├── mcc/ # MPLAB Code Configurator files
│ └── src/
│ ├── main.cpp # Entry point (SYS_Initialize + SYS_Tasks)
│ ├── app.cpp / app.h # App task, GPIO/MCP state, USB HID send path
│ ├── command_handler.cpp / .h # UART command parser and diagnostics
│ ├── gamepad.cpp / .h # USB HID gamepad driver
│ ├── mcp23017.cpp / .h # MCP23017 I2C I/O expander driver
│ ├── logger.cpp / .h # UART debug logger (singleton)
│ ├── usb_debug.c / .h # USB debug logging helpers
│ ├── config/ # Harmony-generated peripheral config
│ └── third_party/rtos/ # FreeRTOS source
└── README.mdSponsor
PCB prototyping for this project is sponsored by PCBWay.
PCBWay makes it easy to go from design files to manufactured boards. Upload your Gerber files, pick your board specs (layers, thickness, surface finish, color, etc.), and get an instant quote. Orders typically ship within a few days. Their online ordering process is straightforward — just create an account, upload your files, review the specs, and check out.
License
See Microchip's license terms in the source file headers.
Parts
93| Qty | Value | Footprint | References |
|---|---|---|---|
| 32 | 12k | Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_Horizontal | R1, R2, R10, R11, R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R22, R23 +16 |
| 25 | 0.1µF | Capacitor_THT:C_Disc_D5.0mm_W2.5mm_P2.50mm | C1, C2, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C24, C25 +9 |
| 18 | SW_Push_Dual | Button_Switch_THT:SW_TH_Tactile_Omron_B3F-100x | SW1, SW2, SW3, SW4, SW5, SW6, SW7, SW10, SW11, SW12, SW13, SW14, SW15, SW16, SW17, SW18 +2 |
| 2 | 0.01µF | Capacitor_THT:C_Disc_D5.0mm_W2.5mm_P2.50mm | C22, C23 |
| 2 | 4.7k | Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_Horizontal | R36, R37 |
| 2 | R_Potentiometer | Potentiometer_THT:Potentiometer_Bourns_3386P_Vertical | RV1, RV2 |
| 1 | 1.2k | Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_Horizontal | R34 |
| 1 | 10k | Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_Horizontal | R35 |
| 1 | 15k | Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_Horizontal | R38 |
| 1 | 20MHz | Crystal:Crystal_HC49-4H_Vertical | Y1 |
| 1 | 8.2k | Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_Horizontal | R33 |
| 1 | Conn_01x03_Pin | Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical | J3 |
| 1 | Conn_01x08_Pin | Connector_PinHeader_2.54mm:PinHeader_1x08_P2.54mm_Vertical | J2 |
| 1 | LED_Dual_AKA | LED_THT:LED_D3.0mm-3 | D2 |
| 1 | MAX3232 | Package_DIP:DIP-16_W7.62mm | U2 |
| 1 | MCP23017x-x-SP | Package_DIP:DIP-28_W7.62mm | U3 |
| 1 | PIC32MX250F128B | Package_DIP:DIP-28_W7.62mm | U1 |
| 1 | USB_MiniB_Adafruit_Breakout | extra:USB_MiniB_Adafruit_Breakout | J1 |
Similar boards
- 2 layers111.8 × 161.8 mm

- 2 layers64.1 × 33.4 mm

32mx2xx
PinguinoIDE/pinguino-cad
Open Hardware Pinguino boards (and extensions) CAD files (Kicad)
41 parts11GPL-2.0 - 2 layers191.5 × 97.6 mm

Open Apple 1 SBC
davischris/OpenAC1
This work is largely based on the work of Tor-Eirik Bakke Lunde (https://github.com/tebl/RC6502-Apple-1-Replica).
72 parts4GPL-3.0 - 2 layers92 × 76 mm

ILV2-7-5 Clock
biomurph/ILV2-7-5_VFD_Display
KiCAD circuit for a VFD Clock using the Popular ILV2-7/5 flat tube segmented nixie
50 parts3GPL-3.0 - 4 layers61.4 × 61.3 mm

Cyton wired
BostonUniversitySeniorDesign/brain-4ce
Where thoughts become motion. Designed by BU ECE 2023 Senior Design Capstone Team 4 From left to right: Brendan Shortall, Mitchell Gilmore, Dayanna De La Torres, Jonathan Mikalov, Alexander Johnson
100 parts3 - 2 layers45 × 39 mm

- 2 layers125 × 113 mm

- 2 layers189.5 × 204.9 mm

SmartSpin2k Panelized
doudar/SmartSpin2k
Transform your spin bike into a Smart Trainer!
749 parts292GPL-2.0
Questions
How big is the Usb controller-32 PCB?
It measures 194.3 × 109.2 mm and has 2 copper layers, 1.6 mm thick.
What parts does the Usb controller-32 use?
93 parts, built around the PIC32MX250F128B-I/SS and MAX3232ID. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.
Where can I download the Usb controller-32 KiCad files?
From the jcksnvllxr80/usb-controller-32 repository on GitHub, at the commit this page was made from: the board is pcb/usb-controller-32/usb-controller-32.kicad_pcb and its schematic pcb/usb-controller-32/usb-controller-32.kicad_sch. PCBKit opens the board in the browser, with nothing to install.
Can I use the Usb controller-32 design in my own project?
Its repository states no licence, so its author keeps all rights: ask jcksnvllxr80 before reusing the design.