aboutsummaryrefslogtreecommitdiffstats

AVR assembly programming

This is a repo containing my attempts at programming in AVR assembly

I want the every byte of macihne code executed by my processor to be written by myself, so no libraries, no definitions, no nothing.

DISCLAIMER

Please have a sense of humor and don't take the jokes in this README seriously.

WARNING

ChatGPT and any other genAI, as of 2025-09-05, can NOT write proper AVR assembly. And I doubt they'll learn any time soon. Try it for yourself, maybe you'll get something working if they write it completely from scratch, but as for debugging, you are on your own. Use debugging tools mentioned below.

Examples of generative AI being completely useless include: them trying to persuade me that I've used the wrong interrupt vector address, mixing up out/sts and in/lds instructions, mixing up addresses of IO registers, writing/reading data from wrong registers (like mixing up TIMSK/TIFR, PINx/PORTx), not knowing how to actually compile the code and so much more, not unserstanding how timers work and so on. Save yourself some time, don't use genAI.

How can I use it?

Firstly, as an example of how to program in assembly for AVR. I am not responsible for the quality though :silly:. My only source is datasheets.

Secondly, there is a really useful Makefile that you can copy to use with your own projects. Most variables do not need to be changed there, maybe just the MCUPATH. Name a file something.s, and then run make TARGET=something to build, or make TARGET=something flash to upload your code to the arduino. You can set the TARGET as an environment variable to aviod typing it in each invokation of make.

Thirdly, for debugging. Run make TARGET=something sim, then run avr-gdb something, when inside of it, type target remote :1234 and you're good to go. make sim automatically detects wheher the simulation is already running and forks to background, so to rerun the simulation, just type make sim again: it will rebuild the file, and you won't even have to restart gdb (it will preserve breakpoints), just retype the target remote :1234 command. I find this workflow satisfying, and it does not exhaust my arduino flash memory by flashing the program every 30 seconds there. I think I will add a debugging guide as well...

Dependencies

Software

  • make
  • avr toolchain (avr-as, avr-ld, avr-objcopy, avr-objdump)
  • avrdude (flash tool)
  • For debugging: avr-gdb + simavr (or qemu-system-avr, but I had problems with it)

Not that you don't actually need avr-libc or avr-gcc to build assembly.

Hardware

  • an ARDUINO UNO board, or any other AVR-based microcontroller if you change the variables in Makefile. Note that most of the variables can be changed from the environment.
  • wirez
  • rizz

Dependency installation

  • Arch linux: # pacman -S avr-binutils avrdude. For C development, you also need to install avr-gcc and avr-libc. For debugging, avr-gdb and simavr [AUR] [CLONE]
  • Any other non-superior distro: read the fucking manual

Why?

  • to have fun.

Useful resources

Read this if you are going into it blind

This section contains some of the pain that I've gone through while doing this programming journey. If you don't want to make same mistakes, please take your time to read it.

  1. AVR interrupt addresses from datasheet are not the same ones you specify in assembly!
    For example, TIMER1 COMPA (timer 1 compare A match) has address 0x0016 in the datasheet, but in assembly you have to align it like this: asm .org 0x002C: jmp timer1_int Why? Because they probably refer to "instruction address", not to "memory address". Is it said anywhere? No. Can you figure it out by compiling corresponding C code and looking at disassembly? Yes, but you will spend 5 hours trying to understand why your interrupt is not working.
  2. Don't forget to link your file after compiling!
    This would have not been a problem on a processor that has an OS, because the file just wouldn't run unless you link it. But here you're using objcopy. That means that ALL jumps and calls will be broken in your assembly. I thought that this was a bug for so long, dont be like me.
  3. I've said this before, but don't ever try to use AI, or even worse, vibe code the microcontroller. It's just not going to work, you will loose time instead of saving it. You can vibecode a crappy website in react only because there is so much training data for it. But almost entirety of AVR programming is done in C++, thanks to fucking nobody. But I mean, it is a good thing that AI can't comprehend assembly. It means you'll have more fun exploring the old fashined way ;)
  4. I will add entries to this list as I go...