USB basis AVR programmer

A USB AVR programmer made from discrete components.

Status du project
Date de début 13/11/2014
Status work in progress
Initiateur(s) Magnus

Ok, so, you may argue that there are already (too) many ways to program AVRs. If you have a serial or parallel port, many very simple solutions exit. But as soon as you are stuck with USB, you needs some extra logic, typically either some kind of USB to GPIO chip/cable or another uC. If you don't like the former (many need closed-source drivers), you can use an AVR-based programmer. Yes, Arduinos can be used to program arduinos.

Hey, but that's a chicken-egg problem: how to program the first programmer? - This project aims at providing a solution.

  • avrdude integration
  • micro bootloader
  • open-source everything

The programmer is built using (optional in parenthesis):

  • 2x npn transistor, BC547
  • 2x pnp transistor, BC557
  • 2x resistor 10k
  • 4x resistor 100k
  • 4x resistor 100R
  • 1x capacitor 10nF
  • USB B connector through-hole
  • pinheaders, 2.54 mm
  • (diode)
  • (jumper)
  • PCB (OSH park)

To test the stuff:

  • USB-2.0 HUB
  • arduino uno

<doodle |[usbbasis] Interested in joining this project>

participation active participation passive suivre de loins


Reading the USB specs, I came across the port test modes. They would make perfect GPIOs for computers with only USB ports. Unfortunately, these modes only work in high-speed mode, where signal levels are somewhat small (reaching only 800mV without termination). I would need to build a small level shifter. A USB device made from discrete electronics, that just has to be done!

Also, D+ and D- cannot be driven independently, but only three combinations are possible J, K, SE0_NAK, where either one line is high or none, respectively (i.e. never both lines are high). Now, the AVR samples the data line on the rising edge of the clock. To send a one, the normal operation would be:

  • clk=0, data=X
  • clk=0, data=1
  • clk=1, data=1
  • clk=1, data=X

For a zero:

  • clk=0, data=X
  • clk=0, data=0
  • clk=1, data=0
  • clk=1, data=X

… which would ask for all four combinations.

Well, luckily this situation can also be achieved with the available three states by delaying the data line.

Unfortunately, the story is not yet over… after bread-bording a bit with a simple npn-inverter circuit, the following issue caught me: the arduino is power hungry on SCK (arduino pin 13), where it has an LED connected. The level shifter needs a bit more driving strength…

Three issues need to be fixed:

  1. the signal levels need to be adjusted,
  2. the driving strength need to be high enough to drive a LED, and
  3. the data (MOSI) signal needs to be delayed wrt the clock (SCK/CLK).

This circuit (put in LTspice) would do: This is the result, with a close-up on the CLK rising edge:

A PCB is not really necessary, but with KiCad it's quite quickly designed (single-sided) and sent to for production to OSH Park (as double-sided, with empty top layer…)

The PCBs are back. Time to solder!

That's an X-mas hack! – finally a quite minute to connect up everything (the ISP pins are also available on the I/O pin headers of the arduino, a perfect place to hook up a logic analyser): Let's send the init programming sequence AC-53-00-00 (MSB first) and see if the AVR answers with 53-00: … it DOES! Merry Christmas! (and more to come next year)

avrdude hacking! – reading does of course not work, but here just an example command:

$ ./avrdude -C avrdude.conf -p m328p -c usbbasis -P 250.3.3
avrdude: Device signature = 0xff003f
avrdude: Expected signature for ATmega328P is 1E 95 0F
avrdude done.  Thank you.

… and the corresponding screenshot from the state analyser: showing actually the correct results.

This is some micro bootloader that may be used to install a real bootloader. I do not know if it is really working, but keep it here for reference. 26 bytes and no warranties!

; ub -- the micro bootloader V0.01a
; Copyright (C) 2015 Magnus (magnustron)
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; GNU General Public License for more details.
; You should have received a copy of the GNU General Public License
; along with this program.  If not, see <>.
; This is a "boot loader loader" used to install a bootloader via serial port.
; It is quite minimal.
; Supported devices (tested): ATmega328
; Baud rate: fosc/16 (if not set to something else but default by bootloader...)
  clr	r29
  ldi	r28,0xB8	;enable RX, TX and add a few ones
  std	Y+9,r28		;UCSR0B (0x00C1)
  ldd	r16,Y+8		;UCSR0A (0x00C0)
  sbrs	r16,7		;check RXC0
  rjmp	wait_data
  ldd	r17,Y+14	;UDR0 (0x00C6)
  ldd	r16,Y+8		;UCSR0A (0x00C0)
  sbrs	r16,7		;check RXC0
  rjmp	wait_addr
  ldd	r28,Y+14	;UDR0 (0x00C6)
  st	Y,r17
;  rjmp	loop
; Looping is done via wrapping of IP. Well, as long as nothing else (like a bootloader) is written to the flash...

With an ardiuno uno this python snipplet was used as a proof of principle for the communication “protocol”:

import serial
import time
PORT='/dev/tty.usbmodemfd121' # the arduino on my Mac
BAUDRATE=115200 # this is since I still have the arduino bootloader, which leaves its traces
print ser.write(''.join(map(chr,['E',0xC6])))
print '%02X: %c' % (ret,chr(ret))
  • projects/usbbasis.txt
  • Dernière modification: 2021/10/20 17:29
  • de micmac2