Software

Now that we've built the kit for the digg button and also built the cable to the computer's parallel port, the next step is to install and use some free software to read the contents of the chip's memory, write modified contents back to the chip, and eventually compile new source code for the chip.

See ladyada's AVR Tutorial for more background on the chip itself. Important to note is that there are two types of memory in the chip which we're using here - the program code is held in the flash memory, and the runtime storage is held in the EEPROM memory. One might think that it should be the other way round, with the non-changing contents in EEPROM and the "RAM" using flash memory, but anyway.

According to the spec, our chip has the following capacity:

ATtiny2313V-10PU
2K Bytes of In-System Self-Programmable Flash, 128 Bytes In-System Programmable EEPROM

PonyProg for Windows

We start by following the instructions at ladyada.net, using a free, GPL'd (but described as 'beta') program called PonyProg. There are various downloads offered, both binary and source. First of all I tried the windows binary described as "v2.07c BETA". Inside this zip file is a setup.exe executable which requires root permissions to install.

Once you've got through the standard setup wizard installation process, there are three steps to configure the application so that it can talk to our chip via our cable. First of all it asks for "calibration" - to test the timings of the computer, which just takes a second or two. Secondly it needs "configuration" to set up the details of the interface. We need "Parallel" (not serial) of type "DT-006 I/O" as shown in ladyada's screenshot, and the appropriate parallel port (for me it is LPT1 and the others are not selectable). The final step is to set the chip type in the toolbar, the dropdowns look grey but they're not disabled - make sure the first one is set to "AVR micro" and the second to "Attiny2313" (the setting "AVR Auto" didn't work for me).

Ladyada's instructions are very detailed and include screenshots so I won't repeat all that here. Note that in PonyProg, the program code in the flash memory is shown with green hex codes, and the runtime storage in the EEPROM memory is shown with dark blue hex codes.

The easiest trick to do is just change the current value of the counter - this is held in the first two bytes of the EEPROM memory. All the rest of the EEPROM (the other 126 bytes) should be set to FF, as it is unused. You can check whether this value corresponds to what the board currently displays - just remember to convert from the hex value to normal decimal. Now you can enable the edit buffer in PonyProg, edit the value of this first byte (in the range 0-255) and then write the EEPROM data back to the chip. If the write is successful, the display should now show the new value of the counter, and will continue to count up from there. It's a disproportionate sense of excitement and achievement which comes from this simple result, there's something very cool about typing things into a PC and seeing the result on a home-assembled LED display!

If you want to set values greater than 255, what do you do? Use the second byte of course. If you set the second byte to 02 and the first byte to 03, then the counter value is 515 (2 * 256 + 3 * 1). Try this out too! This provides a sneaky opportunity to set the counter to 995 and then press the button a few times to roll over 999, just in case you didn't have the patience to try this out without a shortcut!

The next trick described by ladyada is to change the scrolling text displayed when you short the control pins. By default the text displayed is "digg", scrolling endlessly right to left. This text is stored in the program itself, so you'll find it in the flash part of the memory. You can overwrite this text, just keep to these four characters and don't overwrite the instructions on either side. (Actually you can use one of the spaces to the left of the 'digg' to make a five-letter message). Once you've edited it, you can write the buffer contents back to the flash memory on the chip with the "Write Program (FLASH)" command or the associated toolbar button. If this was successful, you can test it by shorting the control pins as before to see the new text.

PonyProg for Linux

The PonyProg program described above is also available for Linux, in both source and binary form. I tried the binary version "v2.06c BETA" which comes in a gzipped tar containing an executable ponyprog2000 in /usr/local/bin and an object file libVx.so.1.25 in /usr/local/lib. Obviously this needs root permissions to unpack the tar into these locations. After install the gui runs (with slightly unusual gui behaviour) and gets through the calibration and configuration ok. However, the option to choose the attiny2313 is missing from the toolbar dropdown, and all the other AVR options just give error messages when trying to read the chip, even when running with root permissions. This might be a very simple problem but I couldn't get it to connect.

Avrdude for Linux

avrdude is a command-line program dedicated to reading from and writing to AVR microcontrollers, and like PonyProg supports a wide range of chips and interfaces. This makes invocation a little clumsy however, and is not as friendly as PonyProg to use. It should be fairly straightforward to make a GUI frontend to avrdude (maybe C++/Qt?) but I haven't come across a suitable one yet. But a bonus is that it's already packaged for some Linux distributions, along with the other parts of the AVR toolchain, and immediately installed from the repositories with a simple command.

In anticipation of the other tools required, I added the following packages to Debian Etch:

avrdude           5.2-2             software for programming Atmel AVR microcontrollers
avrdude-doc       5.2-2             documentation for avrdude
binutils-avr      2.16.1-1          Binary utilities that support Atmel's AVR targets.
avr-libc          1.4.5-2           Standard C library for Atmel AVR development
gcc-avr           4.1.0.dfsg.1-1    The GNU C compiler (cross compiler for avr)

The avrdude packages are for the reading and writing, and the other three will be needed later for cross-compiling and building code.

With avrdude now installed, we can try it out using the terminal mode to read (or 'dump') the memory. For now these commands require root permissions, so use su in a console before executing avrdude. Firstly we'll try looking at the counter value in the EEPROM memory as before.

# avrdude -p t2313 -c dt006 -P /dev/parport0 -t

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e910a

avrdude> dump eeprom
>>> dump eeprom
0000  02 00 ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
0010  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
0020  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
0030  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|

avrdude> write eeprom 0000 18
>>> write eeprom 0000 18

avrdude> quit
>>> quit

avrdude: safemode: Fuses OK

avrdude done.  Thank you.

#

There are several parameters in this call to avrdude:

The dump command here just reads the first block of bytes from the EEPROM. You can also give a start address and number of bytes here to look at other parts of the memory, and giving flash as the memory type reads the flash memory instead of EEPROM.

The write command here writes a single byte back to the EEPROM, in this case a decimal value 18 into address 0000. Note that it doesn't read the whole memory contents and then write them all back again, it just writes a single byte to the chip. You can also do the same for address 0001 to set the higher byte of the counter value.

You should now have immediate success, and the new value of the counter should be displayed by the chip! Yay!


The next step is to try again to change the scrolling text. This is a bit more tricky with avrdude though, as although the interactive terminal mode can easily read the contents of the flash memory (in the same way as reading the EEPROM memory, just with dump flash), it is apparently unable to write to the flash in the same way. In any case, we're going to have to use a slightly different technique to modify the program code.

Firstly, let's read the contents of the EEPROM again but this time write it out to a file:

# avrdude -p t2313 -c dt006 -P /dev/parport0 -U eeprom:r:eepromcontents.data:r

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e910a
avrdude: reading eeprom memory:

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

avrdude: writing output file "eepromcontents.data"

avrdude: safemode: Fuses OK

avrdude done.  Thank you.

This command has the same parameters as before, plus two new ones:

This should create a new file in the current directory, 128 bytes long, containing the memory contents. Now let's load this binary file into a hex editor, in this case KHexEdit:

screenshot of KHexEdit

This screenshot shows the contents of the file in KHexEdit, similar to the display in PonyProg. The first two bytes hold the counter value (here 28), and the rest are unused. We can use KHexEdit to modify the contents of this file just by overtyping hex codes, and saving the result in a new file. (Of course you can use any hex editor for this, such as gnome's hex editor GHex).


Then we can use avrdude to upload the result back into the chip.

# avrdude -p t2313 -c dt006 -P /dev/parport0 -U eeprom:w:eepromcontents.mod.data:r

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e910a
avrdude: reading input file "eepromcontents.mod.data"
avrdude: writing eeprom (128 bytes):

Writing | ################################################## | 100% 0.03s

avrdude: 128 bytes of eeprom written
avrdude: verifying eeprom memory against eepromcontents.mod.data:
avrdude: load data eeprom data from input file eepromcontents.mod.data:
avrdude: input file eepromcontents.mod.data contains 128 bytes
avrdude: reading on-chip eeprom data:

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

avrdude: verifying ...
avrdude: 128 bytes of eeprom verified

avrdude: safemode: Fuses OK

avrdude done.  Thank you.

This write command is almost identical to the earlier one for reading, except that we use a w for writing, instead of an r for reading. So this command takes the modified file (in raw binary format) and writes it to the chip.

So far this doesn't do anything new, it just updates the counter as we did earlier from terminal mode. However, this technique of downloading a file, editing the file in KHexEdit, and then uploading the modified file, works in exactly the same way for flash data too. So by doing the same thing for flash memory type to the file flashcontents.data, we can use KHexEdit to change the "digg" text to some other four- or five-letter string, and writing the modified code back to the chip.


screenshot of KHexEdit

This screenshot shows part of the flash memory contents in KHexEdit, with the "digg" text on the last line. By overwriting this text and writing the modified binary file back to the chip, we can change the scrolling text displayed by the board.

Hex files

So far the files we've read and written with avrdude have been in raw binary format. But there is an alternative file format called "Intel Hex format", which is popular for storing such files and often has the file suffix ".hex". In fact, this is how the digg button firmware is released on ladyada's download page. It has the advantage over raw binaries in that it includes checksums to make sure everything is ok and the file hasn't been corrupted along the way.

See the wikipedia article Intel Hex for more information about the format. Note that despite the name it's not specific to Intel processors and actually just consists of ASCII text. Because of this and due to the checksums, the .hex files are more than double the size of the raw binary files.

We can try to restore the original firmware just by writing the hex file back to the chip:

# avrdude -p t2313 -c dt006 -P /dev/parport0 -U flash:w:digg.hex:i

This time we use the file digg.hex from ladyada and specify intel hex format ("i"). The file should be written to the chip and verified as before, and the default settings should be restored.

We can also try to edit this hex file to see if we can change the scrolling text in a similar way. Firstly we must understand that the digg.hex file is in ASCII format, so two bytes of this file represent one byte of output. Therefore we open the file in a normal editor (like gedit or kate) instead of a hex editor.

:10071000012C0AD011240895E199FECFBFBBAEBBD6
:10072000E09A11960DB20895E199FECFBFBBAEBB22
:100730000DBA11960FB6F894E29AE19A0FBE089599
:0A0740002020206469676700600054
:00000001FF

This is the end of the original digg.hex file, with the highlighted section showing the "digg" text. Each pair of characters give the ascii code for the text, so 64 represents the d, 69 represents the i, and so on.

We can edit this file with a normal editor, giving an alternative text (eg "61626364 for "abcd"). However, when we try to write the modified text file to the chip, it fails with a checksum error. The checksum at the end of the line no longer matches the data. Handy for seeing if a received file is uncorrupted, not so handy for us with our deliberately modified file. Fortunately, avrdude explains what the checksum error means, giving both what it expected based on the data, and what it received from the checksum characters. So it's quite easy to edit the file once again, changing the checksum characters at the end of that line to the expected checksum. And this time the write attempt should succeed.

We can also now understand how the hex file fits into the chip - we saw that this attiny2313 has only 2k of program memory, yet the digg.hex file is over 5k. The answer is in this hex format, where the file size is doubled by the ASCII format. The actual raw binary read from the chip earlier is less than 2k.

Note that if you get a strange error saying avrdude: ERROR: address 0x0090 out of range at line 9 of digg.hex, then it probably means you're trying to write to the wrong kind of memory. Make sure you're specifying "flash" when writing the program file.

Compiling from source

So now we can not only read and write the memory contents, we can also manually edit the .hex file and write it to the chip. The next stage is to download the source code for the firmware from ladyada's download page and compile it to produce a new hex file.

After unpacking the zip file, the source code including Makefile is all there, and it should take just a simple make command to compile the code and produce a new hex file. It might be a good idea to rename the original digg.hex file so it doesn't get overwritten.

Then we try to write the hex file back to the chip, and that's done in exactly the same way as before with the i option. So now we can transfer our compiled source code into the chip.

Finally we modify the main source file main.c and change the relevant line to again modify the scrolling text. This way we can show that we're really compiling the code.

char *display_string = "  bingo";

After recompiling and rewriting to the chip, the new code should be running successfully, including the new message. Now we can go through the source code again, analysing how it works and looking for ways it could be modified for additional functionality.

Building the kit // Parallel cable // Software