I don’t have any dedicated programmers. I have been programming Atmel chips using the USB-to-serial bitbang method.
Recently, I thought I’d get one because doing a re-programming cycle is taking quite a bit of time (a disadvantage of serial port bitbanging).
A popular one on Aliexpress seems to be this “USB ISP” one, so I bought one. I chose this one because it has a nice aluminium case, and a pinout diagram imprinted on the case, which is handy. After having so many one-off projects with bare PCBs collecting dust, I now appreciate the importance of having projects in their own box or case.
While it has “USBasp” in the item name, it turns out that this was not a USBasp device, and getting it to work like one takes some effort.
It identifies itself as a zhifengsoft HID device when I plug it into Linux:
usb 3-1: new low-speed USB device number 3 using ohci-platform usb 3-1: New USB device found, idVendor=03eb, idProduct=c8b4 usb 3-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0 usb 3-1: Product: USBHID usb 3-1: Manufacturer: zhifengsoft
avrdude does not recognize the device, even after creating an entry with the corresponding vendor/product ID. This particular device was designed to work with their Windows-based UI called ProgISP and will not work with avrdude.
And apparently you can’t just take the USBasp firmware and flash it into this device, because the circuit is somewhat different.
After some research based on the PCB markings, I found these sites that talk about them:
- GreenPhotons: Hacking an AVR programmer
- GreenPhotons: Hacking an AVR programmer II
- USBasp Experiences – efiHacks Wiki
Disassembling the device is simple. While grabbing the side of the case, firmly push the USB connector inwards and the board should slide out the other end. You can then gently pull the board out by the IDC connector.
The programmer seems to be based off of the popular USBasp programmer, but modified somewhat (to what end I’m not sure). It lacks some features offered by other USBasp programmers, like the ability to control the target’s clock, or to use 3.3V for certain targets. But at $2 with a nice aluminium case, what more can you ask for?
It’s powered by an ATmega88 (I read that older versions were based on ATmega8). The markings on the board indicate that this is a
MX-USBISP-V4.00. You can ignore tHe date because it was never updated; the older V3.02 also has the same date. While the GreenPhotons blog was talking about V3.00, I have verified that this version suffers from the same issue.
Note that there are provisions on the PCB to add a voltage regulator, and the PCB link marked “C” can be cut to separate USB power from the rest of the system. Link “D” can be cut if you wish to disable target power. However, none of these options were used.
The crucial difference with this clone is that the USB
D- pin is additionally connected to
PD3, shown here highlighted in blue:
However, in the USBasp’s
PORTD‘s data direction register was initialized like so:
/* all outputs except PD2 = INT0 */ DDRD = ~(1 << 2);
This causes the USB
D- line to be actively driven from
PD3, thereby impeding communication to/from the USB host.
The rest of this post will talk about (1) correcting this problem in USBasp, and (2) uploading the firmware into your zhifengsoft programmer.
Fixing up USBasp
In GreenPhoton’s blog posts above, you will find that he recompiled USBasp with those changes and provided the HEX file.
From what I read in his post, it doesn’t exactly inspire confidence in his provided HEX file:
So I grabbed my 3 ½ year old project and imported it into the 3 versions newer Atmel Studio 7. Compiling showed a couple of errors and warnings caused by the newer configuration settings and the newer, more picky version of GCC, but finally it compiled through now for the ATmega88.
Here instead, I shall just suggest a very simple patch to the HEX file compiled by USBasp’s author himself. Essentially, we just want to modify the
DDRD value to make
PB3 inputs instead of outputs.
Here’s the snippet of the original compiled code that initializes
In the ATmega88 HEX file, the corresponding code is located on line 185, and here’s the line with the bytes highlighted:
Let’s patch the code to set
DDRD = 0b1111_0000, thus the corresponding new bytes should be
0x80EF and the correct checksum for that line should now be
With these simple changes made to the HEX file, you can now use this updated file to be flashed into the programmer.
Either that, or you can compile USBasp yourself. I have tried this as well and it wasn’t too difficult — you just need to sprinkle some
const keywords in
usbdrv.[ch] and it will compile cleanly with
Re-programming using an Arduino
You can upload a sketch to an Arduino to make it act like a programmer. (I assume you do have an Arduino lying around somewhere?) This programmer is supported by avrdude, so you only need the Arduino IDE to upload the sketch.
The good thing about the Arduino IDE is that it comes with
avr-gcc as well, so no other additional downloads are necessary. I unzipped the Arduino IDE zip file into
C:\. You can find the avr binaries under
hardware\tools\avr\bin, and the
avrdude.conf resides in
hardware\tools\avr\etc. You can either go to the
bin directory to run avrdude, or you can add the
bin directory to your
%PATH%. The same can be applied to the Linux and Mac versions (I think).
The USBasp programmer was designed to be programmed via the same port it uses to program the target. All the ICSP pins are connected through, except for RESET, which is used to control entry into programming mode. That pin can be connected to RESET via a jumper when programming is required.
We will choose to use the “old wiring style” in the Arduino sketch. This can be done by looking for the following lines in the sketch, then uncommenting the
// Uncomment following line to use the old Uno style wiring // (using pin 11, 12 and 13 instead of the SPI header) on Leonardo, Due... #define USE_OLD_STYLE_WIRING // <-- uncomment this
Use the Arduino IDE to upload the modified sketch into your Arduino. After you are done, close your Arduino IDE, in case it also tries to open the serial port.
You should then wire up your Arduino to the programmer’s ICSP connector by following the code in the sketch. This is where the pinout diagram imprinted on the case comes in handy.
#define RESET 10 #define PIN_MOSI 11 #define PIN_MISO 12 #define PIN_SCK 13
Also, remember to hook up
GND, so you should have a total of 6 pins connected. Here, I have spliced a 6-pin IDC connector into the provided programming ribbon cable. You can more easily connect to “standard” 6-pin ICSP headers that way.
For the final step, you will need access to the programmer’s PCB to enable self-programming.
Insert a wire to bridge the
--> UP <-- holes as indicated on the rear of the programmer board. That will bridge the RESET on the programming header with the RESET on the ATmega88 to allow it to be programmed. The PCB holes are so small that I had to use AWG 30 wire-wrapping wire.
Now, verify that your Arduino programmer is working by running the following
avrdude command from the
bin directory. Use
-P to specify your serial port, which in my case is
If you are using an Arduino Leonardo as your programmer, you should specify
-c arduino, but if you are using an Arduino Uno, you will instead need to specify
-c stk500v1 -b 19200.
C:\arduino-1.8.3\hardware\tools\avr\bin>avrdude -C ..\etc\avrdude.conf -vv -c arduino -P COM15 -p atmega328 avrdude: Version 6.3, compiled on Jan 17 2017 at 12:00:53 . . . avrdude: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.01s avrdude: Device signature = 0x1e930a (probably m88) avrdude: Expected signature for ATmega328 is 1E 95 14 Double check chip, or use -F to override this check. avrdude done. Thank you.
If avrdude can successfully read the device signature and identify the target device properly, it means that the programmer is working. Here, despite me specifying the part as an ATmega328, it still correctly detected the device as an ATmega88 (
If you get a
0x000000 device signature instead, your programmer might not be working correctly. Check your wiring to ensure you have the connections right.
Now using avrdude, your Arduino should be able to read the device signature and fuses. The zhifengsoft programmer already has the correct fuses programmed in, so nothing needs to be changed. Refer to the USBasp README to find out what are the
hfuse values to use for different processors.
All that’s left to do is to program the updated HEX file with avrdude:
avrdude -vv -c arduino -P COM15 -p m88 -U flash:w:usbasp.atmega88.2011-05-28.hex:i
Again, if you are using an Arduino Uno as your programmer, you will need to modify your command slightly:
avrdude -vv -c stk500v1 -b 19200 -P COM15 -p m88 -U flash:w:usbasp.atmega88.2011-05-28.hex:i
usbasp.atmega88.2011-05-28.hex is the path to the HEX file you have just patched above, and
i stands for Intel HEX format.
After programming is complete, your programmer should now have the blue LED lit to indcate it is powered on. When there’s activity, the red LED will flash.
Plug in the programmer into a USB port and verify that it can be detected by the OS. If the OS does not detect your programmer, it could be that you flashed the wrong HEX file without the updated
Congratulations, you are now the proud owner of a USBasp programmer.