Build a Hummingbird Tamagotchi

A pocket virtual pet with a full-color round display, built around one all-in-one board instead of a separate MCU and display module. This guide covers hardware and wiring only — firmware comes in a follow-up guide.

RP2350-LCD-1.28 Edition
Difficulty: Intermediate Build time: 2–3 hrs (excl. print time) Est. cost from scratch: ~$25–35 USD Soldering: required 3D printing: required
Why this edition instead of a separate MCU + display module This build uses the Waveshare RP2350-LCD-1.28 — a single round board with the RP2350 MCU, a 240×240 color display, a 6-axis IMU, and Li-ion battery charge management already integrated. An earlier pass of this guide used a separate ESP32-C3 SuperMini + GC9A01 display module instead, on the reasoning that having 4 spares of each part left more room to prototype. For a one-time build, that reasoning doesn't apply — this edition is meaningfully simpler to wire (no separate charge board, no boost converter, no 7-wire SPI harness between two boards) at the cost of having only one unit on hand if something goes wrong. It also picks up two things the separate-module build didn't have: a backlight you can actually dim/turn off in software (battery-life relevant), and a free 6-axis IMU for future tilt/shake interactions.

What you're building

A Tamagotchi-style virtual pet themed around a hummingbird, built on a single integrated board rather than wiring a display to a separate microcontroller. This guide is hardware and wiring only — component selection, the power system, the input controls, a component-compatibility validation pass, and the 3D-printed enclosure. Firmware (the pet logic, sprite animation, save state, power management) is intentionally left as a placeholder for a follow-up guide.

Note on graphics A hummingbird's whole visual appeal is iridescent color — the reason this build uses a 240×240 full-color IPS panel rather than a monochrome OLED. The tradeoff is battery life: see the callout in Step 1. This board's backlight is independently software-controllable (dimmable/off), which the bare 7-pin GC9A01 module used in an earlier version of this guide could not do — a real advantage for managing that tradeoff later in firmware.

Battery safety — read this before you buy or wire anything

LiPo batteries are not optional-safety territory

Tools required

Bill of materials

This edition needs far fewer parts than a separate-MCU build — no charge board, no boost converter, no display module, no long SPI wiring harness.

Waveshare RP2350-LCD-1.28 board

Waveshare RP2350-LCD-1.28

MCU + Display + IMU · qty 1

RP2350, 240×240 round IPS (GC9A01A), QMI8658 6-axis IMU, onboard Li-ion charge management — all on one board.

~$15–20 · waveshare.com
503035 LiPo battery

3.7V LiPo, 503035 (500mAh)

Battery · qty 1

Small pouch cell. Needs a 1.25mm-pitch (MX1.25) 2-pin JST-style plug to match this board's connector — verify before buying (see Validation step).

~$5–8
12x12mm tactile switch with colored knob cap

12×12mm Tactile Switch + Knob Cap

Input · qty 3 (of 12 owned, any colors)

Through-hole, 4-pin (2 common pairs), bare legs — no pigtail. Snap-on colored cap for a bigger, easier-to-press face. Not waterproof, not panel-securing on its own — see Validation and the case notes.

~$0.30 each · common "12x12 tactile switch + cap" kits
passive electromagnetic buzzer

Passive Buzzer (~160Ω)

Audio · qty 1

2-terminal, non-polarized. Passive — needs a PWM/tone signal to make sound.

~$0.50
SPDT slide switch

SPDT Slide Switch

Power · qty 1

Spliced inline into the battery's positive lead — this board has no onboard power switch of its own.

~$0.30
M2 brass heat-set threaded inserts

M2 Heat-Set Threaded Inserts

Fasteners · qty 4–6

Brass, knurled. M2×3mm or M2×4mm. Pressed into printed bosses with a heated iron tip.

~$0.10 each in bulk packs
M2 hex socket button head bolts

M2 Hex Socket Bolts

Fasteners · qty 4–6

M2×8mm or M2×12mm button head, threads into the heat-set inserts above.

~$0.10 each in bulk packs
What's no longer needed Compared to a separate-MCU build: no standalone display module, no TP4057 charge board, no MT3608 boost converter, and no 7-wire SPI harness — this board's onboard battery management (an ETA6096 charge IC) and internally-wired display/IMU remove all of that.
Tradeoff: tactile switches instead of panel buttons This edition uses 12×12mm tactile switches with snap-on knob caps for the controls, not panel-mount waterproof pushbuttons. They're smaller and give you 6 cap colors to pick from, but they give up two things the panel buttons had: they don't seal against dust/moisture, and they don't self-secure in a case wall with just a hole and a nut — they need to be soldered to a small mounting board and held in place structurally (see enclosure notes). Worth it for a smaller, more colorful control cluster; not worth it if this pet needs to survive a rainy backpack.
Also needed, not pictured Hookup/solder wire (26–28AWG), solder, heat shrink tubing, 3D printer filament.

Component validation — do this before wiring anything

This board's own wiki was unreachable while researching this guide (blocked automated access), so several details below come from independent third-party sources rather than Waveshare directly. Treat this section as mandatory, not optional — it's specifically designed to catch the things that weren't independently confirmed before you commit solder to anything.

ABoard identity check

BBattery connector compatibility

CConfirm the ground pins

This step used to be a hunt. It isn't any more — Waveshare's official pinout diagram documents three GND pins, so you're confirming known positions rather than discovering unknown ones.

DPower-on baseline, before adding anything

EConfirm each tactile switch's pin pairs

One thing this validation pass could not confirm Whether the onboard ETA6096 charge IC supports true power-path operation (running the board off USB while the battery is connected and the power switch is on) wasn't confirmed from its datasheet. Until it's verified by testing, treat USB-connected-plus-battery-switched-on the same way as any other unverified dual-power-source setup: avoid relying on it, and if you must have both connected, watch for anything getting unexpectedly warm.

System overview

LiPo Battery 3.7V 500mAh Slide Switch spliced into +lead RP2350-LCD-1.28 integrated display + IMU onboard ETA6096 charger USB-C: power + program 2-pin MX1.25 battery in 3x Buttons GP13/14/15 Buzzer GP16 (PWM)
Power flows left to right (teal); MCU-to-peripheral signal wiring shown in pink. Not a physical layout — see the pin reference table for exact GPIOs.

Step 1 — Battery & power switch

1Splice the slide switch into the battery's positive lead

  1. With the battery disconnected from the board, cut the battery's red (+) wire only, a few centimeters from the JST plug.
  2. Strip both cut ends, solder one to each outer terminal of the slide switch (either orientation — it's a simple on/off break in the circuit here, not using the switch's third throw position).
  3. Insulate both solder joints individually with heat shrink before moving on — don't leave bare wire exposed on a battery lead.
  4. Leave the black (−) wire untouched, running straight from the cell to the JST plug.
  5. Confirm with a multimeter (continuity mode, battery disconnected) that flipping the switch actually makes and breaks the connection before plugging it into the board.
This switch is not a normal power switch — it stops the pet's clock Worth understanding before you build it in, because it shapes the firmware and the case labelling. The RP2350 has no real-time clock — the RP2040 had one, the RP2350 replaced it with an always-on (POWMAN) timer that draws from the chip's own supply and has no separate battery-backed pin. So when this switch cuts the battery, the timer isn't merely inaccurate, it's gone. The pet cannot know how long it was off.

Rather than fight that, this build leans into it: the slide switch means torpor. Real hummingbirds enter nocturnal torpor, dropping their metabolism by roughly 95% to survive the night without feeding — so flipping this switch puts the bird into torpor, time stops, and no stats decay across the gap. It wakes exactly as you left it. That's for long-term storage, air travel, or a safety cut.

Everyday "off" is a different thing: a press-and-hold on a button, which puts the chip into a deep sleep with the clock still running, so the pet does get hungry while it sits in your bag. That's where the classic "you neglected me" mechanic lives, and it covers virtually all real not-looking time. Make sure the two are visibly distinct in the firmware — it should be a choice the owner makes, not a trap they fall into.
The real risk here is battery life, not graphics A 240×240 always-on color IPS panel draws meaningfully more current than the segment LCD in a real Tamagotchi. This board's independently-controllable backlight (see pin reference) is a genuine tool for managing that in firmware later (dimming, sleep between checks) — but it's still something to budget for in software, not something solved by the hardware alone.

Step 2 — Buttons

2Wire the three control switches

  1. For each of the 3 switches, solder a short length of hookup wire directly to one leg on each of its two independent sides (the pair you confirmed in Validation step E) — one wire becomes the GPIO leg, the other the GND leg. These switches have no pigtail; this is a direct solder joint to the switch's own through-hole legs.
  2. Snap a colored knob cap onto each switch's actuator before mounting — much easier now than after it's wired into the case.
  3. Mount the three switches to a small offcut of perfboard (their legs through-hole solder in directly), sized to fit behind the case's button cluster cutout — see enclosure notes. This gives them the structural support panel-mount buttons got for free from their own threaded barrel + nut.
  4. Run each switch's two wires back to the board per the table below.
Switches → RP2350-LCD-1.28 — all on header H1 (internal pull-ups, configured in firmware later)
SwitchGPIO legGND leg
A (left / feed)GP13 — H1 pin 11GND — H1 pin 20
B (middle / select)GP14 — H1 pin 13GND — H1 pin 20
C (right / play)GP15 — H1 pin 15GND — H1 pin 20

Cap color has no electrical meaning — pick any 3 of the 6 available colors and assign them to functions however makes sense to you.

Wire these switch-to-GND and pull them UP in firmware — never down The table above is not one of two equally valid options. The RP2350 has a documented erratum (E9): increased leakage current on Bank 0 GPIO when the pad's input buffer is enabled, which can overcome an internal pull-down and make the pin read unreliably. GP13, GP14 and GP15 are all Bank 0. Internal pull-ups are unaffected, so the button must idle high and be pulled to GND when pressed (active-low) — which is what the wiring above does.

Two practical follow-ons: solder a 100nF ceramic capacitor across each switch to ground (it shortens the mid-rail transition E9 dislikes and handles most of the debounce in hardware), and never configure these pins INPUT_PULLDOWN in firmware. Newer A4-stepping silicon fixes E9 outright, but wire it this way regardless — it costs nothing and makes the build independent of which stepping you happen to have.

Step 3 — Buzzer

3Wire the passive buzzer

This buzzer is also bare-legged, no pigtail — solder hookup wire directly to its two terminals, same as the switches. Mount it on the same small perfboard sub-assembly as the 3 switches from Step 2 so the input/audio cluster stays one internal module.

Buzzer terminalBoard pin
Terminal 1GP16 — H2 pin 2
Terminal 2GND — H2 pin 19 or 20
The buzzer lands on the other header — plan for two harnesses The three buttons are on H1; the buzzer is on H2, the opposite side of the board. So the perfboard cluster runs two short harnesses, not one: three signal wires plus a ground to H1, and one signal plus a ground to H2.

This is fine electrically — each header carries its own GND (H1 p20, H2 p19/p20), so nothing has to bridge across the board. But route the two bundles before you glue anything down; on a Φ32.4mm board there is not much slack, and discovering the split after the case is assembled is annoying.

If you'd rather have a single harness, GP0–GP5 are free and sit on H1 — GP5 is H1 pin 12, right beside GP13. That was considered and deliberately not taken here; GP16 stays.
Passive, not active Stays silent on plain DC — needs a PWM tone signal from firmware to make any sound. Exact current draw isn't confirmed by its datasheet; if you notice a weak/distorted tone, add a small NPN transistor as a driver stage between GP16 and the buzzer rather than driving it directly.

Step 4 — Smoke test

4First full power-up with battery installed

  1. Double-check every button/buzzer ground lands on the GND pin you identified in Validation step C, and the battery's spliced switch works both ways.
  2. Plug the battery's JST connector into the board (Validation step B should already have confirmed pitch/polarity match).
  3. Flip the slide switch on. The display backlight should illuminate the same way it did in Validation step D's USB-only test — no firmware required for this, since backlight-on is this board's default power-up state.
  4. With a multimeter, confirm the battery reads a sane voltage (3.0–4.2V) at the board's battery input while the switch is on.

Full pin reference

Every GPIO wired in this build, plus the board's full reserved-pin map for reference
GPIOConnected toFunction
GP6onboardIMU_SDA (QMI8658 I2C) — reserved, pre-wired
GP7onboardIMU_SCL (QMI8658 I2C) — reserved, pre-wired
GP8onboardLCD_DC — reserved, pre-wired
GP9onboardLCD_CS — reserved, pre-wired
GP10onboardLCD_CLK (SPI) — reserved, pre-wired
GP11onboardLCD_DIN (SPI) — reserved, pre-wired
GP12onboardLCD_RST — reserved, pre-wired
GP13Button ADigital in, internal pull-up
GP14Button BDigital in, internal pull-up
GP15Button CDigital in, internal pull-up
GP16BuzzerPWM tone output
GP17–22unused — freeGeneral purpose, reserved for future expansion
GP23onboardIMU_INT1 — reserved, pre-wired
GP24onboardIMU_INT2 — reserved, pre-wired
GP25onboardLCD_BL (backlight) — reserved, software-controllable
GP26–28 / A0–A2unused — freeADC-capable, reserved for future expansion
GP29 / A3onboardBAT_ADC — battery voltage sense, reserved, pre-wired

GP0–5 are also free/general-purpose and unused in this build. Source: Adafruit CircuitPython board definition for this exact board — see Sources.

3D-printed enclosure

Design guidance for modeling your own case — not a ready-made STL. This edition's internal layout is simpler than a two-board build: one round board, one small battery, three buttons, and a buzzer.

RP2350-LCD-1.28 display + IMU + MCU, one board front bezel window, active ∅32.4mm (board OD unconfirmed) LiPo 30×35mm Switch cluster perfboard, 3× 12×12mm + caps Buzzer + sound vents USB-C access Slide switch
Conceptual top-down layout, not to scale — use it to plan relative placement, not exact geometry.

Design notes

What's next

Placeholder — firmware guide to follow This guide stops at working, tested hardware: display backlight confirmed alive on both USB and battery power, battery connector and ground pin verified by the validation pass, every input wired to a known GPIO. The pet's actual behavior — sprite animation, hunger/happiness stats, button handling, sleep/wake power management, and optionally the onboard IMU for tilt/shake interactions — is software, covered in a follow-up guide once this hardware is built and validated.

Sources & verification notes

Hardware sources used for this edition:

Prior-art virtual-pet projects referenced during hardware selection (same as the earlier edition of this guide): TamaFi, TamaFi V2, ESP32-TamaPetchi, DIY ESP32-C3 Tamagotchi, EspTama.

Component specs are drawn from each part's own datasheet or official product page where available; generic/commodity parts (buttons, switch, buzzer) are sourced from vendor listings only, flagged as typical-for-class rather than lab-verified. The Component Validation section above exists specifically to catch what neither source category could confirm — verify against your own physical parts before finalizing anything permanent.