There’s a new embedded hacking tool on the scene that gives you an interactive Python interface for a speedy chip on a board with oodles of GPIO, the ability to masquerade as different USB devices, and a legacy of tricks up its sleeve. This is the GreatFET, the successor to the much loved GoodFET.
I first heard this board was close to launch almost a year ago and asked for an early look. When shipping began at the end of April, they sent me one. Let’s dig in for a hands-on review of the GreatFET from Great Scott Gadgets.
Lots of Fast I/O with Direct Access From Your Computer
GreatFET is a jack-knife for embedded projects — it’s meant to stand in for multiple tools and components during development so that you can work on the problem in front of you right now and figure everything else out later on. For instance, consider testing out a new chip. You could hook it up to your favorite microcontroller, write and flash some test code, and see if the chip you’re testing works the first time. But chances are you have the I2C address wrong, or you hooked up TX/RX or MISO/MOSI backwards, or myriad other common gotchas.
At its simplest, GreatFET is designed to give you an interactive Python shell that controls oodles of IO pins on the board. You run commands and get feedback as fast as you can type them. But this is the tip of the iceberg with the GreatFET. On the more advanced side of things, this board can be used to emulate USB devices, as a data acquisition device for building custom instrumentation, for MSP430 flashing and debugging, or as automated testing gear in manufacturing environments.
Officially named the GreatFET One, this board is a giant leap forward in terms of available pins, horsepower, and software interactivity, at an MSRP of $89.99.
GreatFET Hardware Overview
The chip at the center of the GreatFET is an NXP LPC4330 in a massive LQFP-144 package. On either side of the board you can see the bulk of those 144 pins have been broken out, with 40-pin female headers. There’s also a “bonus row” SIL-20 pin header on one side. The vision here is for the ability to add hardware to the board using shields which Great Scott Gadgets are calling “Neighbors” as a hat-tip to [Travis Goodspeed] who designed the original GoodFET.
The LPC4330 is the same chip you’ll find on the HackRF One; a 32-bit ARM Cortex-M4 with a clock speed of up to 204 MHz. HackRF has made a name for itself as a go-to in the software-designed radio realm, you could think of this as a similar device without the analog radio circuitry attached. The board has a Hi-Speed USB port for interfacing with your computer, and a Full Speed USB port so it can be used as a FaceDancer to emulate USB devices, but under Python control.
I must say kudos to Great Scott Gadgets on the labeling of this board. One annoyance of prototyping with dev boards is having the thing sitting on the bench with a bunch of jumper wires already hooked up, then having to move it to read the pin labels on the bottom of the board. GreatFET pins are labeled on both sides, with top side labels on the outside edge. Frequently used signals like SDA, SCL, MISO, or MISO are individually labeled. Both USB ports are labeled with hints to tell you which one you’re looking for, and all test pads on the bottom have descriptive labels. A sticker the shape and size of the board
comes with it to locate special-use pins was being handed out at KiCon and other live events.
You can easily jumper the signals you need, but for more robust applications you might want to purchase or build a Neighbor. My review kit included a Daffodil Neighbor which brings a solderless breadboard to the party. You could easily build your own Neighbor using protoboard and two double-row pin headers as the spacing is a predictable 0.1″. The bonus row of pins is optional when building Neighbors. Each GreatFET One wisely includes a “wiggler”, a simple tool made of PCB used to pry the two boards apart without bending pins, and you need it to overcome the 100 pins that make connections between the two boards.
Software Delivers Big Versatility
Yes, the hardware on this board is a beast, but the software holds the most promise for versatility. I don’t know if this is a software geeks’ hardware tool or the other way around, but it certainly blurs the line in a good way.
The current state of the software is not quite mature, and both the documentation and the APIs are being worked on. I tripped on a few gotchas out of the gate, but once they were worked out, the parts I tested were simple and the parts of the API used were straightforward.
First the gotchas. I tried installing these libraries for Python 2.7 and that was a no-go; you must use Python 3, which is fine, since Python 2.X reaches end of life six months from now. Next, I had problems connecting to the board reliably, and foolishly assumed I had udev problems when in fact I had a dodgy USB extension cable. Finally, I didn’t do a firmware upgrade, which is the first thing you should do on hardware this new. Luckily, all of these things are actually dead simple if you follow the getting started guide.
$ sudo pip3 install --upgrade greatfet $ gf info Found a GreatFET One! Board ID: 0 Firmware version: git-2019.5.1.dev0 Part ID: a0000a30654364 Serial number: 000057cc67e630187657 $ gf fw --auto Trying to find a GreatFET device... GreatFET One found. (Serial number: 000057cc67e630187657) Writing data to SPI flash... Written 84812 bytes of 84812. Write complete! Resetting GreatFET... Reset complete!
From here you can control the board through a command line interface, by typing commands in a live Python shell, or by writing and running your own Python scripts. There’s a bit of a learning curve here. Online documentation and tutorials are both a bit scarce right now, with the bulk of available information in the greatfet Python package itself. For instance, typing
help(gf.apis.dac) is what helped me figure out which pin to probe for the DAC output.
That said, many existing features are being ported over to GreatFET, so if you’re used to using GoodFET with MSP430 or using a Facedancer for USB dev I think you’ll feel right at home. Let’s take some of this for a test drive.
Test Run: I2C, DAC, and Facedancer
One of the places I often use interactive tools (primarily a Bus Pirate) is in trying out new screens. This is because they usually have a long string of initialization commands necessary to turn them on, and I want to make sure I have that right before I start writing and compiling code for a project.
I2C OLED Display
This turned out to be extremely easy using GreatFET. In just a few minutes I had a screen hooked up and showing a cross-hatched pattern. The board is a Python object in the greatfet library we installed above, and documentation from that library comes up when using tab completion. I used the scan feature to find the address. I2C commands can be sent by adding 0x80 or 0x40 to the beginning of the array of bytes to signify a command write or a data write.
Here’s the code I used. I really love the ability to whip up a quick script like this as it’s dead simple to commit to GitHub for me (or others) to use in the future.
from greatfet import GreatFET ssd1306init = [0xA8, 0x1f, 0xd3, 0x00, 0x40, 0xa0, 0xc0, 0xda, 0x02, 0x81, 0x7f, 0xa4, 0xa6, 0x20, 0x00, 0x21, 0x00, 0xff, 0x22, 0x00, 0x03, 0xd5, 0x80, 0x8d, 0x14, 0xaf] gf = GreatFET() addrscan = gf.i2c.scan() addr = 0 for i in range(len(addrscan)): if addrscan[i] != False: # i is both the index of the array # and the address tested in the scan addr = i if addr != 0: #Initialize the OLED gf.i2c.write(addr, [0x80] + ssd1306init) #Make screen buffer and fill with hash pattern screenbuff = list() screenbuff += 128*[0xCC,0xCC,0x33,0x33] #Write screen buffer to OLED gf.i2c.write(addr, [0x40] + screenbuff)
0-3.3V DAC with 10-bit Resolution
Next up I tested the DAC. Not much to report here. The Python help(gf.apis.dac) function tells us how to set the voltage and what pin is used for the output: “Sets the DAC value on ADC0_0 (0-1023)”. Looking on the huge list of pin functions on the wiki I see that J2 pin 5 maps to ADC0_0. You can see my DMM verifies that setting the value to 512 (50% of the resolution) produces 50% of the 3.3 V rail:
Facedancer USB Emulation
The GreatFET product page links to a Facedancer repo which can be used to emulate USB devices so I decided to give this a try as well. I’ve been aware of this tool since Travis Goodspeed started showing off prototypes back in 2012 but this is my first time trying it out and it’s really neat.
You use two USB cables, and both of them connect to the board with microUSB and to a computer (it doesn’t need to be the same one) with USB Type-A. The Facedancer software is written in Python — I also had to install pyserial — and includes a few different samples. The most straightforward I found when looking around is the ability to mount an ISO file using the board. This makes GreatFET look like a thumb drive with files on it. I had an old version of Mint on hand that I used in the test.
$ git clone firstname.lastname@example.org:usb-tools/Facedancer.git $ sudo pip3 install pyserial $ cd Facedancer $ ./facedancer-umass.py /Marge/linuxmint-18.3-cinnamon-64bit.iso
Complete Fail: You Can Recover from This!
There’s a function of the greatfet class called onboard_flash. Do not play around with this function. I didn’t closely read the doc comments on this and just went along my merry way writing “Hackaday” to the first address space of this flash. Of course, as soon as I rebooted the board it no longer enumerated. This function allows you to overwrite the firmware programmed to the board. Looking back on this mistake, there is clearly a warning about this:
The short version of the story: there’s a DFU mode built into the greatfet Python package installed on your computer. The long version is that I compiled from source and was not able to get my binary to resurrect the board. After opening an issue on GitHub I was directed to the proper commands. First, the code you shouldn’t run:
In : #Do Not Run This Code! In : arr = bytes("Hackaday",'utf-8') In : gf.onboard_flash.write(arr,address=0x00,erase_first=True) In : gf.onboard_flash.read(0x00,8) Out: array('B', [72, 97, 99, 107, 97, 100, 97, 121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
If you happen to do this, or any other foolish thing to brick your board, the NXP chip has a hardware DFU mode that’s dead simple and will have you up and and runnning again in about twenty seconds. Just hold the “DFU” button on the board, press and release the “RESET” button, then run the following command:
$ gf fw --dfu --autoflash dfu-util 0.9 Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc. Copyright 2010-2016 Tormod Volden and Stefan Schmidt This program is Free Software and has ABSOLUTELY NO WARRANTY Please report bugs to http://sourceforge.net/p/dfu-util/tickets/ dfu-util: Invalid DFU suffix signature dfu-util: A valid DFU suffix will be required in a future dfu-util release!!! Opening DFU capable USB device... ID 1fc9:000c Run-time device DFU version 0100 Claiming USB DFU Interface... Setting Alternate Setting #0 ... Determining device status: state = dfuIDLE, status = 0 dfuIDLE, continuing DFU mode device DFU version 0100 Device returned transfer size 2048 Copying data from PC to DFU device Download [=========================] 100% 52736 bytes Download done. dfu-util: unable to read DFU status after completion Trying to find a GreatFET device... libgreat compatible board in flash-stub mode found. (Serial number: 000057cc67e630187657) Writing data to SPI flash... Written 84812 bytes of 84812. Write complete! Resetting GreatFET... Reset complete!
This Tools Does It All, If You Choose to Use It
What’s the final verdict on the GreatFET? If you decide to go all in and make this the board you have in your kit, it will live up to its name and be a great tool.
That’s true of almost any bench tool, right? If you’re really good at using your oscilloscope, but then need to perform some advanced tricks using a friend’s scope by a different manufacturer, it’s going to take you some time to figure things out. The GreatFET has a learning curve, but if you put in the time and make this your go-to tool, the sky is the limit on what you can do with it. However, if you rarely pick it up, you’ll need to glance back at the tutorials each time.
For me, this tool makes a ton of sense because I’m a frequent user of Python on the desktop. I can commit my GreatFET scripts to a repo and look back to them as my own tutorials. This is much preferred to my previous go-to tool, the Bus Pirate, which has its own live terminal language that I have to keep relearning without the same easy ability to save and reference previous hacking sessions. And the extensibility of Python is so vast that any data processing, logging, or IO manipulation you need to do is both possible and relatively easy.
The power of the chip on this board is insane, but truthfully why wouldn’t you go for a beefy chip in terms of IO, speed, memory, etc. It’s quite possible you will never outgrow the functionality of this chip. The labelling of the board, and interface methods are well thought out and well executed. I don’t see a way the hardware could be any better on the GreatFET.
My only hesitation is the state of the documentation and API. Right now I don’t see a way to read from the ADC, and I’m not sure if there is just one ADC pin or if you can multiplex to a number of pins. This is just one example of the alpha state of the tutorials and quick start information. But I fully expect this to improve. The project is completely open source, the team is good about responding to GitHub issues, and I think a good set of user-contributed examples will grow as more people begin using the board.