An ARM microcontroller board with built-in battery and power management, all in a compact package that fits in your pocket.
Why? I've built a lot of wearable lighting projects and got tired of wiring together the same 3 parts: arduino, charging controller & battery. They always felt janky and flat lipo batteries can explode if they get damaged (especially if you're wearing it!!!)
I wanted something compact, rugged and could pump out enough current for a lot of blinkenlights without any additional parts. What I've ended up with is this little beast with 4 onboard PWM MOSFETs, each driving up to 2.3A per channel!!! Develop your project faster with onboard LEDs attached to each PWM output -- so you can play without wiring anything up.
It's breadboard friendly, has 8 additional GPIOs (12 total) and a git repo with examples in Arduino, ChibiOS, libopencm3, and STM32Cube -- choose your favorite flavor.
The controller should have everything you need on a single PCB: MCU, battery, USB, charger, buttons, and LEDs for status and debugging.
It needs to easily fit inside a pocket or in the palm of your hand.
You should be able to throw it around without much concern for damage. The problem with the typical lithium pouch cell batteries, is they will explode if they get bent or punctured. This project will use a cylindrical lithium battery so it can take some abuse.
This will have 2 buttons: One satisfying on/off push button and another tactile momentary button which can be programmed to do anything (i.e. cycle through modes).
On most LED controllers, the single button for both power and mode selection is horrible! To turn it off, you either have to press and hold for an undetermined amount or cycle through all modes to get it to stop blinking. Not a very good user experience at all.
The goal of ThunderPack is to be accessible to beginners and experts alike. With that in mind, CircuitPython seemed like an important thing to include. Only one problem...the chip I chose will not work for it.
Why? STM32L072xx and CircuitPython
I liked the STM32L07 because it's small, low-power and has integrated EEPROM. The only problem is that CircuitPython requires ~50KB of flash to work as expected*, and the STM32L072 only has about 128KB.
* you can technically get CircuitPython/MicroPython to fit inside 128KB, but it doesn't include the USB mass storage device firmware loader or the REPL. In my opinion, this removes the two most useful things of CircuitPython -- so why bother.
Upgrade to STM32F4xx with big flash and speed boost!
A great thing about the SMT32 line of chips is how they attempt to maintain pin compatibility between families. Which means we can upgrade ThunderPack to the STM32F4xx chip, which packs a whopping 1MB of flash space and can run up to 100Mhz, without significant changes to the board.
It's pin-compatible, but unfortunately not a drop-in replacement because the chip footprint itself is a little bigger (7x7 vs. 5x5). I had to rearrange a few things but was able to keep the overall form factor and pinout the same. I will also need to update the examples for this chip and the Arduino core.
Feel free to follow along the process in the STM32F4 branch on Github.
As the board is finally in the more production-ready phase, I'm collecting ideas for what people would do with ThunderPack. Share your ideas in the comments!
Open Hardware Summit
I will also be going to the Open Hardware Summit in New York in March and hope to have a handful of these boards with me to give away.
While talking to friends about the projects they wanted to use ThunderPack for, I realized that the 18650 battery size might be a bit big for smaller projects. So I took the design and shrunk it to two smaller battery sizes: 14500 (AA) and 10440 (AAA).
The real downside to the smaller batteries is power. These are the maximum ratings I've found for cells with built-in protection:
Ultimately the 10440 is the least bulky, but also severely lacks juice for projects involving LEDs; however, it could still be useful for other projects.
ThunderPack needs to be accessible to everyone, so the next step is to get CircuitPython running on it. I've done a little work on this already and it's clear I'll need to make some hardware changes to support this. More details soon...
Open Hardware Summit
I'll be flying to New York for the Open Hardware Summit in March and I'm planning to bring a handful of these boards with me. This will be my first time at a hardware conference, so I'm very excited and not sure what to expect.
It's official, ThunderPack has been added to version 1.8 of the STM32 Arduino Cores project! This version hasn't been released yet, but support for ThunderPack will conveniently be there for Arduino when it does.
I also have another PR open to remove the need to install outside software to flash programs to the board from Arduino. This update should also benefit all STM32 boards which support USB flashing via the DFU protocol. This also led to a pretty interesting conversation about the DFU protocol and potential enhancements to the dfu-util program itself.
More Bugs, More Prototypes
In writing the Addressable LED (WS2812B) examples, I found a bug with the board design...
Naturally, an addressable LED strip should be powered by the battery and the "Batt+" pin is connected directly to the battery. This all sounds good, right? Well, imagine this: You turn your board on, the program runs a lighting program to the LED strip, then you turn the board off. At this point the board stop sending new data to the strip, but the power isn't remove because it's directly connected to the battery. So, the strip continues to display the last pattern sent to it until you physically remove it from power. 🤦
The next version of the board (rev 5) will have a pin which provides power after the on/off button.
Of course I'm already thinking about what to do after the board is finalized. Here are the ideas I have running around my head currently:
MicroPython (or CircuitPython) support.
A version of the hardware built around the smaller 14500 battery (AA size). This would be for more compact projects and give up to 1A of power.
We're rounding the corner to a final product! I've been getting feedback from friends, creating documentation and prepping arduino support.
Pin out diagram
The real step to making something real and usable by others is documentation. And in my mind, the first tangible piece of documentation for a custom board is the pinout diagram. From there an intrepid maker can dig up datasheets as necessary to get things running.
I went through a few iterations of this because I wanted it to be easily viewable without scrolling (a vertical oriented board meant vertical scrolling on laptop screens). If the labels look familiar, I borrowed the style from the adafruit pinout diagrams.
There's still room for improvement (I'm not loving the angled labels), so if anyone wants to lend a hand or ideas, please let me know. (also the SVG file is also an inkscape file)
Another important step to making a board usable by others is platform support; notably Arduino. These days I run a little closer to the metal, but there's a lot of value in giving all makers a very accessible starting point.
The stm32duino project already provides arduino support for STM32 boards; however, I still needed to add Thunder Pack board configs to it. Luckily the stm32duino team (notably [fpistm]) have been very responsive and helpful with my pull requests. Along the way, I even found a bug with one of their binaries and am providing additional pull requests to cut down on the number of outside software dependencies necessary for an end-user to get up and running with any of their boards.
If I'm lucky ThunderPack will be supported by stm32duino 1.8.0! 🤞
Hardware Reviews & Feedback
A couple weeks ago I sent the hardware files to some friends who actually work in hardware design & development. Through that, they pointed out that I was missing some decoupling caps, my USB traces could be optimized for data line impedance, and a few other helpful tricks. This was incredibly helpful and also reassuring about the overall design.
The next step is to build a few more boards and hand them off to more friends for real-world testing.
The boards have arrived! I haven't assembled any yet, but everything is feeling a lot more polished.
Now that the boards are close to completion, I've reached out to some friends and asked them to give them a spin and put them through their paces. I'm excited to get their feedback.
If you're interested to be a beta tester, let me know and I'll help you get setup.
Now 100% more dongle & sewable
The new batch has a hole at the end so it can be hung from a carabiner and notches if it will be sewn to something. The dongle hole can be removes from the board with a pair of diagonal cutters, if it's unnecessary.
Debug Changes + More GPIO
When I moved from 4 layers to 2 layers, space got tight and I had to move the JTAG/SWD pins to the bottom of the board, under the switch (assuming you'd have the switch on top and the debug headers on the bottom). At the time I thought this was a clever way to save some space and keep the layout tidy.
While waiting for the new round of boards, I've been working on writing a decent WS2812B addressable LED example and have been using the debugging interface quite a lot. It's become clear that having the debug pins on the bottom means you cannot debug AND be on a breadboard; which is inconvenient.
So last night I rerouted things.
Now, instead of a dedicated JTAG/SWD block, the necessary 3 pins (reset, PA13, PA4) have been added to the GPIO rows. The happy side-effect is now the board has 2 additional GPIO pins to use!
Next Round of Boards...
I'm controlling my twitchy finger from ordering a new batch of boards with the latest routing. First, I want to build a couple boards from this batch, run them through some tests and get the WS2812B example working.
This is one of those projects that I've been casually working on for the past couple years. Every few months I pick it up, iterate on it a bit, and then put it away. Well, the past few months have seen a great deal of progress and I'm really happy with how far it's come.
In fact, I took one of the recent iterations of it to Burning Man and it survived the week in the harsh elements beautifully. Nothing beats some real-world testing.
Here's a brief rundown on what's been changing:
I've upgraded the MOSFETS to supply max 2.3A per PWM channel (there are 4 PWM channels!!! You know, so you can drive really big LEDs or just a long string of them. (however, you're still limited by the battery voltage)
The lithium battery charger IC has been changed to more than double the charging current from 500mA to 1.1A.
So Many Example Programs
II've been going crazy writing examples for the board across 4 different popular HAL libraries:
STM32Cube (Official STM32 HAL lib)
My goal is to have the same examples for each HAL (with some exceptions) so people can compare 1:1 how the libraries differ. It could even be a useful tool for people looking to switch from one library to another (maybe someone familiar with Arduino wants to get closer to the bare metal).
PCB: 2-Layer -> 4-Layer -> 2-Layer
Even though the overall circuit design isn't too complicated, it can be challenging to effectively route everything on such a narrow board. After reading Hackaday's article on 4-layer PCBs, I decided to give 4 layers a try. It truly made routing the PCB so much easier!
The only problem, though, is the cost. It's still twice as expensive as a 2 layer board, and even more with some PCB houses. For a prototype run, it averages out to $8+/board just for the PCB. Because I want this board to be economical and accessible to anyone, I've decided to switch back to the 2-layer design (although, I could be convinced to keep 4-layers).
The latest 2-layer redesign feels fine, however, I'm still a long way from from being a PCB designing expert. So if anyone is interested in taking a look at the latest iteration, I'd love feedback:
I was never really happy with calling the project "Lit Fist". It seemed to pigeonhole it as purely an LED controller. Even though that was the original goal of this project, it has been expanded to be much more than that. Now I see it as a general purpose battery-powered, ARM board with 4 high current outputs and 10 GPIOs. With that in mind, the name has been changed to "Thunder Pack". It still makes for a pretty awesome personal LED controller for wearable projects.
This morning I submitted an order for a fresh run of prototype boards with the new 2-layer design. Now comes the part that I hate...waiting for the PCBs (it's like waiting for Christmas as a kid). When they arrive and if they work as expected, we'll be at a place to call this project feature complete! Until then, I'll keep myself busy writing documentation and coming up with more examples. Stay tuned.
Not long after I posted the project log "The anatomy of feature creep", @Xasin posted a comment suggesting that I try something other than an AVR chip for this project. For example, many ARM chips have a built-in USB peripheral and bootloader, which would remove some of the complexity & hardware from the previous plan.
I have been looking for an excuse to play with ARM chips and this was all I needed to go foraging down the path to learn everything I could. ARM is very different than AVR and I spent several days with my head spinning trying to figure everything out.
This may have removed some hardware from the design, but replaced it with some new mental gymnastics.
I started with the STM32F070RB (via a Nucleo-64 dev board). From what I could find, the STM32 line of chips has a great following and quite a bit of online support. I've been really enjoying playing with this chip, so far. The only problem is that it doesn't have an integrated EEPROM; which the final device will need.
This week I'll be giving the STM32L053R8 a try. It looks very similar to the F070, and has an EEPROM built-in. If it works, it'll have everything I need in a single chip.
The original suggestion from @Xasin was to use a ESP32 Pico for this project and I'll be giving that dev board a try soon. This chip would give the project wifi and bluetooth, however, I'd have to add a UART/USB bridge and an external EEPROM chip.
Here are the tools I'm using for ARM development:
VS Code IDE
ChibiOS RTOS & HAL
I tried to use Eclipse, I really did. My problem is, I really f***ing hate eclipse. It's large and clunky and I'm just used to more streamlined IDEs. When I use eclipse, I feel like I spend more time dealing with the IDE than actually working.
I read about people using Visual Studio Code and decided to give it a try. Once I got it up and running I was floored by the level of integration it has with ARM development through the plugins. Everything from compiling & flashing to debugging & stepping through the execution of the program is all in the IDE.
This part is probably complete overkill. Do I really need a RTOS for fading some LEDs? Probably not...but, it does make fading without blocking a hell of a lot nicer than traditional methods. Also, the HAL it includes for interfacing chips is quite nice.
After I prototype a little more with the dev boards, I'll decide on a chip and send off another order to OSH Park for more purple PCBs.
The first version of the controller worked pretty well and had just a couple small things I wanted to improve on. It should be an easy upgrade, right? Well, my friends, welcome to a journey down feature creep road.
My primary gripe was that the Attiny10, although tiny, doesn't have an on-board EEPROM to save the last LED mode that was used. No worries, we can upgrade to the Attiny85 just fine.
Just move some things around the board to make room, and we're good to go, right?
Well, now that we have an Attiny85, we might as well use all PWM outputs so the controller can do RGB. Just throw a couple more mosfets in there.
While we're at it, programming via the ISP isn't super convenient and it's completely inaccessible when the device is wrapped in shrink tubing (my cheap/compact enclosure to keep everything together). The board already has a USB port for charging the battery, why not use it to programmed the attiny? Micronucleus is a pretty well trodden USB bootloader for the attiny range, just wire up the USB port to the Attiny85 and we should be good to go, right?
Not so fast! Unfortunately, micronucleus needs a minimum of 12 Mhz to work and the Attiny85 datasheet says it needs at least 4.5V to run more than 10Mhz -- we're not going to get that directly from a single lithium cell.
That's fine, we'll just add boost converter to raise the voltage to 5V 1A. We'll also need to add a couple simple schottky diodes to keep the battery and USB voltage from each other.
This was the first version. It has a itty bitty attiny10 driving it. This was the first time I'd worked with an attiny10 and it was a good experiment. It was driving 1 meter (50 LEDs) of SparkFun's sewable LED ribbon and with that battery, it was fading it in and out for about 24 hours on a single charge.
Rugged (held up to over a week of use at Burning Man)
Long battery life.
Charges from by USB
Can only program it with an AVR ICE tool.
Does not remember the last LED animation mode that was used. (attiny10 has no EEPROM).
Programming it via ISP with an AVR ICE was fine, but it wouldn't make it very easy to work on, if I wanted to make any last minute tweaks in the field. Also, we live in a time of USB bootloaders and I have some free time on my hands.