In this post I describe how I built a working program for an AVR directly in hex without using a C compiler or assembler. This is not directly useful, but it helps to understand how assembly instructions are represented and translated into binary.
This is a simple example program which sets PB5 (the LED on Arduino Pro Mini) to output and toggles it in an infinite loop.
ldi r16, 0x20 out DDRB, r16 // set PB5 to output loop: out PINB, r16 // toggle PB5 ldi r17, 0xff wait: dec r17 brne wait rjmp loop
translate to binary
The instruction encoding is defined in the AVR Instruction Set Manual and the register addresses you find in the register summary of the AVR’s datasheet.
To give an example, let’s look at the line
out DDRB, r16. The instruction is defined as follows:
Just take the 16bit opcode
1011 1AAr rrrr AAAA and insert
r = 0x10 (r16) and
A = 0x04 (DDRB), which gives
1011 1001 0000 0100 or
0xb904 in hex.
The whole program translated to binary:
asm bin hex ldi r16, 0x20 1110 0010 0000 0000 e200 out 0x04, r16 1011 1001 0000 0100 b904 out 0x03, r16 1011 1001 0000 0011 b903 ldi r17, 0xff 1110 1111 0001 1111 ef1f dec r17 1001 0101 0001 1010 951a brne -2 1111 0011 1111 0001 f7f1 rjmp -5 1100 1111 1111 1011 cffb
write a hexfile
For flashing with avrdude, the program needs to be in the intel HEX format.
:[Data Size] [Start Address] [Record Type] [Data] [Checksum]
:0e 0000 00 00e204b903b91fef1a95f1f3fbcf [Checksum]
(Note that instructions are stored in little endian byte order which means that the LSbyte comes first.)
At the end there is a 1 byte checksum which is simply the two’s complement of sum of all bytes (inclusive size, address, record type). Just calculate the sum (0x0e + 0x00 + 0x00 … = 0x7d8), reduce it to the least significant byte (0xd8) and apply the two’s complement, which gets you a checksum of 0x28.
With adding a terminating line with a record type ‘End Of File’ (0x01) you get the hexfile:
I flashed it on an Arduino Pro Mini (ATMega328) using a FTDI USB to serial adapter with avrdude.
avrdude -c arduino -P /dev/tty.MYFTDI -b 57600 -p atmega328p -D -U flash:w:MYPROGRAM.hex:i