Skip to main content
Topic: Using a USBASP v2.0 as a cheap ATmega8 Arduino platform (Read 38175 times) previous topic - next topic

Using a USBASP v2.0 as a cheap ATmega8 Arduino platform

Hello list!

tl;dr: Buy two USBASP v2.0 programmers, follow these instructions and use one to program the other through the Arduino IDE.

[hr:][/hr:]
Edit 2016-01-15 Simplified instructions for the 1.6.x IDE.

First, we now have a method of installing digitally signed Windows libusb drivers for USBASP, thanks to Ray's efforts (link here). This is particularly useful if you are using Windows 8 or 8.1, there is no need to disable signature enforcement.

Then, all the hard work of setting a USBASP board in the Arduino IDE now comes down to adding the following URL into the IDE's preferences panel in Additional Boards Manager URLs. Thank you James!  (detailed instructions).

In the IDE, once the DIY boards are installed in the boards manager, you can select Board "Atmega8/A". Use bootloader NO, processor speed 8MHz (default), processor version Atmega8A and programmer USBASP.

With these, I was able to upload the blink sketch below using ctrl-shift-U (don't forget to close JP2 on the target USBASP).

[attachment=0]

You may still need to update the firmware on the USBASP (instructions below).
[hr:][/hr:]

I finally got round playing with my AVRASP v2.0 boards. The ones Sleepwalker3 mentioned. Thanks mate!

I bought three USBASP v2.0 on ebay for under £1.50 each. They each came with a short cable (5x2 sockets at each end). However, they do not come with the JP2 header soldered on. Solder it or you won't be able to re-flash the on-board ATmega8 chip. JP3 on the other hand has been deprecated. It may still have some use in your own projects. You decide!

Then download some software (this is for Windows):

To use the USBASP programmer with the Arduino IDE, you will need to download the driver, latest firmware and WinAVR-20100110-install.

Small setback, my boards came pre-installed with an older firmware, so I needed to upload the latest. This is to avoid complaints from the Arduino IDE. avrdude: warning: cannot set sck period. please check for usbasp firmware update.

So let's do this, shall we? Link two boards using one of the provided cables. Close JP2 on the board you intend to program. The other board, and ONLY the other board, goes into the USB port. This is the board that will be used as the programmer.

Type the following command in the appropriate folder.

Code: [Select]
D:Downloadsusbasp.2011-05-28binfirmware>avrdude -c usbasp -p m8 -U flash:w:usbasp.atmega8.2011-05-28.hex

Upon success, the R LED on the programmed board will light-up after the new firmware has been uploaded. Unplug, move the J2 jumper to other other board, swap the boards and repeat.

Quote
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.03s

avrdude: Device signature = 0x1e9307
avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed

        To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "usbasp.atmega8.2011-05-28.hex"
avrdude: input file usbasp.atmega8.2011-05-28.hex auto detected as Intel Hex
avrdude: writing flash (4700 bytes):

Writing | ################################################## | 100% 2.01s



avrdude: 4700 bytes of flash written
avrdude: verifying flash memory against usbasp.atmega8.2011-05-28.hex:
avrdude: load data flash data from input file usbasp.atmega8.2011-05-28.hex:
avrdude: input file usbasp.atmega8.2011-05-28.hex auto detected as Intel Hex
avrdude: input file usbasp.atmega8.2011-05-28.hex contains 4700 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 1.68s



avrdude: verifying ...
avrdude: 4700 bytes of flash verified

avrdude: safemode: Fuses OK

avrdude done.  Thank you.

Then we need to add a section in boards.txt for the USBASP v2.0 board. My location was: "C:Program Files (x86)Arduinohardwarearduinoavrboards.txt"

I added the following section at the end of the file:

Code: [Select]
##############################################################
usbasp.name=USBASP v2.0
usbasp.upload.protocol=arduino
usbasp.upload.maximum_size=7680
usbasp.upload.speed=115200
usbasp.upload.tool=avrdude

usbasp.bootloader.low_fuses=0xef
usbasp.bootloader.high_fuses=0xc9
usbasp.bootloader.path=optiboot
usbasp.bootloader.file=optiboot_atmega8.hex
usbasp.bootloader.unlock_bits=0x3F
usbasp.bootloader.lock_bits=0x0F
usbasp.bootloader.tool=avrdude

usbasp.build.mcu=atmega8
usbasp.build.f_cpu=12000000L
usbasp.build.core=arduino
usbasp.build.variant=standard
##############################################################

Almost there! Run the Arduino IDE and select the new "USBASP v2.0" from the tools / board menu.

My blink code follows:
Code: [Select]
/*
  Blink
  Turns on an LED on for one second, then off for one second, repeatedly.

  Most Arduinos have an on-board LED you can control. On the Uno and
  Leonardo, it is attached to digital pin 13. If you're unsure what
  pin the on-board LED is connected to on your Arduino model, check
  the documentation at http://arduino.cc

  This example code is in the public domain.

  modified 8 May 2014
  by Scott Fitzgerald
 */

#define PIN_LED 14

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin 13 as an output.
  pinMode(PIN_LED, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(PIN_LED, HIGH);  // turn the LED on (HIGH is the voltage level)
  delay(500);              // wait for a second
  digitalWrite(PIN_LED, LOW);    // turn the LED off by making the voltage LOW
  delay(500);              // wait for a second
}

The LEDs are connected to PC0/ADC0 (G) and PC1/ADC1 (R). These are Digital Pin 14 and 15 (can someone explain where these values come from?).

To upload the code from the Arduino IDE, use file / upload using programmer (or ctrl-shift-u). If successful, LED G should now be blinking at 1 pulse a second.

Hope this helps! Any comments / additions / corrections appreciated.

edit: fuse values in the boards.txt section.

Re: Using a USBASP v2.0 as a cheap ATmega8 Arduino platform

Reply #1
Didn't think this would make the front page, cool! :)

I have done a bit more digging since.

Here's a nice schematic of the USBASP programmer and pdf manual from protostack:



We also have the ATMega8 pin mapping from jeelabs:


LEDs are therefore:
  • (R) is PC0 is Digital 14
  • (G) is PC1 is Digital 15
  • (JP3) is PC2 is Digital 16

And here is the 5x2 connector pinout from rcgroups.com (arrow shows Pin 1):


To use JP3 as an input, use the internal pull-up, as in:

Code: [Select]
pinMode(PIN_SWITCH, INPUT_PULLUP);

but it occurs to me that since PC0 is directly connected to the JP3, it can also be used as an output (pin closest to the USB connector is GND).

On the back connector, we have RX/TX as well as VCC/GND. I'm using a USB Serial-TTL cable. Connections: Red to VCC, White to TXD, Green to RXD, Black to GND. JP1 on 5V for this to work, otherwise you are feeding 5V through the regulator's output!

... and let's whip-up a simple test to check if everything is working. Or at least sending data back to the PC, which could be quite useful for debug messages. Anyway, after uploading this code, GLED should be flashing. Close JP3 and RLED will light-up. Also, "Hello ?" should appear on the serial console @ 9600 baud.

Code: [Select]
int PIN_RLED = 14;
int PIN_GLED = 15;
int PIN_SWITCH = 16;
volatile int state = LOW;

void setup()
{
  pinMode(PIN_RLED, OUTPUT);
  pinMode(PIN_GLED, OUTPUT);
  pinMode(PIN_SWITCH, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop()
{
  digitalWrite(PIN_RLED, state);
  delay(200);
  state = !state;
  if (digitalRead(PIN_SWITCH) == LOW) {
    Serial.write("hello?n");
    digitalWrite(PIN_GLED,LOW);
  } else {
    digitalWrite(PIN_GLED,HIGH);
  }
}

That's all for today!

Re: Using a USBASP v2.0 as a cheap ATmega8 Arduino platform

Reply #2
I managed to make some progress last week, so here is some more material.

First, I broke out 4 of the bottom pins (2,4,6,8) to a 90 degree connector. The idea is to have a serial console permanently connected to the "dev board". My USB serial to TTL cable is very similar to this adafruit cable. The reason I used 90 degree pins it to avoid putting strain on my laptop USB ports when the USBASP stick is dangling.

See picture, white goes to pin 4, green to pin 6. If you already have the board connected, it will run fine without having GND/VCC connected. Probably best to avoid ground loops.

[attachment=2]

I use KiTTY.exe for my console. During programming (which also use the TX and RX lines), some strange characters may appear on the console, but if I only use it for debug output, I can certainly live with that.

Next, something a lot more exciting (I hope).

I came across Ray's hobby HIDSerial library for Arduino. The library comes with examples and a HIDSerialMonitor program to communicate through HID serial (both send and receive).

[attachment=1]

You can either download a tarball from Ray's GITHub or download my version attached: [attachment=0] (only contains the library and examples).

Let's see what we need to change to make it work with the USBASP:
First, USBASP uses different pins for D+/D-. This is easily fixed in usbconfig.h

Code: [Select]
#define USB_CFG_IOPORTNAME      B
#define USB_CFG_DMINUS_BIT      0
#define USB_CFG_DPLUS_BIT      1

Next, some of the files can be updated to the latest version of V-USB. All but usbdrv.h, leave that one alone or the library won't work.

Now, after checking various websites, the consensus for the fuse values is 0xc9 for high and 0xef for low. Here's the amended section of boards.txt

Code: [Select]
##############################################################
usbasp.name=USBASP v2.0
usbasp.upload.protocol=arduino
usbasp.upload.maximum_size=7680
usbasp.upload.speed=115200
usbasp.upload.tool=avrdude

usbasp.bootloader.low_fuses=0xef
usbasp.bootloader.high_fuses=0xc9
usbasp.bootloader.path=optiboot
usbasp.bootloader.file=optiboot_atmega8.hex
usbasp.bootloader.unlock_bits=0x3F
usbasp.bootloader.lock_bits=0x0F
usbasp.bootloader.tool=avrdude

usbasp.build.mcu=atmega8
usbasp.build.f_cpu=12000000L
usbasp.build.core=arduino
usbasp.build.variant=standard
##############################################################

And here is one of modified Ray's test programs for bi-directional communication over HIDSerial:

Code: [Select]
// *******************************
// HID Serial Example
// Button press
// RAYSHOBBY.net
//
// This program opens an HID serial
// channel and shows the status of
// the pushbutton as it's pressed
// or released. To use it, you need
// to run the HIDSerialMonitor
// from a host computer.
// *******************************

#include <HIDSerial.h>

#define PIN_RLED 15
#define PIN_GLED 14
#define BUTTON 16

HIDSerial serial;

unsigned char buffer[32];

void setup() {
  serial.begin();
  pinMode(BUTTON, INPUT_PULLUP);
  pinMode(PIN_RLED, OUTPUT);
  pinMode(PIN_GLED, OUTPUT);

  digitalWrite(PIN_RLED, LOW);
  digitalWrite(PIN_GLED, HIGH);

}

void loop() {
  static int last = HIGH;
  static int count = 0;
 
  if(serial.available()) {
    int size = serial.read(buffer);
    if (size!=0) {
      if (buffer[0] == '0') digitalWrite(PIN_GLED, HIGH);
      else if (buffer[0] == '1') digitalWrite(PIN_GLED, LOW);
    }
  }
 
  int b = digitalRead(BUTTON);
  if(b!=last) {
    serial.print((b==LOW) ? "button down :" : "button up.");
    if (b==LOW) {
      count ++;
      serial.println(count);
    } else {
      serial.println("");
    }
    last = b;
    delay(50);
  }
  serial.poll();
}

Opening and closing JP3 shows-up on the HIDSerialMonitor. Typing 1 or 0 in the text control switches the G LED on and off.

Uploading this example leaves a couple of KB free (if I can trust my usbasp.upload.maximum_size):

Quote
Sketch uses 3,868 bytes (50%) of program storage space. Maximum is 7,680 bytes.
Global variables use 191 bytes of dynamic memory.

That's it for today! As usual, corrections welcome.

Re: Using a USBASP v2.0 as a cheap ATmega8 Arduino platform

Reply #3
No Arduino board would be complete without... shields! Here's one I cooked earlier.

[attachment=1]
[attachment=0]
Spacing between JP3 on the one side and JP2/JP1 on the other allows for a small breadboard to be used as a "shield". And when the shield is sitting on all three jumper sockets, mechanical coupling between the boards is actually pretty good.

As annotated, we have 5V, 3.3V, VCC (pin2 on the back connector), GND, D16, D10 (pin5 on the back connector) and Reset/PC6.

When programming, we need to make sure that the shield does not interfere with the back connector in any way. JP1 needs to be closed in the 5V position. JP2 is still work in progress. It looks like it needs to be closed too, otherwise we get:
Quote
avrdude: error: programm enable: target doesn't answer. 1
avrdude: initialization failed, rc=-1
        Double check connections and try again, or use -F to override
        this check.
Setting the -F option for USBASP in programmers.txt and leaving JP2 open leads to more aggro:
Quote
avrdude: error: programm enable: target doesn't answer. 1
avrdude: initialization failed, rc=-1
avrdude: Expected signature for ATmega8 is 1E 93 07
So this is why I have added jumper sockets for JP2/JP1 and am closing both.

Another one to investigate: James C4S informs us that
Quote
From the datasheet: "If the RSTDISBL Fuse is programmed, PC6 is used as an I/O pin. Note that the electrical char- acteristics of PC6 differ from those of the other pins of Port C.

If the RSTDISBL Fuse is unprogrammed, PC6 is used as a Reset input. A low level on this pin for longer than the minimum pulse length will generate a Reset, even if the clock is not running. The minimum pulse length is given in Table 28-12 on page 323. Shorter pulses are not guaran- teed to generate a Reset."

The RSTDISBL (reset disable) fuse determines if the pin is a Reset or I/O.
So potentially, we have one more IO pin to play with but I haven't checked this one any further. Worth noting, looking at the schematic: Reset/PC6 pin is permanently connected to an external pull-up resistor.

Re: Using a USBASP v2.0 as a cheap ATmega8 Arduino platform

Reply #4
Just a placeholder for my next fun project.
Edit: Added some code. It's alive!

My kitchen scales died after close to 10 years of service (yay Lidl!) and am now looking into interfacing the USBASP with a HX711 board connected to the 4Kg load cell.
[attachment=2]
I soldered the board to the back of the USBASP, linking VCC (pin2), TX-RX (pin4), RX-TX (pin6), GND (pin8).
[attachment=1]
Idea for this mini project is to send the HX711 data to a Python program via HID-Serial. I used bogde's HX711 library to parse the HX711 output. Since we are using the Atmega8's RX and TX pins, here's the initialisation code:
Code: [Select]
#define PIN_DOUT 1
#define PIN_SCK 0

HX711 scale(PIN_DOUT, PIN_SCK); // parameter "gain" is ommited; the default value 128 is used by the library
And here is the complete code. An almost exact copy of bogde's HX711Serial example, with serial being an HIDSerial object instead of Arduino's Serial object. I also added some LED blinking to try and catch when the HID serial device becomes ready.
Code: [Select]
#include <HX711.h>
#include <HIDSerial.h>

#define PIN_DOUT 1
#define PIN_SCK 0

#define PIN_RLED 14
#define PIN_GLED 15

HX711 scale(PIN_DOUT, PIN_SCK); // parameter "gain" is ommited; the default value 128 is used by the library
HIDSerial serial;

void setup() {
  pinMode(PIN_RLED, OUTPUT);
  pinMode(PIN_GLED, OUTPUT);

  serial.begin();

  digitalWrite(PIN_RLED, LOW);
  delay(2000);
  digitalWrite(PIN_RLED, HIGH);

  serial.println("HX711 Demo");

  serial.println("Before setting up the scale:");
  serial.print("read: tt");
  serial.println(scale.read()); // print a raw reading from the ADC

  serial.print("read average: tt");
  serial.println(scale.read_average(20));  // print the average of 20 readings from the ADC

  serial.print("get value: tt");
  serial.println(scale.get_value(5)); // print the average of 5 readings from the ADC minus the tare weight (not set yet)

  serial.print("get units: tt");
  serial.println(scale.get_units(5), 1); // print the average of 5 readings from the ADC minus tare weight (not set) divided
// by the SCALE parameter (not set yet) 

  scale.set_scale(2280.f);                      // this value is obtained by calibrating the scale with known weights; see the README for details
  scale.tare();         // reset the scale to 0

  serial.println("After setting up the scale:");

  serial.print("read: tt");
  serial.println(scale.read());                // print a raw reading from the ADC

  serial.print("read average: tt");
  serial.println(scale.read_average(20));      // print the average of 20 readings from the ADC

  serial.print("get value: tt");
  serial.println(scale.get_value(5)); // print the average of 5 readings from the ADC minus the tare weight, set with tare()

  serial.print("get units: tt");
  serial.println(scale.get_units(5), 1);        // print the average of 5 readings from the ADC minus tare weight, divided
// by the SCALE parameter set with set_scale

  serial.println("Readings:");
}

void loop() {
  serial.print("one reading:t");
  serial.print(scale.get_units(), 1);
  serial.print("t| average:t");
  serial.println(scale.get_units(10), 1);

  scale.power_down();         // put the ADC in sleep mode
  digitalWrite(PIN_GLED, LOW);
  delay(2000);
  digitalWrite(PIN_GLED, HIGH);
  scale.power_up();
}
After uploading, a few 100s bytes are still available (and lots of strings that can be trimmed):
Quote
Sketch uses 7,106 bytes (92%) of program storage space. Maximum is 7,680 bytes.
Global variables use 328 bytes of dynamic memory.
The HIDSerial monitor provides an output for now:
[attachment=0]
I haven't calibrated my load cell, this is just a quick check. If I push the load cell down, I get negative values, positive values if I pull the load cell up.

So far so good!

Re: Using a USBASP v2.0 as a cheap ATmega8 Arduino platform

Reply #5
Not much progress this week. I've simplified the scale program to experiment with the host side of things.

The new program lights up the G LED when the weight is greater than a hardcoded value. JP2 calls the tare routine. The weight value is sent 20 times / s (or thereabout) and the overflow and JP2 values are also sent in each packet. From the host, sending 't' or 'T' tares the balance.

Code: [Select]
#include <HX711.h>
#include <HIDSerial.h>

#define PIN_DOUT 1
#define PIN_SCK 0
#define PIN_RLED 14
#define PIN_GLED 15
#define PIN_SWITCH 16

HX711 scale(PIN_DOUT, PIN_SCK);      // parameter "gain" is ommited; the default value 128 is used by the library
HIDSerial serial;

struct packet {
  float value;
  uint8_t overflow;
  uint8_t pin;
};

typedef struct packet HIDPacket;

HIDPacket hidpacket;
size_t packetsize;
uint8_t *packetaddress;
uint8_t buffer[32];

void tare() {
  scale.tare();                    // reset the scale to 0
  digitalWrite(PIN_RLED, LOW);
  delay(200);
  digitalWrite(PIN_RLED, HIGH);
}

void setup() {
  pinMode(PIN_RLED, OUTPUT);
  pinMode(PIN_GLED, OUTPUT);
  pinMode(PIN_SWITCH, INPUT_PULLUP);
   
  packetsize = sizeof(hidpacket);
  packetaddress = (uint8_t *)(&hidpacket);

  serial.begin();
  scale.set_scale(2280.f);                      // this value is obtained by calibrating the scale with known weights; see the README for details
  tare();
}

void loop() { 
  serial.poll();
  if(serial.available()) {
    int size = serial.read(buffer);
    if (size!=0) {
      if (buffer[0] == 'T' || buffer[0] == 't') tare();
    }
  }

  hidpacket.value = scale.get_units(10); //average of 10 readings from the ADC
 
  if (hidpacket.value > 150 || hidpacket.value < -150) {
    digitalWrite(PIN_RLED, LOW);
    hidpacket.overflow = 1;
  } else {
    digitalWrite(PIN_RLED, HIGH);
    hidpacket.overflow = 0;
  }

  if (digitalRead(PIN_SWITCH) == LOW) {
    tare();
    hidpacket.pin = 1;
  } else {
    hidpacket.pin = 0;
  }

  //sending the data via HID serial
  serial.write(packetaddress,packetsize);

  //scale.power_down();                // put the ADC in sleep mode
  digitalWrite(PIN_GLED, LOW);
  delay(50);
  digitalWrite(PIN_GLED, HIGH);
  //scale.power_up();

}
I'm using a structure to pack the floating point value returned by HX711 (4 bytes), 1 byte for overflow and 1 byte for the status of JP3.

Work in progress on the HIDSerialMonitor (Processing project), I added a HEX mode but for some reason, I can't send data from the host to the client like in the original version...
[attachment=1]

On the Python side, here is my test code (windows only for now):
Code: [Select]
#http://stackoverflow.com/questions/12802401/simple-reading-writing-from-to-a-usb-hid-device-in-python
#http://stackoverflow.com/questions/16357756/how-to-send-hid-data-to-device-using-python-pywinusb

from pywinusb import hid
import time

def readData(data):
    print data
    #print len(data)
    return None

if __name__ == '__main__':
    filter = hid.HidDeviceFilter(vendor_id = 0x16c0, product_id = 0x05df)
    devices = filter.get_devices()

    if devices:
        hid_device = devices[0]
        print(hid_device)
    else:
        print "no device..."
        exit(0)

    hid_device.open()
    out_reports = hid_device.find_output_reports()
    in_reports = hid_device.find_input_reports()

    print "Number of output reports: %d" % len(out_reports)
    print "Number of input reports: %d" % len(in_reports)

    for i in range(10):
        print i
        hid_device.set_raw_data_handler(readData)
        time.sleep(500)

    hid_device.close()
For some reason, I'm receiving 9 bytes instead of 8... will need to sort this later. And here is the way I will convert data values 1-4 to a float (will do for now):
Code: [Select]
 np.fromstring(numpy.array(data[1:5],np.uint8).tostring(),dtype=np.float32)[0]
Also sending exactly 8 bytes (two floats for example) seems to send 16 bytes (last 8 zeros) instead of just 8 bytes. Not sure what's going on here either.

That's all for today!

Re: Using a USBASP v2.0 as a cheap ATmega8 Arduino platform

Reply #6
[quote author="JohnLittle"]Not much progress this week. I've simplified the scale program to experiment with the host side of things.

The new Wealthy Affiliate review lights up the G LED when the weight is greater than a hardcoded value. JP2 calls the tare routine. The weight value is sent 20 times / s (or thereabout) and the overflow and JP2 values are also sent in each packet. From the host, sending 't' or 'T' tares the balance.[/quote]

Awesome John, just read through the whole thread. Did you finish your project? Would be cool if you could post an update on how it went.

 

Re: Using a USBASP v2.0 as a cheap ATmega8 Arduino platform

Reply #7
I also love these cheap USBasp sticks for small projects.

I first put USBaspLoader or a variant. This is a small bootloader that you can have run on reset, or when a jumper is closed on reset, etc. This allows self-reflashing, and works with avrdude. Once reflashed it runs your new program. This way you can just leave your project plugged into USB the whole time, especially useful if itself is a USB device.

For serial debugging, I use the small two-pin jumper header for output, and do software-based serial (since that jumper doesn't have TXD, just one of the other I/O pins). This leaves the 10-pin header for full use by the project, and doesn't monopolize the hardware serial port in case the project wants it.