💭Understanding AVR Basics

Sources: 1

What is a register? "Registers are data storage devices that are more sophisticated than latches. A register is a group of binary cells suitable for holding binary information. A group of cascaded flip-flops used to store related bits of information is known as a register." Source

🤖Binary Operations in C

Sources: 1 2

  1. Bitwise AND &

    Any overlapping bits (bits that are 1 in both inputs) are output as 1 … everything else is 0.

    Ex. 0b11 & 0b01 = 0b01

  2. Bitwise OR |

    Any high bit in either of the inputs is output as 1 … everything else is 0.

    Ex. 0b10 & 0b01 = 0b11

  3. Bitwise NOT ~

    All bits are inverted. 0 becomes 1 and vice versa.

    ex. ~0b101 = 0b010

  4. XOR (exclusive or) ^

  5. Left Shift <<

    Shift the bits of the first operand over to the left by a number specified by the second operand.

    Ex. 0b00101 << 1 = 0b01010

  6. Right Shift >>

    Shift the bits of the first operand over to the right by a number specified by the second operand.

    Ex. 0b00101 >> 1 = 0b10010

Do the bits "wrap around" when you bitshift or are new bits just zeroed?

📌Input/Output

This was probably the biggest point of conceptual confusion when I was starting out. The technical words take on a different meaning from their coloquial usage.

Every physical IO "pin" — I'm using this word in quotes because it'll mean something different later — on the ATtiny has three features (three bits!) that the microcontroller keeps track of.

  1. The digital voltage value of the "pin" — a read-only input — PIN

  2. A value to potentially write outread/writePORT

  3. The direction of the input/output; whether this "pin" is receiving input or sending output — read/writeDDR

    • The direction of the 'pin' lets you toggle between the other two features.
    • If the "pin" is an input, then the first feature — the digital voltage value — is what the microcontroller needs to pay attention to.
    • If the "pin" is an output, then the second feature — the value to write out — is what is important.

I was confused by the terminology, so I think it is helpful to understand what each thing is doing before going giving them names. The first feature is called the PIN. The second feature is called the PORT. And the third is called the "Data Direction" (which is abbreviated to DDR, "Data Direction Register" ).

Any "pin" can be described by 3 bits of data. However these three bits are split up across different registers. Rather than have a single register for each "pin", there is a register for each featurePIN, PORT and DDR.

So rather than storing these values like 0b100, they are stored in three different registers: 0b10000000, 0b00000000 and 0b00000000, where the bit position in each register maps to information about the same "pin". 

Screen Shot 2019-10-19 at 1.35.51 PM

These are the relevant IO registers for the ATtiny.

The other source of confusion is that due to the memory constraints of the ATtiny, these feature registers —PIN, PORT and DDR — are themselves broken up into different registers. For example, on the ATtiny, there is are A and B registers for each of the features.

🤓 Understanding echo.c

Neil introduces a layer of abstraction that makes the code more readable but also obfuscates what is going on.

Let's look at some of the macros.

#define output(directions,pin) (directions |= pin) // set port direction for output
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin

|= is a bitwise inclusive OR assignment operator. It performs a bitwise or between the left and right operands and then assigns the result into the left.

Both set and output are doing the same thing. They take two 8 bits values, create a resulting 8 bit sequence where all of the positions have OR'd and then assign it into the first variable.

#define serial_port PORTA
#define serial_direction DDRA
#define serial_pins PINA
#define serial_pin_in (1 << PA0)
#define serial_pin_out (1 << PA1)
#define serial_interrupt (1 << PCIE0)
#define serial_interrupt_pin (1 << PCINT0)

These defines make much more sense when we understand the datatype of all the constants from LibAVR.

This helps explain what the macros above are doing. The code set(serial_port, serial_pin_out can be understood as something like 0b00000000 | 0b00001000 which equals 0b00001000.

🤫Interrupts

How do interrupts work? I'll probably have to look at the data sheet for figure out. For now, I will just continue to use the example code.

When the PCIE0 bit is set (one) and the I-bit in the Status Register (SREG) is set (one), pin change interrupt 0 is enabled. Any change on any enabled PCINT[7:0] pin will cause an interrupt. The corresponding interrupt of Pin Change Interrupt Request is executed from the PCI0 Interrupt Vector. PCINT[7:0] pins are enabled individually by the PCMSK0 Register.

 

GIMSK – General Interrupt Mask Register

Turns on tracking!

PCMSK registers which pin to track (PCINT)

 

💻 Writing my first AVR program in C

I want to make a program that:

  1. Uses interrupts to detect button presses.
  2. Turns an LED on when the button has been pressed
  3. Keeps the LED on until button is pressed again.

Seems simple enough...

Screen Shot 2019-10-18 at 5.27.01 PM

 

I think I wrote it.

The logic itself is very simple. I declared a global Boolean variable led_on. The code below runs when the button is pressed.

   led_on ~= led_on;
   led_port |= (led_on << led_pin_idx);
⚙️Compiling

https://github.com/osx-cross/homebrew-avr

  1. brew tap osx-cross/avr
  2. brew install avr-gcc

I copied the default make file and updated the PROJECT to the name of my C file.

I ran make and was met with the message make: *** No targets specified and no makefile found. Stop. Running make blink worked better.  But now I have a complier error: fatal error: 'avr/io.h' file not found. avr/io.h is in avr-libc.

https://askubuntu.com/questions/155088/fatal-error-avr-io-h-no-such-file-or-directory-compilation-terminated

avr-gcc -mmcu=attiny44 -Wall -Os -DF_CPU=20000000 -I./ -o blink.out blink.c This

avr-objcopy -O ihex blink.out blink.c.hex;\avr-size --mcu=$attiny44 --format=avr blink.out

avrdude -p t44 -P usb -c usbtiny -U flash:w:blink.c.hex

https://stackoverflow.com/questions/48291366/how-to-find-dev-name-of-usb-device-for-serial-reading-on-mac-os

ls -lha /dev/tty*

/dev/ttys000

system_profiler SPUSBDataType

avrdude -p t44 -P usb:020:041 -c usbtiny -U flash:w:blink.c.hex

🏃‍♂️ Running on my Board