This project consists of notes and examples that I worked on while learning AVR assembly language programming for the first time.
Most or all of the examples assume use of the atmega168p. I
haven't used any headers for constants (which forces me to
really understand where these values come from) so these programs
will require adaptation to use with other AVR chips. The mods
required should be minor, though.
I've used a breadboard set up as per the example on page 56 of Make: AVR Programming by Elliot Williams.
Download the source code for avra from Github:
git@github.com:Ro5bert/avra.git
To build avra from scratch:
# cd into the root directory and run:
makeTo check the device/programmer are working, run the command below (adjust for your programmer and chip):
avrdude -c usbasp -p m168
-c programmer type
-p AVR part/device
If you call avrdude -c without the part, it will give you
a list of available AVR device strings to choose from.
Note, my chips that look like m168p read as m168. Shrug?
You can check the fuse settings like:
avrdude -c usbasp -v -p m168
I noticed that it won't output information about the fuses if it thinks that the chip is wrong, however.
To build using avra is trivial:
avra filename.asm
avrdude -c usbasp -p m168 -U flash:w:hello.hex
You may also want to set the bitrate:
-b 57600
Obviously, change these settings however it makes sense for your particular setup.
I noticed that the AVR chips can be a bit sensitive about VCC while being programmed, and that power via USB / programmer isn't always reliable. If something isn't working, try using a real power supply.
AVR I/O registers are 64 bytes in data memory just after the 32
general working registers (0x20 - 0x5F). They include the PORT,
PIN, and DDR registers that control the m/c's pins.
Note that the Status Register (SREG) is one of the I/O registers.
AVR assembly language has instructions just for dealing with the I/O registers:
in In from I/O location
out Out from I/O location
cbi Clear a bit in an I/O register (first 32 registers)
sbi Set a bit in an I/O register (first 32 registers)
sbic Skip if bit in I/O register is 0
sbis Skip if bit in I/O register is 1
cbi and sbi only work with the first 32 I/O registers. All
PORT, PIN and DDR registers are in the first 32 memory locations.
c/sbi are useful for setting output to pins.
cbi and sbi use a pin number and not a mask, so you can only
set one pin at a time. in/out may be more efficient.
sbis/sbic can skip the next instruction based on a bit in an
I/O register, so you can use this to check the state of a pin.
Examples:
in r15, DDRB ; load DDRB to r15
out DDRB, r0 ; load r0 to DDRBThere are Data Memory addresses, and there are I/O addresses. I/O addresses are mapped to data memory addresses, in order to be able to more efficiently access (some) I/O addresses.
Data memory address 0x20 maps to I/O 0x00.
You can see how this is useful: by renumbering the I/O addresses, it allows access to the first 32 in 5 bits.
Extended I/O and SRAM allow for direct access using the lds and
sts instructions. Because these addresses are out of the range
of the first 32 I/O registers, we can't use in or out with
them. sts/lds work with the general purpose registers and up
to 64K of memory. Prefer to use these with r16-r31, it's more
efficient.
(Random and incomplete)
ldi rd, imm
Loads an 8-bit number (0-255) into an upper half register (16-31)
out rd, r
Copies a number from a working register to an I/O register.
rjmp label
Jumps to the label. The label cannot be more than 204 instructions away. This is a "relative" jump.
