Skip to main content

Arduino in Assembly (First Post)

What is this?

Hello! This is my first post for the foxgirl laboratory blog. We'll be going over different projects as I experiment with projects and learn how they work! I'm doing this purely for the science (and engineering) as I want to learn more how different aspects of the universe work. For those interested in who I am, I'm a trans woman who writes software for fun. I would like to be able to write software which I get paid for, so if any companies are hiring for that position, let me know if you'd like to hire me.

First, we'll set some rules for how this blog will work. This is NOT a copy/paste tutorial. Chances are likely, the copy/pasted code and designs will not work, or at the very least, won't work as it should. I'll be writing this as I learn, so mistakes will be left in, with corrections added and noted later on (possibly even in different chapters). I'll be writing in a mixture of freeform and structured writing. Also, I'll be uploading files I believe I have permission to use (either from copyleft licensing or fair use laws under the United States jurisdiction). For files which I'm not sure I can upload, I'll link to them instead.

I plan on focusing more on the hardware side of computing in the near future. Currently, I have a 6502 microprocessor and other parts which are similar to the parts used by Ben Eater's Hello 6502 tutorial.  The parts I have can be seen at this Mouser project link. If you haven't ordered from Mouser before, do note, they primarily sell to manufacturing companies, so Mouser will ask you what your company does as part of the Know Your Customer guidelines put in place by the US Export Administration Regulations. I told them that I was wanting to know more about how a computer works on a hardware level, will be following along with Ben Eater's 6502 tutorials, and will be posting about them on this site you are reading right now. They'll ask after you place your first order, so don't wait until Thursday morning to make the order, else you'll be waiting for far longer than 2 days before they start processing the order. Also, make sure you don't use the products for anything illegal like making weapons of mass destruction or anything else which would violate human rights.

In the future, I'll be looking into photonic circuits. Currently, I have no idea how to get a photonic chip.

When writing this blog, I'll be assuming you, the reader, have at least some experience with higher level languages (such as C), GNU/Linux, the shell, git, reading documentation, binary in different formats such as hexadecimal, and basic mathematics such as algebra.

Arduino

For this first post, we're going to program an Atmega2560 Arduino to blink the internal LED on/off every second. When asking for help with getting proof of life on my Arduino after flashing it with assembly, I was sent a link to this Atmega328P kit.

When starting off with this project, you'll want both an Arduino (based) Atmega2560 and a USBasp ISP cable. The firmware on the USBasp ISP cable is out of date, so it may have trouble flashing bigger projects, and we'll be looking into how the customers in the reviews flashed the updated firmware to the ISP cable in the future.

The ISP cable is required to flash assembly directly to the Arduino as the binaries we are creating will not have the Optiboot bootloader which the Arduino IDE tacks onto sketches (Arduino's programs).  The Arduino IDE assumes the Optiboot bootloader is already installed on the Arduino when it uploads sketches. If it isn't, like it won't be after flashing the blink program, then you'll need to use the IDE to flash the bootloader back to it using the ISP cable.

The Atmega2560 runs at a clock cycle of 16 MHz or 16,000,000 cycles per second. CPUs operate on cycles and each instruction takes a specific number of cycles to execute. The number of cycles is documented per instruction on the ISA datasheet. The Instruction Set Architecture or ISA is a description of how the code should work. It doesn't always work that way, hence the prevalence of Illegal Instructions on older processors. You can read more about Illegal Instructions on this reverse engineering blog.

Arduino Blinker

In order to compile the blink program, you'll need an AVR compatible assembler such as AVRA. I installed my copy of AVRA from the Arch User Repository or AUR.  AVRA is based off of the official Microchip AVR Assembler. The documentation can be found on Microchip's website. The Atmega2560 is 8 bit. You can find all sorts of documentation for the Atmega2560 on microchip's website. For flashing the binaries to the Arduino and also reading the binaries back, you'll need avrdude. You can find documentation for avrdude in the git repo. avrdude is also what the Arduino IDE needs to flash the bootloader back when you are done with this project.

When compiling the program, I use the command below to output both the hex file avrdude flashes as well as a list file which compares the binary opcodes to the assembly instructions. The AVR microprocessor is based on the RISC architecture.

avra blink.asm -o blink.hex -l blink.list

When flashing the program to the Arduino Mega 2560, I use the following command and specify the device is the Atmega2560, as well as specify the programmer uses USBasp, and specify the location of final output from the assembler. The hex format allows flashing bytes only where they need to be flashed instead of having to pad out the file to get the bytes in the correct positions.

avrdude -p atmega2560 -c USBasp -U flash:w:blink.hex

I'll be using ports to write to the internal LED pin. The Internal LED is on pin D13 (digital 13) of the Arduino 2560. Pin D13 is on Port B as can be seen on the Arduino Mega 2560 pinout datasheet. There's also a pinout datasheet on the Atmega2560 microprocessor itself. The text, PB7, which is attached to the D13 section of the datasheet specifies that the pin is on bit 7 of port B. Such that bit 7 means the highest bit of a byte which is mapped from 7 to 0. This would look like binary 10000000 on if bit 7 was the only pin set to output.

When using ports, we need to set all of the pins corresponding to that port at once, even if we don't plan on using them. When a bit is set to 1, it means output, and when set to 0, it means input. We set the pin modes by writing to data direction register B also known as DDRB. We can write to the pins by writing a value to port B or PORTB and we can read from the pins by reading from pin B or PINB.

We will be writing the below program in AVR assembly.

void setup() {
  // pinMode(LED_BUILTIN, OUTPUT);
  DDRB = 0b10000000;
}

void loop() {
  // digitalWrite(LED_BUILTIN, LOW);
  PORTB = 0b00000000;
  delay(1000);

  // digitalWrite(LED_BUILTIN, HIGH);
  PORTB = 0b10000000;
  delay(1000);
}

To be continued at a later date...