In the Arduino ‘microcontrollers’ forum, there have been a few threads on programming an atmega2560 with an usbasp, recently. These made me wonder whether or not usbasp has proper support for AVR’s with >128KB flash. Searching the net to find the answer, is not that obvious. I bought a Chinese usbasp clone so I could do some experimenting myself.
Fuses, BOOTRST, pc wrap around…
The Arduino IDE burns the bootloader to an avr in two avrdude commands. It sets the fuses in the first step and burns the actual bootloader image in a second one. (It also manipulates the lock bits but that is not important in this discussion).
For the atmega 2560 it sets the fuses to lfuse=0xFF, hfuse=0xD8 efuse=0xFD.
Bit 0 of the hfuse is of special importance in this matter:
- hfuse=0xD9, BOOTRST=1: the exception table is at 0x00000, so this is where program execution begins (first entry of that table is the instruction executed when the mcu comes out of reset).
- hfuse=0xD8, BOOTRST=0: the exception vector is at the beginning of the bootload section, in our case at 0x3E000.
If you upload a sketch using a programmer, the whole flash is erased, including the bootloader. The sketch is placed at 0x00000. So th elogical thing to do is set the fuse to 0xD9 to start program execution at the beginning of the flash.
However using hfuse=0xD8 seems to work also. Program execution then starts in the bootload section (which only contains 0xff’s, as we just erased the flash), but will proceed towards the end of memory and will wrap around to 0x00000 and start the sketch. There is one caveat: a sketch bigger than 0x3E000 bytes overlaps the boot loader section, and this trick will not work. However a sketch of that size would be a very rare thing.
It is often believed this wrap around trick does not work for the atmega 2560, but this is not true. If the image is correctly flashed, it does work. It has been reported to work when using an avrispmkII as programmer and in my tests with the ArduinoISP sketch + avrdude 6.1, it worked also. It seems to not work with the usbasp however.
Fischl’s most recent firmware (v1.04) introduced support for flash > 128KB. So it could be expected that the ‘wrap around’ should work. (Otherwise put: upload using programmer with hfuse set to 0xD8 should work). Unfortunately a subtle bug is the reason it does not. Towards the end of this post there is a link to a fix.
Firmware versions < v1.04. have no big flash support so it should not be a surprise wrap around does not work. Likewise it could be expected that burning a bootloader does not work with these versions. Surprise, surprise: it does work correctly! Even with the medieval version v1.02.
What does it mean to support flash > 128KB?
To prepare programming a byte into flash, a programmer sends the “Load Program Memory Page (high or low byte)” command. In this command there is only room for a 2 byte address. This is the address of a two byte word. So this command can address a range of 64K words i.e. 128K bytes.
The atmega2560 has 256 KB flash, so to support this device, the programmer must complete the full address by sending the “Load Extended Address Byte” command upfront.
As an example, take the first two bytes of the bootloader. These should end up at byte addresses 0x3E000 and 0x3E001. To obtain the word address, shift the byte address 1 bit to the right: 0x1F000. So the word address sent in the “Load Program Memory Page High/Low Byte” commands is 0xF000 and the extended address byte is 0x1.
In the sections below, I figure out what firmware is in the usbasp clone I bought. Then, on hand of a few tests, I check whether it supports flash > 128 KB.
Determining the firmware version.
I opted for one of these blue pcb’s, marked “USBASP V2.0 LC Technology”.
In lsusb it shows up as follows:
(On windows the information below can be retrieved from device manager)
$ lsusb ... Bus 002 Device 019: ID 16c0:05dc Van Ooijen Technische Informatica shared ID for use with libusb ...
The vendor id is 16c0, product id is 05dc, so the manufacturer string can be read as follows:
$ lsusb -v -d 16c0:05dc | grep Manufacturer iManufacturer 1 www.fischl.de
This is an indication it runs the Fischl firmware, or one based on it.
Following command returns the ‘device version’.
$ lsusb -v -d 16c0:05dc | grep bcdDevice bcdDevice 1.02
This ‘device version’ corresponds to the version of the Fischl firmware:
|Version Number||Filename||Features added|
|1.04||usbasp.2011-05-28.tar.gz||Support for AVR’s with flash > 128KB|
|1.03||usbasp.2009-02-28.tar.gz||Support for setting the ISP speed (option -B)|
|1.02||usbasp.2007-10-23.tar.gz||Firmware of device I used is based on this version|
So the device I received seems based on Fischl 1.02. The flash is not locked, so I started by reading in the firmware and keeping a backup of it, so I can always restore the vendor firmware if needed.
The vendor firmware is not identical to the Fischl 1.02 release, it is 300B bigger. Although Fischl’s firmware is GPL, I could not find the vendor’s firmware sources.
When using the usbasp, avrdude gives a warning:
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
This is consistent with the firmware being 1.02: setting the ISP speed from avrdude was introduced only in 1.03. As a consequence, avrdude warns it cannot set the default ISP speed. This warning is only relevant if you are working with a slow part for which you explicitly need to set a slow ISP speed.
Now, does the original vendor firmware support flash > 128KB?
No. In Fischl’s firmware this feature was only introduced version 1.04 and from a few tests it is clear that the vendor did not add support for this to the Fischl 1.02 code it started from.
Nevertheless, even without proper support for flash > 128KB, you can accomplish quite a few tasks like correctly programming the booloader near the end of the 256KB flash of the atmega2560.
Let us see how far we get with the vendor’s original firmware. Note that the Fischl 1.02 release can accomplish the same as well:
I started by burning the bootloader into an atmega2560 using the Arduino IDE. It was programmed correctly, I verified this by reading back in, the resulting image, using ArduinoISP sketch (with avrdude v6.1) as a programmer. Moreover, the bootloader is fully functional!
So far so good.
However, if you read back in the image using usbasp, you get an incorrect image: the bootloader appears in the file in two locations: once just below 0x20000 and once just below 0x40000. In reality the bootloader is in there only once, but the firmware’s lack of support for high memory addressing reports the memory above 0x20000 twice, once for the lower 128KB and once for the upper 128KB.
Now, if you flash a blink sketch using ‘Upload using programmer’, the sketch will not work! Why not, what has happened?
Reading back in the image with the ArduinoISP sketch gives the answer: the sketch ended up in memory at 0x20000 instead of the expected 0x000000.
If hfuse is 0xD8, program execution starts at 0x3F000, proceeds towards the end of flash, wraps around to 0x00000 where normally the sketch should be. Probably the program excecution will proceed and in the end reach 0x20000 but the code will not run: it cannot run from this address range.
A side effect of BOOTRST on programming flash through isp?
I did not yet find official documentation confirming this, but the following seems consistent:
If hfuse is set to 0xD8 (BOOTRST=0), and the flash is programmed without first executing the “Load Extended Address Byte” command, the image ends up in high memory (last 128KB). If you do the same thing with the hfuse set to 0xD9, the image will end up in the first 128 KB of flash.
Let us see what this means for both high fuse settings:
With this fuse set, when programming a bootlader, it will be programmed correctly because the image gets written in the second 128KB half of flash, 2K before the end: at 0x3E000, which is correct.
With this fuse set, as sketch uploaded through “Upload using programmer” does not run, because it ends up at the beginning of the second half of 128KB: at 0x20000.
Conversely, if you set hfuse to 0xD9, and burn the bootloader (with a single avrdude command, not with the IDE: the IDE would start by setting the fuse to 0xD8), it will end up near the end of the first 128KB: at 0x1E000 and the bootloader will not work. (You have to change the fuse to 0xD8 afterwards, but that will not help).
With this fuse setting, uploading a sketch using “Upload using programmer” will work correctly because the sketch ends up in the first 128KB, at 0x00000, which is where it should be.
In the Arduino fora, the latter is suggested as a solution: set hfuse to 0xD9 when using “Upload using programmer”. But that is actually not needed if the programmer correctly sends “Load Extended Address Byte” commands.
As a side note, the Arduino Reference suggests to first load the bootloader to a fresh microcontroler from factory, before using it. This will set fuses to appropriate values. For the amega2560, this would be 0xD8 and that can indeed perfectly work, also for uploading using a programmer.
A subtle bug in Fischl firmware 1.04
So after upgrading the firmware to v1.04, I expected to be able to use “Upload using programmer” together with using hfuse=0xD8. I uploaded a blink sketch to my mega and to my surprise the led did not start blinking! Aaaaargh!
v1.04 has this subtle bug: the extended address byte is only set if it differs from the previous one. The previous one is incorrectly initialized to 0x00. As a consequence when starting to program the sketch at 0x00000, the “Load Extended Address Byte” is not executed and the sketch still ends up in 0x20000!
A fix already lives on the internet, a bit buried in this rc forum thread: http://openrcforums.com/forum/viewtopic.php?f=109&t=1363
I keep a compiled version here: usbasp-v1.5.hex along with the sources it was compiled from.
Upgrading the usbasp firmware.
Please decide for yourself whether you want to upgrade the firmware. If you have a different board, check whether its schematics is the same. If the usbasp’s flash is not locked, you can first backup the original firmware, in this case you can restore it any time later.
The picture above shows how this is done with an “ArduinoISP shield”. Note JP2 is closed to allow resetting the atmega8. The 5V jumper is closed too, in order to power the atmega8.
Here are command lines for respectively backing up the original firmware and flashing the new one:
avrdude -v -p m8 -c arduino -P /dev/ttyACM0 -b 19200 -Uflash:r:usbasp-ori.hex:i avrdude -v -p m8 -c arduino -P /dev/ttyACM0 -b 19200 -Uflash:w:usbasp-v1.5.hex:i
After upgrading the usbasp with this version, it shows up in lsusb with device version 1.05. Connect to an atmega, burn bootloader so hfuse is set to 0xD8 and then burn a blink sketch using “Upload using programmer”. Tadaaah, it blinks.
Moreover you can now:
- flash images spanning more than 128KB.
- set the SPI speed using the -B parameter. (the argument is a float specifying the bit clock period in microseconds. A very useful feature.
Compiling the firmware
The code does not compile with a recent avr-gcc. I settled for using an older avr-gcc, from an arduino 1.0.x IDE that was left on my system:
$ export PATH=_path_to_arduino-1.0.x_/hardware/tools/avr/bin:$PATH $ avr-gcc --version avr-gcc (GCC) 4.3.2 ... $ make main.hex ...