ECE 4760: Digital Systems Design Using Microcontrollers

PicoChess

Authors: Rachel Lee, Zephan Sanghani, Kailey Ye
Date: Fall 2025

Demonstration Video

Introduction

An interactive physical chess game featuring piece detection, VGA display, and a computer opponent.

Chessboard display showing the game interface on VGA monitor
The PicoChess game board displayed on a VGA monitor.

This project creates a physical, interactive chess game that combines the tactile experience of a real chessboard with the functionality of modern chess applications. The system uses a Raspberry Pi Pico (RP2040) microcontroller to interface with a physical chessboard equipped with reed switches and magnetic pieces, enabling automatic piece detection. Players interact with real chess pieces on a physical board, while the system provides visual feedback on a VGA display, legal move hints when pieces are picked up, and an optional computer opponent.

The system supports both two-player and single-player modes, with additional features including optional game timing and move hints. The implementation includes all standard chess rules: check, checkmate, en passant, pawn promotion, and comprehensive move validation. The board automatically detects piece movements and validates each move in real-time.

High-Level Design

Rationale and Sources

The motivation behind this project was to create a physical chess game that combines the tactile experience of a real chessboard with the functionality of modern chess applications. Unlike purely digital chess games, this system allows players to interact with physical pieces while receiving visual feedback, legal move hints, and optional computer assistance. The project draws inspiration from online chess platforms but maintains the traditional feel of moving pieces by hand.

The system integrates several key technologies: reed switch-based piece detection for automatic board state tracking, VGA display for visual feedback, a computer opponent using minimax search, and a keypad interface for game configuration. This combination creates a unique hybrid experience that bridges physical and digital gameplay.

System block diagram showing RP2040 Pico with software modules and hardware components
System block diagram showing software modules inside RP2040 Pico (left) and hardware components (right), with connections showing hardware-software interfaces.

As shown in the block diagram above, the system consists of five software modules running inside the RP2040 Pico, which interact with three external hardware components. The Chess Engine serves as the central orchestrator, maintaining the canonical representation of the chess board, current turn, check status, and all game rules. The Board Scanner continuously monitors the physical chessboard, detecting when pieces are lifted or placed by reading the 64 reed switches. The Computer module implements the opponent logic using minimax search to calculate moves. The User Interface processes keypad input, handling menu navigation and game configuration. The VGA Display generates video signals to render the game state, legal moves, and menus on the VGA monitor.

The modules interact through a coordinated flow. When a player lifts a piece on the physical chessboard, the Board Scanner detects the change and queries the Chess Engine to identify which piece was lifted and request all legal moves for that piece. The Chess Engine responds with valid destinations and passes them to the VGA Display to render as visual hints. When the player places the piece, the Board Scanner calls the Chess Engine to validate the move. If valid, the move is committed to Game State. If invalid, an error is displayed.

In single-player mode, when it's the computer's turn, the Chess Engine requests a move from the Computer module. The Computer reads the current Game State, uses the Chess Engine's move generation functions to explore possibilities, evaluates positions, and returns its chosen move. The Chess Engine then updates Game State with the computer's move and signals the Board Scanner to enter verification mode. The Board Scanner monitors the physical board until the player executes the computer's move, creating a handoff where digital calculation is followed by physical execution. The VGA Display receives all rendering information from the Chess Engine, which provides the current board state, legal moves to highlight, and move history, ensuring the display always reflects the authoritative game state.

Hardware Design

The hardware design centers around the physical chessboard with 64 reed switches arranged in an 8×8 grid, each corresponding to a square on the chessboard. Magnets attached to the bottom of each chess piece activate the reed switches when placed on the board, enabling automatic piece detection. The system also includes VGA output for visual feedback, a keypad for menu navigation, and the RP2040 microcontroller coordinating all components.

Chessboard

The chessboard uses 64 Littlefuse MDSR-7-10-20 reed switches, one for each square. The switches are arranged in a matrix configuration with 8 rows and 8 columns. Each row is connected to a GPIO output pin (GPIO 0-7), and each column is connected to a GPIO input pin (GPIO 8-15) with internal pull-down resistors enabled. 330Ω current-limiting resistors are placed in series with each row to protect the GPIO outputs from overcurrent.

Diodes (1N4148) are placed in series with each reed switch to prevent current from flowing between columns when multiple switches are closed simultaneously. This is essential because when multiple pieces are on the board, multiple switches may be closed, and without diodes, current could flow between columns, causing false readings.

Circuit diagram showing 8×8 reed switch matrix with diodes and resistors Physical chessboard with reed switches mounted on each square
Left: Chessboard reed switch matrix schematic showing row/column connections and diode protection.
Right: Physical implementation with reed switches mounted on the chessboard during the construction process.

Chess Pieces

We attached multiple small neodymium disc magnets to the bottom of each chess piece. We experimentally discovered that the reed switches only close when a magnet is positioned directly over them, so a single small magnet didn't reliably activate the switch regardless of piece placement. To solve this, we placed 4-5 magnets spread across the base of each piece, ensuring at least one magnet is always over the reed switch. An alternative approach would be using larger, thinner magnets that cover more area with a single magnet per piece.

Chess pieces with neodymium magnets attached to their bases
Chess pieces with multiple neodymium magnets attached to the base for reliable reed switch activation.

VGA Interface

The VGA display connects to the RP2040 via GPIOs 16-21 and ground. HSync and VSync (GPIOs 16-17) connect directly to the VGA connector. The interface uses 4-bit color: 2 bits for green, 1 bit for blue, and 1 bit for red. Green gets more bits since human eyes are more sensitive to green.

For red and blue, 330Ω resistors create a voltage divider with the display's internal 70Ω resistor, stepping down the RP2040's 3.3V output to the 0.0-0.7V range expected by VGA. For green, the high bit uses a 330Ω resistor while the low bit uses 470Ω, enabling a more expressive range from the 2-bit green values.

VGA connector pinout showing HSync, VSync, and RGB connections with resistor values
VGA connector pinout (from Professor Adams).

Keypad Interface

The keypad works similarly to the chessboard: pressing a key closes a switch that shorts a row pin to a column pin. We use three keys (2, 5, 8) from a standard 3×4 matrix keypad. Row pins are configured as outputs and the column pin as an input with internal pulldown. Scanning sets each row high and reads the column to detect presses. A rising edge detector ensures that holding a key registers as only a single press.

Software Design

The software architecture uses protothreads for concurrent task management, with two main threads handling board scanning and keypad input. The system is organized into five modules corresponding to the system block diagram: the Chess Engine, Board Scanner, Computer, User Interface, and VGA Display. Each module is implemented in separate source files with clear interfaces. The chess algorithms are based on techniques described in Cornell's AI Chess Algorithms.

Chess Engine ( chess.c/ h )

The Chess Engine maintains the canonical 8×8 board representation, tracks turns, manages check status, and enforces all chess rules. The board is stored as a 2D array of Tile structures containing piece type and color.

Move Generation

The move generator populates an 8×8 bitmap of legal destinations for a selected piece. Sliding pieces (rooks, bishops, queens) iterate outward in each direction until hitting the board edge or another piece, stopping after captures. Knights use a lookup table of eight L-shaped offsets. Kings check all eight adjacent squares. Pawns move forward (one or two squares from start), capture diagonally, and can perform en passant when the opponent's pawn just advanced two squares. En passant is tracked via state variables that record the "passed through" square, cleared after each move.

Check and Checkmate Detection

Check detection locates the king, then generates moves for all enemy pieces to see if any attack the king's square. When in check, the move generator filters candidates by temporarily applying each move, testing for check, and restoring the board. Checkmate occurs when the king is in check and no legal moves exist.

State Management

The engine provides save/restore functions using memcpy() to copy the entire game state, enabling the computer to explore hypothetical moves without corrupting actual state. A render-enable flag suppresses VGA updates during search.

Board Scanner ( chessboard.c/ h )

The Board Scanner translates reed switch states into game actions by comparing "expected" occupancy (from the Chess Engine) against actual occupancy (from hardware). GPIO pins 0-7 drive rows, and pins 8-15 read columns with pull-downs. Each scan cycle activates one row, waits 10μs for signals to stabilize, and reads all columns, completing in under 100μs. The 10μs delay is necessary. We initially used 1μs but encountered faulty readings due to insufficient settling time.

State Machine

A seven-state machine interprets player actions. The state machine also provides implicit debouncing: if a piece momentarily bounces during placement, the system transitions from IDLE to a lifted state and back to IDLE without registering an invalid state.

State machine diagram showing transitions between board states
Chessboard state machine diagram showing all states and transitions for move detection and validation.

The distinction between OWN_LIFTED and ENEMY_LIFTED supports two capture styles: some players lift their own piece first, others remove the captured piece first. When a player lifts an enemy piece, the system checks if any friendly piece can capture that square. If so, it waits for the capturing piece to be lifted. Once both pieces are off the board (BOTH_LIFTED), placing the player's piece on the capture square completes the move.

The INVALID state handles error recovery by displaying red borders on squares missing pieces and yellow borders on squares with unexpected pieces. The system waits until the board matches the expected state before returning to IDLE. The VERIFY state is used after the computer selects its move: cyan borders indicate the source and destination squares, and the system waits for the player to physically execute the move before continuing.

Computer ( computer.c/ h )

The Computer module implements an AI opponent using minimax search with alpha-beta pruning, constrained by a 2-second time limit.

Position Evaluation

The evaluation function combines material (pawns=1, knights/bishops=3, rooks=5, queens=9, kings=100), positional bonuses from piece-square tables (rewarding central knights, advanced pawns, safe kings), and mobility (counting safe squares each piece can reach, weighted by piece value). The final score weights material heavily (×100), adds position directly, and includes mobility (×10). These weights were not optimized and were chosen mostly arbitrarily to ensure the computer makes somewhat reasonable moves. There is significant room for improvement in tuning these parameters.

Minimax with Alpha-Beta Pruning

Minimax models chess as a two-player zero-sum game. The algorithm recursively explores the game tree, alternating between maximizing (computer's turn) and minimizing (opponent's turn) at each level. At leaf nodes, the static evaluation function scores the position. These scores propagate up the tree: maximizing nodes take the highest child score, minimizing nodes take the lowest. The depth of search determines how many moves ahead the computer considers.

Alpha-beta pruning dramatically reduces the search space by eliminating branches that cannot affect the final decision. The algorithm maintains two bounds: alpha (the best score the maximizer can guarantee) and beta (the best score the minimizer can guarantee). When evaluating a maximizing node, if any child's score exceeds beta, the remaining children are skipped because the minimizer would never allow this path. Similarly, at minimizing nodes, scores below alpha trigger cutoffs. With good move ordering, alpha-beta can reduce the effective branching factor from ~35 to ~25.

Move ordering improves pruning efficiency by examining likely-good moves first. Captures are searched before non-captures, sorted by MVV-LVA (Most Valuable Victim, Least Valuable Attacker), so capturing a queen with a pawn is examined before capturing a pawn with a queen. Non-captures are sorted by the moving piece's value.

Iterative Deepening

The algorithm searches to depth 1, then 2, then 3, etc., until the time limit expires. This guarantees a move is always available (using the best from the last completed depth) and provides natural time management.

Quiescence Search

At leaf nodes, instead of returning static evaluation immediately, the algorithm extends along capture sequences until a "quiet" position is reached. This prevents the horizon effect where a position appears favorable just before a devastating capture. However, due to the RP2040's limited processing power (typically evaluating only ~2,000 positions per move), we believe the search rarely reaches sufficient depth for quiescence to provide significant benefit.

User Interface ( user_interface.c/ h )

The User Interface handles keypad input, the pre-game menu, chess clocks, move history, and promotion selection.

Keypad and Menu

Three buttons (Up, Select, Down) use row-column scanning identical to the chessboard. Edge detection ensures held buttons register as single presses. The menu offers game mode (1-player, 2-player, debug), player color, and time control options. The Start button activates only when all pieces are correctly positioned.

Chess Clocks

Each player's time is stored in microseconds using time_us_64(). The display updates only when seconds change, reducing redraw overhead. Timeout triggers immediate game-over.

Move History and Promotion

Moves are recorded in algebraic notation and displayed in a scrolling two-column list. When a pawn promotes, a menu appears for piece selection. The game pauses until confirmed.

VGA Display ( vga16_graphics_v2.c/ h )

We use the VGA library provided by Professor Adams and Land. The library stores a 640×480 4-bit pixel array in memory, supported by a front-end library for drawing shapes and text. In the backend, three PIO state machines generate VGA signals: one for HSync, one for VSync, and one for pixel output. The pixel state machine connects to the frame buffer via DMA, producing 60 Hz VGA signals while the game updates at 30 FPS without CPU intervention. Chess pieces are rendered from 28×28 pixel art sprites by Etienne Pouvreau, stored with transparency in chess_rom.h.

Main Program ( animation.c )

The main program initializes hardware, then launches two protothreads. The board thread (30ms interval) scans reed switches and runs the state machine, triggering computer moves when needed. The keypad thread (20ms interval) handles menu navigation, timer updates, and promotion input. The system clock runs at 150 MHz.

AI Use

We used AI assistants for code generation and debugging throughout development. Specifically, AI generated several functions in the computer module (quiescence search, minimax with alpha-beta pruning, iterative deepening) and the entire keypad/menu interface in user_interface.c. All AI-generated functions are annotated in the source code. We also used AI extensively for formatting and styling this website. See Appendix: AI Prompt Log for detailed prompts and edit statistics.

Results

The final implementation of PicoChess is functionally complete and responsive. The VGA display renders smoothly with no visible flickering or tearing. Reed switch readings and keypad presses are detected with minimal latency, contributing to a smooth gameplay experience.

The success of our implementation is primarily evaluated through direct gameplay. We assessed the game based on the responsiveness of piece detection, the clarity of visual feedback, and how intuitive the physical interaction felt. Testing with multiple users confirmed that players could understand the system and play without technical instructions.

Speed of Execution

Accuracy and Functionality

The reed switch detection system accurately identifies piece presence on all 64 squares. The system correctly distinguishes between piece lifts, placements, and captures. Move validation ensures all moves conform to chess rules, preventing illegal moves from being accepted. All implemented chess rules function correctly:

Usability

Before the game begins, the system verifies that all pieces are correctly positioned. Each square is highlighted with a green border when its expected piece is detected, or a red border when the piece is missing or misplaced. The game only starts once all 32 pieces show green, ensuring reliable detection before play begins.

The system provides clear visual feedback throughout gameplay. When a piece is lifted, legal move destinations are highlighted with colored borders (cyan for moves, magenta for captures). Invalid board states trigger error indicators with red and yellow borders. The menu system allows easy configuration of game mode, player color, and timer settings. The physical board provides natural interaction while the VGA display supplements with game state information.

Computer Performance

The computer opponent plays reasonably and has achieved checkmate against inexperienced players. However, due to the unoptimized evaluation function, it tends to blunder pieces in certain positions. The shallow search depth (2-3 ply) limits its ability to see tactical sequences, and the arbitrary weighting of material, position, and mobility leads to suboptimal decisions.

One notable quirk: the computer strongly prioritizes putting the opponent in check, since check positions receive high evaluation scores. While checking moves are often strong, this bias causes the computer to pursue checks even when better quiet moves exist. Tuning the evaluation weights and increasing search depth would significantly improve play quality.

Safety

The project operates at safe voltage levels (3.3V logic, 5V USB power). All GPIO pins are configured with appropriate pull-down resistors to prevent floating inputs. Current-limiting resistors protect GPIO outputs when driving the reed switch matrix. The system includes error handling to recover gracefully from invalid board states.

Gameplay Screenshots

Idle state Legal moves
Left: Board in idle state awaiting player move. Right: Legal moves highlighted when piece is lifted (cyan for moves, magenta for captures).
Computer move Invalid state
Left: Computer's move displayed with cyan borders on source and destination. Right: Invalid board state showing error indicators.
Check Checkmate
Left: King in check with limited escape options. Right: Checkmate screen displaying winner.
Pawn promotion Game menu
Left: Pawn promotion menu for piece selection. Right: Pre-game menu with mode, color, and timer options.

Conclusion

This project successfully demonstrates a physical chess game on the RP2040 that combines reed switch-based piece detection, VGA graphics, and a minimax-based computer opponent. The system bridges physical and digital gameplay, allowing players to move real pieces while receiving visual feedback and playing against an AI.

Intellectual Property Considerations

The chess engine and board detection system were implemented from scratch. The VGA graphics library was provided by Professor Adams. The minimax algorithm is a standard game programming technique, and our implementation is original. Chess piece sprites are by Etienne Pouvreau, released as a free asset pack. The project is for educational purposes only.

Future Improvements

Future work could add castling support to complete the rule set, implement sound effects for captures and checkmate, add an opening book for stronger early-game play, and improve the physical board construction with better cable management and more permanent reed switch mounting.

Appendix

Permissions

The group approves this report for inclusion on the course website.

The group approves the video for inclusion on the course youtube channel.

Parts List

Part Quantity Cost
Littelfuse MDSR-7-10-20 Reed Switches 64 $37.07
330Ω Resistors 11 Free (lab)
1N4148 Diodes 64 $2.50
Chessboard with Pieces 1 $12.99
Neodymium Magnets (DIYMAG) 1 pack $9.99
Neodymium Magnets (TRYMAG) 1 pack $13.99
12-Button Keypad 1 Free (lab)
Raspberry Pi Pico 1 Free (lab)
Total $76.54

Source Code

Full source code is available in the interactive code viewer. The complete project includes the chess game engine, user interface module, computer player, and main program files.

Work Distribution

Rachel Lee: Tested/debugged magnet detection across board, attached magnets to chess pieces
Zephan Sanghani: Hardware assembly, software development
Kailey Ye: Soldered and constructed chessboard with reed switches

References

AI Prompt Log

computer.c

Date Function Prompt Edits
Dec 3 minimax_alphabeta() Implement minimax search with alpha-beta pruning using the existing evaluate_board function +104 −8
Dec 3 quiescence_search() Write a quiescence search function that continues searching captures until quiet, and integrate it into minimax +72 −68
Dec 3 iterative_deepening_search() Wrap minimax in an iterative deepening loop that increases depth until time expires +52 −10

user_interface.c/ h

Date Feature Prompt Edits
Dec 8 Menu system Implement a menu with toggle buttons for game mode, player color, timer, and enable/disable start button +232 −39
Dec 8 Chess clocks Add chess clocks with configurable time limits that count down and display in mm:ss format +103 −17
Dec 8 Move history Add a scrollable move history panel displaying moves in algebraic notation with move numbers +193 −30

Note: Prompts were summarized by AI for readability.