[{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eOverview\u003c/h2\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/944/original/two-player-demo-screenshot.png?1755115735","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n        \u003cp\u003e\u003cspan\u003eThis is my third iteration of a CircuitPython USB host gamepad tester, now with support for two controllers. The main loop in code.py uses asyncio to improve code readability. There's a new boot keyboard to gamepad mapper. For hot-swapping controllers, I devised an unplug detection heuristic to work around limitations in the current CircuitPython USB host implementation. Player numbers get assigned according to Fruit Jam top plate silkscreen port numbers. Player 1 gets USB 1, and Player 2 gets USB 2.\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan\u003eThis demo project is meant to help folks who want to make Fruit Jam libraries for writing games. I don't plan to make a library on my own, but I wrote this code with library-making in mind in case somebody else wants to. Note that some of the performance and stability workarounds included here may become unnecessary once USB host implementation bugs get fixed.\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan\u003eThe code here was written and tested with CircuitPython 10.0.0-beta.2 on a rev D Fruit Jam that I bought from the first production batch that went up in the shop.\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan\u003eRelated work:\u003c/span\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cspan\u003e\u003ca href=\"https://adafruit-playground.com/u/SamBlenny/pages/fruit-jam-gamepad-tester\" target=\"_blank\"\u003eFruit Jam Gamepad Tester\u003c/a\u003e guide (my previous gamepad tester)\u003c/span\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan\u003e\u003ca href=\"https://adafruit-playground.com/u/relic_se/pages/fruit-jam-fruitris-tetris\" target=\"_blank\"\u003eFruit Jam Fruitris (Tetris)\u003c/a\u003e game guide by @relic-se\u003c/span\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan\u003e\u003ca href=\"https://adafruit-playground.com/u/SamBlenny/pages/feather-tft-gamepad-tester-with-sprites\" target=\"_blank\"\u003eFeather TFT Gamepad Tester with Sprites\u003c/a\u003e guide (my original gamepad tester)\u003c/span\u003e\u003c/li\u003e\n\u003c/ul\u003e\n      \n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n        \u003ch2\u003eVideo Demo\u003c/h2\u003e\n      \n\n\n","metadata":{}},{"element_type":"embed","content":"https://youtu.be/vKUXH_GwwaI"},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eParts\u003c/h2\u003e\n\u003cp\u003eFor the board, you'll need a Fruit Jam, or a Metro RP2350 with breakout boards for HSTX DVI and a USB hub. For game controllers, you can use Adafruit's generic SNES compatible gamepad, XInput style gamepads, Switch Pro compatible gamepads, certain HID gamepads (check the code), and wired USB keyboards that provide an HID boot keyboard interface. Note that USB wireless receivers for mouse and keyboard combos may not work. Also, fancy gaming keyboards with N-key rollover may not work (boot keyboards only support 6-key rollover).\u003c/p\u003e\n\u003cp\u003e\u003cspan\u003eFor more information on setting up a Metro RP2350 as a pseudo-Fruit Jam with DVI output and a USB hub, you can read some of the guides by \u003c/span\u003e\u003ca href=\"https://learn.adafruit.com/match3-game-on-metro-rp2350\" target=\"_blank\"\u003eTim C.\u003c/a\u003e\u003cspan\u003e\u0026nbsp;and\u0026nbsp;\u003c/span\u003e\u003ca href=\"https://learn.adafruit.com/minesweeper-on-metro-rp2350\" target=\"_blank\"\u003eM. LeBlanc-Williams\u003c/a\u003e\u003cspan\u003e.\u003c/span\u003e\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/6200","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/6285","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/6267","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/6055","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/6035","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/5999","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/4449","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eUpdating CircuitPython\u003c/h2\u003e\n\u003cp\u003eAs I write this (August 13, 2025), CircuitPython 10.0.0-beta.2 is the most recent build for Fruit Jam. To keep your board up to date, you can use the \"DOWNLOAD .UF2 NOW\" buttons on the appropriate download page of circuitpython.org:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://circuitpython.org/board/adafruit_fruit_jam/\" target=\"_blank\"\u003eFruit Jam Download\u003c/a\u003e\u003cspan\u003e\u0026nbsp;\u003c/span\u003epage\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://circuitpython.org/board/adafruit_metro_rp2350/\" target=\"_blank\"\u003eMetro RP2350 Download\u003c/a\u003e\u003cspan\u003e\u0026nbsp;\u003c/span\u003epage\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eTo install the UF2 File:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eConnect your board to a computer with a USB data cable (\u003cem\u003echarge-only cables won't work!\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003c/em\u003e)\u003c/li\u003e\n\u003cli\u003ePress and hold the board's boot button (Button 1 on Fruit Jam)\u003c/li\u003e\n\u003cli\u003ePress and release the reset button\u003c/li\u003e\n\u003cli\u003eRelease the boot button\u003c/li\u003e\n\u003cli\u003eWhen the removable drive named\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003cstrong\u003eRP2350\u003c/strong\u003e\u003cspan\u003e\u0026nbsp;\u003c/span\u003eappears, copy the UF2 file onto it. After the copy finishes, you should see the\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003cstrong\u003eRP2350\u003c/strong\u003e\u003cspan\u003e\u0026nbsp;\u003c/span\u003edrive disappear and soon after that a new\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003cstrong\u003eCIRCUITPY\u003c/strong\u003e\u003cspan\u003e\u0026nbsp;\u003c/span\u003edrive should appear.\u003c/li\u003e\n\u003c/ol\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eCircuitPython Code\u003c/h2\u003e\n\u003cp\u003eYou can view the code at the\u003cspan\u003e\u0026nbsp;\u003ca href=\"https://github.com/samblenny/fruit-jam-two-gamepad-demo\" target=\"_blank\"\u003esamblenny/fruit-jam-two-gamepad-demo\u003c/a\u003e\u0026nbsp;\u003c/span\u003eGitHub repository. To download a zip archive project bundle with the code and all the necessary libraries, use the \"Download Project Bundle\" button:\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"button","content":"https://github.com/samblenny/fruit-jam-two-gamepad-demo/releases/download/v0.1.1/fruit-jam-two-gamepad-demo-014013a.zip","metadata":{"class":"btn btn-large btn-block btn-primary","button_type":"primary","target":"_blank","zip_folder":"false"}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eInstall Project Bundle\u003c/h3\u003e\n\u003cp class=\"p2\"\u003e\u003cspan class=\"s1\"\u003eTo copy the project bundle files to your CIRCUITPY drive:\u003c/span\u003e\u003c/p\u003e\n\u003col class=\"ol1\"\u003e\n\u003cli class=\"li3\"\u003e\u003cspan class=\"s1\"\u003eDownload the project bundle .zip file using the \"Download Project Bundle\" button above.\u003c/span\u003e\u003c/li\u003e\n\u003cli class=\"li3\"\u003e\u003cspan class=\"s1\"\u003eExpand the zip file by opening it, or use unzip in a Terminal. The zip archive should expand to a folder. When you open the folder, it should contain a README.txt file and a CircuitPython 10.x folder.\u003c/span\u003e\u003c/li\u003e\n\u003cli class=\"li3\"\u003e\u003cspan class=\"s1\"\u003eOpen the CircuitPython 10.x folder and copy all of its contents to your CIRCUITPY drive.\u003c/span\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp class=\"p2\"\u003e\u003cspan class=\"s1\"\u003eTo learn more about copying libraries to your\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003cstrong\u003eCIRCUITPY\u003c/strong\u003e\u003cspan\u003e\u0026nbsp;\u003c/span\u003edrive, check out the\u0026nbsp;\u003ca href=\"https://learn.adafruit.com/welcome-to-circuitpython/circuitpython-libraries\" target=\"_blank\"\u003e\u003cspan class=\"s2\"\u003eCircuitPython Libraries\u003c/span\u003e\u003c/a\u003e\u0026nbsp;section of the\u0026nbsp;\u003ca href=\"https://learn.adafruit.com/welcome-to-circuitpython\" target=\"_blank\"\u003e\u003cspan class=\"s2\"\u003eWelcome to CircuitPython!\u003c/span\u003e\u003c/a\u003e\u0026nbsp;learn guide.\u003c/span\u003e\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eUsage\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003eUpdate CircuitPython and install the code as described above\u003c/li\u003e\n\u003cli\u003eConnect the Fruit Jam board to an HDMI display or capture card\u003c/li\u003e\n\u003cli\u003ePlug the Player 1 controller into the Fruit Jam USB 1 port\u003c/li\u003e\n\u003cli\u003ePlug the Player 2 controller into the Fruit Jam USB 2 port\u003c/li\u003e\n\u003cli\u003eMash some buttons\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eOn the DVI display, you should see a gamepad status visualizer for two gamepads. The status line below each gamepad indicates its USB connection status. The button sprites on the on-screen gamepads should change color as you press actual buttons on your controllers.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eCIRCUITPY/code.py\u003c/h3\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"embed","content":"https://github.com/samblenny/fruit-jam-two-gamepad-demo/blob/v0.1.1/code.py"},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eCIRCUITPY/sb_gamepad.py\u003c/h3\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"embed","content":"https://github.com/samblenny/fruit-jam-two-gamepad-demo/blob/v0.1.1/sb_gamepad.py"},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eCIRCUITPY/sb_usb_descriptor.py\u003c/h3\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"embed","content":"https://github.com/samblenny/fruit-jam-two-gamepad-demo/blob/v0.1.1/sb_usb_descriptor.py"},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eCredits\u003c/h2\u003e\n\u003cp\u003e\u003cspan\u003eThanks to @relic-se for suggestions and inspiration on potential improvements to my previous Fruit Jam gamepad code.\u003c/span\u003e\u003c/p\u003e\n      \n\n\n\n\n\n","metadata":{}}]