PyBadge Hacking

Hacking on Adafruit's PyBadge

Similar projects worth following

Adafruit's PyBadge is coming soon, and I got my hands on a prototype. Now I will do science to it.

What is PyBadge? It's a handheld device the size of a credit card with a display, a bunch of buttons, a microcontroller running CircuitPython and a bunch of extras (neopixels, accelerometer, speaker, flash storage, battery charging, light sensor). It is also a secretly a Feather, as you can connect FeatherWings to it.

It is similar to, but much more powerful than my earlier project #µGame (and the reason why I paused work on #µGame Turbo). I should be able to get my libraries and games from µGame to run on it, but I hope that I can also do some other fun things with it.

  • Finish

    deshipu05/09/2019 at 21:20 0 comments

    Since I have no means of fixing or even debugging that problem (it doesn't appear on the board I have), there is really little I can do further. I'm ending up a proud owner of one of the only few PyBadges in the world on which my games work, yay.

  • Bugs Bugs Bugs

    deshipu05/08/2019 at 20:37 0 comments

    So there is some problem with running my games on the actual final version of the PyBadge — the display goes white randomly several seconds after starting the game. If you have stumbled into that, don't worry, it's not you, it's me.

    The bad news is that it's very hard to debug without actually having a unit that exhibits the problem — it all works perfectly fine on the prototype I have. There has been some changes to pins, in particular the TFT_RST pin was swapped with the TFT_LITE pin internally, but that should be handled by the firmware. I'm still trying to figure out what is happening there.

  • On Sale

    deshipu04/24/2019 at 20:20 0 comments

    I just noticed that the PyBadge is finally on sale at Adafruit:

  • Stage Library

    deshipu04/13/2019 at 10:43 2 comments

    I have now ported the #Stage, a Tile and Sprite Engine to CircuitPython's 4.0 displayio system, so now it runs on any of the Adafruit boards. Here is the Jumper Wire example game running on the PyBadge:

    The screen on the PyBadge is a bit larger, so you can see a bit of trash on the right hand side of the screen. If the game was written for a bigger screen, it wouldn't be there.

    Unfortunately the Stage library is sensitive to how the MADCTL register of the display is set, as it doesn't do rotation in software. That means I had to modify the initialization code on the pybadge, to make it fit what ugame does. Fortunately displayio doesn't care, as it does have software rotation, so the two could be brought in sync.

    The sound on the prototype of PyBadge I have is pretty bad, so I have sound disabled in this demo. Hopefully the final version will be better.

  • Buttons

    deshipu04/11/2019 at 13:07 0 comments

    Handling buttons on a game console requires some special consideration, since it is going to affect how responsive the games feel. Human touch can discriminate really small timing differences, and we definitely don't want to miss any button presses — human input is sacred for computers.

    Since you will usually have quite a few buttons — at least 5, for directions nad fire, and possibly more — there is a big temptation to save some pins by using trick in how the buttons are connected. You may connect them in a matrix, or even charlie-plex them, you can connect them to an analog pin with different voltage dividers, you can use different capacitors and rely on the signal length, or you can use capacitive touch pads to save on components. Whatever you do, there is one problem with all those tricks — they require some logic in the software to work. Even if you have your buttons connected directly to pins, you want them to be either handled by a pin change interrupt, or scanned in background in a consistent manner.

    One way to handle the buttons in the background without imposing too much work on the people programming your device is to include all the required code in a library, and use interrupts — so that they don't have to follow strict requirements about calling a polling function in regular intervals, etc. This lets them write code that blocks, uses delays and so on — which is much easier to understand for a beginner. That is why I wrote the "gamepad" module for CircuitPython — so that I can use it for buttons on the #µGame.

    Another approach is to outsource the task to a dedicated chip, such as the HT16K33 on the #PewPew FeatherWing or a custom programmed ATtiny24 on the #D1 Mini X-Pad Shield — they can do the scanning and the debouncing for your, and you just need a small snippet of code to read the currently buffered button state from them over I²C. Easy!

    Now, back to the PyBadge. That device uses a 74HC165 shift register for the buttons. This is a problem, because it doesn't buffer the button presses — every time you get the data from it, you get the state of buttons at the moment the data was latched, when you started the communication — and not all the presses since you read it last time, which is what you get with the HT16K33 and ATtiny. You can read that state in Python easily enough by bit-banging:

    def get_pressed():
        pressed = 0
        latch.value = 1
        for i in range(8):
            clock.value = 0
            if data.value:
                pressed |= 1 << i
            clock.value = 1
        latch.value = 0
        return pressed

    But in your game you would have to do it constantly, very fast — and at the same time run all the animations and calculations. Not very convenient, and if any of your things takes more time than anticipated, you are going to miss button presses. That makes the experience very frustrating.

    Fortunately, that shift register is very fast — you can get the data out of it in no time at all. So I modified the "gamepad" module a bit, to make it also work with a shift register. Every 8ms it polls the shift register for the current button state, and saves the button presses in a buffer, which is emptied when you query it. This way you can use the same code on the PyBadge as you would on the µGame, just the initialization is different.

    The pull request with the changes is currently in review at

View all 5 project logs

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates