Close
0%
0%

PewPew FeatherWing

A shield for Adafruit Feather boards with buttons and a LED matrix display, for simple games.

Similar projects worth following

Game programming is hard. Sure, you can easily throw together something in RPGMaker, RenPy or Unity3D, and it's great -- but you don't actually know how it works inside. There is a certain skill required to go from scratch, write your own main loop, handle events, push the pixels, etc. Incidentally, the same exact skills are required when programming any other interactive system, such as a graphical user interface, an automatic appliance, a mobile art installation or... a robot! Those are going to be much more common in our lives soon. If we want to stay in control, we need to be able to program them ourselves, and for that we need those skills. They empower us and give us back the control over the technology.

One great tool for teaching it is PyGame -- which is a library, and not a game engine, so it forces you to attend to all those pesky details of game engine internals yourself. Which is a bit difficult, of course, but ultimately very useful. But even if you play with PyGame on the Raspberry Pi, it's still a very complicated and difficult to understand system. The learning curve is steep, and debugging is hell.

Enter MicroPython, and one of its flavors, CircuitPython. It's written by the people at Adafruit with the education in mind, but it runs on infinitely simpler devices than your average computer. Devices which you can't break easily, because reflashing the program will reset them to a known good state. Devices which run on batteries for hours, and which you can carry in your pocket. Devices, for which there is a plethora of add-ons and sensors that you could make use of in your game.

However, as of yet, there is no game library and/or add-on that would allow to easily create games in CircuitPython. This project is an attempt to fix this.

View all 10 components

  • Version 1.5

    Radomir Dopieralski6 days ago 0 comments

    The boards for version 1.5 arrived yesterday, and today I had some time to assemble one. It didn't work initially, but after touching each solder joint with the soldering iron again, it started to work. Go figure.

    Programming of the ATmega8 went smoothly, and it does appear as an I²C device together with the display controller, so everything seems fine. I will test the key scanning and the display library later. The sound code requires some more work before it's usable -- hopefully I will be able to beat it into shape soon.

    I already have a version 1.6 PCB designed -- the only difference is that it has pads for an SMD speaker, and that the speaker is driven from two GPIO pins, not one and ground -- giving me one more bit of resolution and louder volume. I'm not ordering that yet, though, because I'm sure I will have some ideas for improvements while working with the version 1.5.

  • Sound

    Radomir Dopieralski05/31/2017 at 05:01 0 comments

    I got the blinking (actually breathing) support added to the IS31FL3733 library during the PyCon.US sprints, so now you can have a nice hardware blinking cursor. Back from the conference, and I started working on the next prototype.

    Since I want it to have sound (simple 8-bit "pew pew" sounds, as the name implies), I looked around a bit for some kind of dedicated sound-generating chips. Turns out they are all pretty old, coming from old game consoles and computers, and not actually that easy to program. So I decided to put an 8-bit microcontroller on the board for generating the sounds. And of course, once I have the microcontroller there, I can drop the keyboard chip, as that microcontroller can also handle the keys.

    So here's my list of requirements for that chip:

    • at least 6 GPIO pins with internal pull-ups for the buttons,
    • hardware I²C slave peripheral,
    • at least 8-bit timer for sound generation with a decent speed,
    • internal oscillator,
    • small enough to fit on this board,
    • easy to program,
    • already in my drawer,
    • cheap.

    The minimum number of GPIOs is thus 10 (6 for keys, 2 for I²C, 2 for the speaker), so that rules out the ATtiny85 and friends. Looking through what I had on hand, I finally narrowed down my choices to two chips: STM8S003f2 and ATmega8. The first one is very cheap, the second one I already know quite well. I decided to start with the STM8, because it's always a nice bonus to learn something along the way.

    So I re-created my dev environment and flashed the blinking LED sketch on a STM8 development board. So far so good. Then, just for kicks, I tried the UART example for it, but it didn't work correctly -- the speed was all wrong. Oh well, it's not like I'm going to need that. I even found a nice example of an I²C slave for this chip online.

    Then I realized that I need to make sure it actually fits on the board with all the required components. But to determine the required components, I need to actually use a bare chip, not this dev board. So I found a universal breakout board, and soldered one of the chips on it. Then I tried the blink example on it. Hmm, strange, it programmed fine, but the pin only goes up and down a fraction of a volt -- something is fishy. I checked all my connections multiple times, tried the same code on the dev board, used shorter wires for the required capacitor, etc. -- but nothing. It almost looks like that time when I forgot to switch a pin to output on an AVR and was just toggling a pull-up. Several hours and a couple of datasheets and application notes later I decided to throw the towel. I used up all my motivation for the day.

    Next day I started work on the ATmega. I already had a bare ATmega8 chip nicely soldered to a PCB -- one of #D1 Mini Tote old prototypes, so I used that. Just added a piezo on PB1 and an ISP header for easier programming. I also used the I²C slave code that I had from that robot -- it's nice for timing-critical stuff like sound, because it doesn't use interrupts. A few lines of C added and I can read the pins from the D port through I²C -- the key handling is done. (Perhaps I will add some de-bouncing there later on). Yay.

    Encouraged with this small success, I proceeded to playing with sound. The plan is to be able to send a bunch of parameters, similar to what you can play with at http://www.bfxr.net/, and then have the chip play that, possible mixing multiple channels if the sounds overlap. But I started with a simple PCM sound playback, basing the code on http://avrpcm.blogspot.ch/2010/11/playing-8-bit-pcm-using-any-avr.html. That worked pretty well, especially after a few simplifications and some tuning. And it started to sound really good once I replaced the piezo with a tiny speaker I got for that.

    In fact, it worked so well, that for I moment I considered just having a set of few fixed sounds, hard-coded as PCM data in the chip's flash, and triggered with I²C. But after a few calculations and experiments with lower baud rates I realized that...

    Read more »

  • ESP8266 GPIOs Suck

    Radomir Dopieralski05/16/2017 at 20:33 0 comments

    That's a fact.

    But let me start at the beginning. When I realized that the IS31FL3733's open/short LED detecting feature can't be used for reading the state of the buttons for this shield, I immediately designed a second prototype with the buttons connected (as a button matrix) to the GPIO pins of whatever feather board is plugged into it. But since I needed 5 pins for that, I had to plan carefully.

    For the row pins I choose gpio12, gpio13 and gpio15, because I wanted to have them pulled low -- and that pretty much excludes gpio0 and gpio2, because if I pull those low, the board won't boot. I also avoided gpio16, because that's connected to a LED on the Feather HUZZAH. That left gpio14 and one more pin for the columns. The choice was hard, but I finally semi-randomly decided to use gpio16 after all -- mostly because I didn't want the board to fail to boot when the user is holding a key. Yeah, I know, a bad decision -- I also forgot about ghosting effect and generally that prototype is not going to fly. But whatever.

    Then I did some quick research around available keyboard handling chips, and designed another prototype that uses a TM1650 chip, which I ordered from China. (I will probably make yet another prototype that uses a simple atmega both for handling the keys and for making sounds, but more about that later.)

    Fast forward two weeks and I found in my mailbox the PCB for the second prototype, courtesy of OSHPark. Two days later the first prototype PCB arrived. And the chips? They have just left China, because the seller apparently couldn't remember when they put them. So here I am now, traveling to PyCon.us tomorrow, wanting to show something working, with the two prototypes. I decided to give that direct-gpio approach a try.

    So I tried with different approaches. Pull-downs on the rows and columns switched from high-z to high -- that doesn't seem to work, the diode on the GPIO16 seems to be interfering. OK, then let's remove the pull downs and try internal pull-ups on the rows and switching from high-z to low on the columns -- nope, gpioi15 is pulled low internally, and that's stronger than the internal pull-up. Then maybe reverse it, internal pull-ups on the columns and swithing between high-z and low on the rows? Nope, pull-down on the gpio15 again, and gpio16 doesn't have an internal pull-up. Argh. I even tried some mixed modes, low for gpio12 and 13, and high for gpio15, but I couldn't get it working.

    In the end, I just ported my libraries to CircuitPython (which I wanted to do anyways eventually) and used the shield with the Feather M0 Basic board, which has none of that nonsense and simply just works, albeit a bit slow.

  • Version 1.4

    Radomir Dopieralski05/13/2017 at 11:12 0 comments

    I ordered the PCB for version 1.4 from OSHPark on May 1st. It was sent to fab the same day, and shipped on May 4th. Today (May 13th) I found it in my mailbox. I was waiting for it eagerly, hoping it would arrive before May 17th, when I'm departing for PyCon.us -- I wanted to take the prototype with me to show it there. It actually arrived 4 days earlier than anticipated, which is great!

    However, I'm still missing parts for it. The buttons I was able to scavenge from the earlier prototypes, but this new version uses a TM1650 chip for handling the buttons, and that is still on its way from China (it took the seller two weeks to ship it). You can see the empty footprint waiting for it.

    Then again, I was able to verify that the display works (I was a bit afraid I broke something when moving the chip on the other side of the board).

    Hopefully the chips arrive soon, or I will also receive the version 1.2 of the prototype -- that's the one with the buttons connected directly to GPIO pins, and with ghosting problems. That was also ordered on May 1st, but shipped on May 9th, so 5 days later...

  • Prototyping

    Radomir Dopieralski05/09/2017 at 22:44 0 comments

    While I'm waiting for the new PCBs with two different approaches to buttons, I decided to start writing some code. But I need to test it somehow, and it's difficult with the non-functional buttons, so I decided to use a combo of the #D1 Mini X-Pad Shield and #D1 Mini Matrix Shield. Sure, the x-pad shield uses a different chip than what I will use, and the matrix shield only has 1 shade of 1 color, but at least I can get some code going on them. I can later replace the parts that handle the display and keys.

  • Ghosting

    Radomir Dopieralski05/01/2017 at 12:44 0 comments

    When I realized that the IS31FL3733 chip is not going to handle the button scanning well enough for this use case, I decided to design a new prototype board, with the buttons connected directly to the GPIO pins of the Feather.

    However, I want this to work with all Feather boards, including the ESP8266-based Feather HUZZAH, which means that I only have a few GPIO pins to work with. A quick count gave me 7 pins: GPIO0, GPIO2, GPIO12, GPIO13, GPIO14, GPIO15 and GPIO16. However, there are some caveats. The GPIO15 pin has to be pulled low at boot, otherwise the ESP8266 will boot into some weird mode. The same with GPIO0 and GPIO2 being pulled high. And finally the GPIO16 is a bit special and doesn't have an internal pull-up.

    I have 6 buttons, so with the naive approach I will need 6 of the GPIO pins. I made a quick go at the PCB for that, together with six external pull-down resistors. That turned out to be much more complex than anticipated. Also, I really can't leave those pull-down resistors on GPIO2 or GPIO0, so I'm one pin short.

    I considered my options. I could ditch the resistors (which would simplify the design a lot) and use internal pull-ups (which would also solve the problem of the pin state at boot). Hmmm... a quick redesign, and it already looks much better. But I can't use GPIO16 (no pull-up), and the GPIO2 has a LED on it, which lights when you press the button. It would be nice to at least leave that one free...

    Fortunately there other ways of connecting buttons. I can make a key matrix and scan it. Let's see, I have 6 buttons, so the best matrix I can make is 3x2, requiring a total of 5 pins. Not much, but progress. I quickly made another PCB design using that, leaving the GPIO16 and GPIO2 pins free. Perfect! At this point I was pretty late, so I saved the design, generated the gerber files and ordered the prototype PCB at OSHPark. And went to bed.

    And then, lying in the bed, I realized that my design has a fatal flaw: ghosting. It's a game console, and people are not going to just press one button at a time like the cultured citizens they are. They are going to be mashing all the buttons at once, trying to beat the game. And the simple key matrices, the kind that I used in this design, have a problem when several keys are pressed at once: the keys connect together several rows and columns of the matrix, and in effect the microcontroller thinks that more buttons are pressed than actually are. A simple solution for that problem is to add diodes to every button, so that it won't connect the columns and rows in both ways -- this way preventing the columns that are not currently selected by the scanning algorithm from getting power. However, at this point the PCB was ordered and there was simply no room to add 6 additional diodes to it anyways.

    For now I decided to just test the prototype when it arrives and work on the software and the games a little bit, ignoring the ghosting problem, and later I will look for a separate I²C chip that will handle the keys for me.

  • The Concept

    Radomir Dopieralski05/01/2017 at 12:18 0 comments

    Here are some more details about the whole concept of this board.

    The board will be the size of a standard FeatherWing shield -- same as the Adafruit Feather boards, and of course it will plug into those boards. It should work with any of the Feather boards, but I only plan to make the drivers and library available in CircuitPython -- so if you want to use it with any of the boards that don't run CircuitPython, you will need to write the software yourself -- but then again, you are then probably pretty experienced anyways.

    The board will have a bi-color 8x8 LED matrix for display, and 6 buttons for input. It will also contain the electronics for handling the display and buttons. I might add some way of making sounds, but that's not decided yet.

    The FeatherWing will communicate with the Feather using I²C protocol and the two standard pins traditionally used for that on the Feather boards, using a few fixed addresses. All the other pins will be free to be used with other add-ons. The prototypes may be using additional pins for experimenting, but ultimately I want them to be free.

    The power is drawn from the Feather board, which in turn can be powered either through USB, or with a LiPo battery connected to the battery connector. A #Battery FeatherWing can also be used.

    Since the top side of the board is pretty much all taken by the display and buttons, the components have to be placed on the bottom side of the board. They should however be as flat as possible, as to not collide with the components on the top side of the board below.

    There will be a number of CircuitPython libraries for the low-level components of the board, as well as a high-level library dedicated to this particular board and to making games with it. That high-level library might use some simplifications and may add limitations to what can be done, for the sake of making things simpler. Experienced users can bypass that limitation by calling the low-level libraries instead.

    There will be a number of example games implemented for this board, as well as at least one tutorial describing in detail the steps required to write such a game. All those games will be written in CircuitPython. Some of the larger games might not work on all the Feather boards, due to memory limitations.

    Apart from playing games, the board can also be used for controlling other devices -- if a Feather board that has WiFi, Bluetooth or packet radio capabilities is used, or if an add-on giving such capabilities is connected. This will not be covered in the main library, though. (Also, multiplayer games could be possible, but that is also outside the scope for now.)

  • The Buttons

    Radomir Dopieralski05/01/2017 at 11:41 2 comments

    When I started planning this board, I only knew the HT16K33 LED driver chip (well, ok, also the MAX 7129, but that's ancient). That chip has a pretty cool feature -- by adding a diodes to the column pins you can re-use them to scan a matrix keypad at the same time as they drive the LED matrix. The chip even does de-bouncing for you, you just have to read the state of the keys from its registers. Super-convenient for a device like this.

    Unfortunately, the IS31FL3733 chip that I'm using now, while it allows me to control the brightness of each individual pixel, doesn't have such a keyboard-scanning feature. But wait, the datasheet mentions something similar -- it has an open/short LED detection. Isn't a closed button pretty much electrically equivalent to a shorted LED? I could use this, together with the extra column pins that I don't use (the chip supports 12x16 matrixes, I only have 8x16) to scan the buttons!

    I designed the first prototype with that idea in mind. The buttons are connected -- through resistors, for safety -- in place of LEDs on an extra column. Once the PCB arrived and I assembled it, I could start my tests.

    Turns out getting this mechanism to work properly is a little bit involved. First, the LEDs need to be enabled by writing 1s to the corresponding registers on the page 0. Then, the power register on page 3 needs to be set to 1, the minimum power setting. I experimentally determined that this step is not actually strictly necessary for the mechanism to work, but it's probably there for safety, and it prevents the LED matrix from flashing brightly while the chip tests all the lines. Finally, you have to trigger the testing by writing 1 to a bit field in the config register on page 3. Then you have to wait 3.264ms, and finally you can set the current back to what it was, clear the bit field in the config register, and read the LED status from the registers on page 0. Easy.

    I got my code to work, and decided to try and write a simple snake game to see how well it all works. Turns own that it works pretty bad.

    You see, to get a decent responsiveness from the buttons, I need to scan them often. At the minimum once per the game's animation frame. Humans are very sensitive in delays in tactile and visual areas -- especially tactile. So I need to scan often. But you see, to scan I need to drop the current to the minimum setting, which effectively switches the display off. And if I do it for 3.265ms every frame, I get a nasty flickering. The board also makes some suspicious high-pitched noises, which can't be good.

    So that's it for the first prototype. I need to find a better way of handling the buttons. That prototype was going to be trashed anyways, because I made the holes for the matrix pins too small -- that's why the matrix is soldered on top, and not flush with the board on the photos.

  • The Display

    Radomir Dopieralski05/01/2017 at 11:17 0 comments

    I could use an OLED or a TFT display, but there are several problems with that. First and foremost, the pixels are tiny on those, especially on the ones that would fit on a FeatherWing. Second, they aren't very easy to handle, unless I'm using a ready module, which in turn looks pretty bad. Finally, they are rather brittle and easy to damage.

    There is also the problem of graphic design. While I personally have no problems making pixelart for my own games, I expect this to be a problem for someone just starting, and also a big distraction from our goal of teaching the programming of interactive interfaces. So we definitely want to go low-resolution, because then you only have a few pixels you have to care about, and everything goes faster.

    The limited memory and processing power of the devices I am targeting also plays an important role here. Iterating over 8x8 array is almost instant, while doing that with a 320x280 RGB display takes some time.

    So I decided to use a 8x8 LED matrix. But a single-color matrix is a bit limiting, especially when you can only switch the pixels on or off. Sure, you can make a Flappy Bird or a very cramped version of Tetris, but it's not very exciting. That's why I decided to use a bi-color matrix, which looks very pretty with its combination of green and red pixels. I also found a chip that lets me easily control the brightness of individual pixels (or rather their red and green components), which gives me a very nice palette of colors to choose from. There is no blue, unfortunately -- an RGB matrix could be even nicer -- but that would bring the number of pins I need to control to 32, and I simply couldn't find a chip that could handle this.

    So I made the first prototype board using the IS31FL3733 chip and a bi-color 8x8 LED matrix. It took some work, especially as I initially worked with the chips in QFN packages, and couldn't get them to work reliably due to my soldering them by hand being sub-par. But finally the PCB with a TQFP foortprint arrived, and that allowed me to easily solder those huge pins and then it was just a matter of a few hours re-reading the datasheet to figure out which registers I need to modify to bring this thing to life.

    I might need to add some gamma correction for this in software, but it looks better in real life than on the photo -- my phone camera tends to get the color of lights wrong.

View all 9 project logs

Enjoy this project?

Share

Discussions

oshpark wrote 05/10/2017 at 23:43 point

great project!

  Are you sure? yes | no

Radomir Dopieralski wrote 05/10/2017 at 23:46 point

Thank you, hopefully the new PCBs arrive before PyCon.US, so I can show them off there. They just got shipped, and if they arrive within 7 days, I'm good. Otherwise we will miss each other going opposite directions.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

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