Week 08: Embedded Programming

compare the performance and development workflows for other architectures

Read a microcontroller data sheet. Program your board to do something, with as many different programming languages and programming environments as possible.

Learning outcomes:

Have you:

Source: Fab Academy Assessment - Embedded Programming


My Process

Background

I have a little bit of experience with programming in C, playing with Arduinos, etc. but this will largely be new for me.

Getting Started

I started where I left off in Week 06. I had already programmed my Hello board with a simple blink pattern sketch using the Arduino IDE. See Week 06 - Programming the Board to examine my code. Basically, this program has a set of pre-programmed blink patterns, and each time you push the button, it changes to the next one.

I wanted to update this code with a couple of improvements. Mainly, I wanted to improve the User Interface. The code above requires the user to press the button at the end of a blink cycle. Because the blink patterns are all implemented witht the delay() function, the only time when the board is able to read the button push is at the end of a pattern cycle. This proved particularly troublesome for the end of the longer patterns, such as S.O.S. I wanted users to be able to push the button at any time to advance the blink pattern. So I got to work.

Programming with Arduino IDE

I found this tutorial particularly helpful, and basically followed it to burn my bootloader and get started programming my board. Here's my basic reproduction of those steps.

FabISP board and Hello Board connected FabISP (green box) connected to computer via USB cable and connected to Hello FTDI board (blue box) via 6-pin header cable

I downloaded and booted the Arduino IDE and followed the tutorial linked above to load in the ATtiny microcontroller board files.

Arduino IDE - selecting ATtiny board Using Arduino IDE to select ATtiny24/44/84 board

Arduino IDE - selecting ATtiny44 Selecting ATtiny44

Arduino IDE - selecting 20 MHz Selecting external 20 MHz clock

These preceding steps allow the Arduino IDE to correctly set the fuses for the ATtiny44 using a 20 MHz external clock.

Arduino IDE - selecting USBtiny programmer Selecting USBtinyISP from the Tools > Programmer menu

The FabISP is recognized by the Arduino IDE as USBtinyISP, so select that from the Tools > Programmer menu. You are now ready to burn the bootloader onto the target board. Select Tools > Burn Bootloader. If all goes well it will give you a "Bootloader Burned Successfully" message. NB: I first tried to use an Arduino Uno setup as an ArduinoISP and had no luck - it couldn't find my target board. It worked like a charm with the FabISP though.

I had already gotten my blink pattern program working using the delay() function, so now my challenge was to implement "Blink without delay" for each of my blink patterns. I built it up slowly starting with a simple program that just blinked the green LED on and off based on the Arduino Blink Without Delay sketch. I adapted this for my own pin number (pin 7 is connected to my green LED).

/*
Blink without Delay

Modified from Arduino Example Code from:
http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
*/

// constants won't change. They're used here to set pin numbers:
const int buttonPin = 3;    // the number of the pushbutton pin
const int redPin =  8;      // the number of the red LED pin
const int greenPin = 7;     // the number of the green LED pin

const long longInterval = 1000;    // long interval at which to blink (milliseconds)
const long shortInterval = 100;    // short interval at which to blink (milliseconds)

// variables will change:
int redState = LOW;         // redState used to set the red LED
int greenState = LOW;       // greenState used to set the red LED

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time LED was updated
unsigned long currentMillis = 0;        // will store the current time

// the setup function runs once when you power the board
void setup() {
  // initialize digital greenPin as an output.
  pinMode(greenPin, OUTPUT);
}

void loop() {
  
  currentMillis = millis();

  if (currentMillis - previousMillis > longInterval){
    previousMillis = currentMillis;
    if (greenState == LOW)
      greenState = HIGH;
    else
      greenState = LOW;
  }

  digitalWrite(greenPin, greenState);
  
}
    

Then I wanted to make sure I could read the button push, so I wrote a quick sketch to alternate which LED is lit via button push.

/*
  Blink back and forth on button press
  
  Modified from Arduino Example Code from:
  http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
*/

// constants won't change. They're used here to set pin numbers:
const int buttonPin = 3;    // the number of the pushbutton pin
const int redPin =  8;      // the number of the red LED pin
const int greenPin = 7;     // the number of the green LED pin

// variables will change:
int redState = LOW;         // redState used to set the red LED
int greenState = LOW;       // greenState used to set the red LED
int buttonState = 0;        // var to hold buttonState

// the setup function runs once when you power the board
void setup() {
  // initialize digital pins 7 & 8 as an output.
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  //initialize digital pin 3 as input.
  pinMode(buttonPin, INPUT);
}

void loop() {

  buttonState = digitalRead(buttonPin);

  if (buttonState == LOW){
    delay(100);   //allows user time to let go of button
    if (greenState == LOW){
      greenState = HIGH;
      redState = LOW;
    }
    else {
      greenState = LOW;
      redState = HIGH;
    }
  }

  digitalWrite(greenPin, greenState);
  digitalWrite(redPin, redState);
}
    

It worked pretty well:

Now that my button input was working, and my "blink w/o delay" was working, I wanted to put them together and rewrite my sketch from Week 06 - Programming to run without the delay() function, allowing a button press to be read by the board at essentially any time. I built and tested each blink function individually, and eventually put together this sketch:

/*
  Blink Pattern without Delay
  
  Heavily Modified from Arduino Example Code from:
  http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
*/

// constants won't change. They're used here to set pin numbers:
const int buttonPin = 3;    // the number of the pushbutton pin
const int redPin =  8;      // the number of the red LED pin
const int greenPin = 7;     // the number of the green LED pin

const long long_interval = 1000;    // long interval at which to blink (milliseconds)
const long short_interval = 100;    // short interval at which to blink (milliseconds)
const long micro_interval = 50;     // very short interval at which to blink (ms)

// variables will change:
int buttonState = 0;        // variable for reading the pushbutton status
int blinkNum = 0;           // variable to store the current blink pattern
int redState = LOW;         // redState used to set the red LED
int greenState = LOW;       // greenState used to set the red LED
int counter = 0;            // a counter variable for blinkN()
int sosCounter = 0;         // a counter var for sos()

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time LED was updated
unsigned long currentMillis = 0;        // will store the current time
long timer = 0;                         // for incrementing the delay speed
unsigned long default_timer = 1000;     // stores default timer value
unsigned long decrement = 100;          // stores the timer decrement value

// the setup function runs once when you power the board
void setup() {
  // initialize digital pins 7 & 8 as an output.
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  //initialize digital pin 3 as input.
  pinMode(buttonPin, INPUT);
}

//turns both LEDs off
void bothOff(){
  greenState = LOW;
  redState = LOW;
  
  digitalWrite(greenPin, greenState);
  digitalWrite(redPin, redState);
}

//turns both LEDs on
void bothOn(){
  greenState = HIGH;
  redState = HIGH;
  
  digitalWrite(greenPin, greenState);
  digitalWrite(redPin, redState);
}

//blinks both LEDs together with interval t
void blinkTogether(long t){
  
  if (t <= 0){     // if given a negative or zero interval, turn off both LEDs and end the function call
    bothOff();
    return;
  }

  currentMillis = millis();

  if (currentMillis - previousMillis >= t) {
    previousMillis = currentMillis;

    if (redState == LOW)
      bothOn();
    else
      bothOff();
  }

  return;
  
}

//alternates the Red and Green LEDs with a time interval of t
void alternate(long t){
  
  if (t <= 0){     // if given a negative or zero interval, turn off both LEDs and end the function call
    bothOff();
    return;
  }
  
  // check to see if it's time to blink the LED; that is, if the difference
  // between the current time and last time you blinked the LED is bigger than
  // the interval at which you want to blink the LED.
  currentMillis = millis();

  if (currentMillis - previousMillis >= t) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the red LED is off turn it on and vice-versa:
    if (redState == LOW) {
      redState = HIGH;
      greenState = LOW;
    } else {
      redState = LOW;
      greenState = HIGH;
    }

    // set the LEDs with the states:
    digitalWrite(redPin, redState);
    digitalWrite(greenPin, greenState);
  }
}

// blinks green n times for t time and then blinks red once for t time
void blinkN(int n, int t){
  if (n <= 0){     // if given a negative or zero interval, turn off both LEDs and end the function call
    bothOff();
    return;
  }

  currentMillis = millis();


  //check if it's time to change the blink state
  if (currentMillis - previousMillis >= t){
    previousMillis = currentMillis;
    
    //check if it's time to blink green or red, after blinking increment counter
    if (counter < n){
      if (greenState == LOW){
        greenState = HIGH;
        redState = LOW;
        counter++;
      }
      else{
        greenState = LOW;
        redState = LOW;
      }
    }
    else{
      if (greenState == HIGH && redState == LOW){
        greenState = LOW;
        redState = LOW;
      }
      else if (greenState == LOW && redState == LOW){
        greenState = LOW;
        redState = HIGH;
      }
      else{
        greenState = LOW;
        redState = LOW;
        counter = 0;
      }
    }
  }

  digitalWrite(greenPin, greenState);
  digitalWrite(redPin, redState);
  
}


void sos(){
  int s = 125;  //short blink interval for s
  int l = 333;  //long blink interval for o
  
  currentMillis = millis();

  //if sosCounter is 0, 1, 2 || 6, 7, 8
  if ((sosCounter >= 0 && sosCounter <= 2) || (sosCounter >= 6 && sosCounter <=8)){
    if (currentMillis - previousMillis >= s){
      previousMillis = currentMillis;
      if (greenState == LOW){
        greenState = HIGH;
        redState = LOW;
      }
      else{
        greenState = LOW;
        redState = LOW;
        sosCounter++;
      }
    }
  }
  else if (sosCounter >= 3 && sosCounter <= 5){
    if (currentMillis - previousMillis >= l){
      previousMillis = currentMillis;
      if (redState == LOW){
        redState = HIGH;
        greenState = LOW;
      }
      else{
        redState = LOW;
        greenState = LOW;
        sosCounter++; 
      }
    }
  }
  else{
    if (currentMillis - previousMillis >= 2*l){
      previousMillis = currentMillis;
      sosCounter = 0;
    }
  }

  digitalWrite(greenPin, greenState);
  digitalWrite(redPin, redState);
}


// function to call blink functions dependent on blinkNum
void blinkPattern(int n){
  switch (n){
    case 0:
      bothOff();
      break;
    case 1:
      bothOn();
      break;
    case 2:
      blinkTogether(long_interval);
      break;
    case 3:
      blinkTogether(short_interval);
      break;
    case 4:
      blinkTogether(micro_interval);
      break;
    case 5: 
      alternate(long_interval);
      break;
    case 6:
      alternate(short_interval);
      break;
    case 7:
      alternate(micro_interval);
      break;
    case 8:
      blinkN(2, 200);
      break;
    case 9:
      blinkN(3, 150);
      break;
    case 10:
      sos();
      break;
    default:
      bothOff();
      blinkNum = 0;
  }
}

void loop() {
  //read the state of the pushbutton value
  buttonState = digitalRead(buttonPin);
  
  //check if the pushbutton is pressed, if it is, increment blinkNum by 1
  if (buttonState == LOW){
    bothOff();      //turn off both LEDs
    delay(250);     // delay allows user to push button for up to 250ms and release
    if (blinkNum < 10){
      blinkNum++;
    }  
    else
      blinkNum = 0; 
  }

  blinkPattern(blinkNum);
  
}
    

Again, I'm pretty happy with how it works:

As a summary, there are 11 patterns that can be cycled through:

  1. Both Off
  2. Both On
  3. Blink together (slow)
  4. Blink together (medium)
  5. Blink together (fast)
  6. Alternate (slow)
  7. Alternate (medium)
  8. Alternate (fast)
  9. 2 green, 1 red
  10. 3 green, 1 red
  11. S.O.S. (...---...)

Each push of the button advances to the next pattern, and at the end cycles back to 0 (off).

Programming with C

Fairly happy with how programming via Arduino IDE went, I decided to try interfacing with the chip on a lower level, and writing C directly for the board. I decided to start with the FabAcademy Tutorials for this week.

I started by downloading the hello.ftdi.44.echo.c file and the corresponding Makefile. I plugged in my FabISP and connected my target board (as seen above) and navigated to the folder I downloaded the .c and Makefile into. I ran the command make program-usbtiny and got the following output:

$ make program-usbtiny
avr-gcc -mmcu=attiny44 -Wall -Os -DF_CPU=20000000 -I./ -o hello.ftdi.44.echo.out hello.ftdi.44.echo.c
avr-objcopy -O ihex hello.ftdi.44.echo.out hello.ftdi.44.echo.c.hex;\
	avr-size --mcu=attiny44 --format=avr hello.ftdi.44.echo.out
AVR Memory Usage
----------------
Device: attiny44

Program:     758 bytes (18.5% Full)
(.text + .data + .bootloader)

Data:         64 bytes (25.0% Full)
(.data + .bss + .noinit)


avrdude -p t44 -P usb -c usbtiny -U flash:w:hello.ftdi.44.echo.c.hex

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e9207
avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "hello.ftdi.44.echo.c.hex"
avrdude: input file hello.ftdi.44.echo.c.hex auto detected as Intel Hex
avrdude: writing flash (758 bytes):

Writing | ################################################## | 100% 0.72s

avrdude: 758 bytes of flash written
avrdude: verifying flash memory against hello.ftdi.44.echo.c.hex:
avrdude: load data flash data from input file hello.ftdi.44.echo.c.hex:
avrdude: input file hello.ftdi.44.echo.c.hex auto detected as Intel Hex
avrdude: input file hello.ftdi.44.echo.c.hex contains 758 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.83s

avrdude: verifying ...
avrdude: 758 bytes of flash verified

avrdude: safemode: Fuses OK (H:FF, E:DF, L:FE)

avrdude done.  Thank you.
    

I was thrilled that this seemed to program the board successfully. Next I wanted to see it in action, so I followed the steps in this tutorial to start talking with the board over serial input. I booted up the Arduino IDE and tried to select Tools > Serial Monitor but it gave me an error: Board at /dev/cu.usbmodem1421 is not available . I realized I probably needed to connect to my board via an FTDI cable. I didn't have an FTDI cable, but I decided to try this Instructable tutorial to setup an Arduino UNO as an FTDI cable.

The wire colors in the Instructable images were a little different from my wire colors - here's a translation:

Instructable	|	Function	|	My Color
============	|	========	|	========
WHITE		|	rts		|	BROWN
YELLOW		|	tx		|	RED
ORANGE		|	rx		|	ORANGE
RED		|	vcc (5v)	|	YELLOW
BLACK		|	gnd		|	GREEN
unassigned	|	gnd		|	BLUE

Arduino connected to target board as FTDI Hooking up my Arduino as an FTDI to talk to the Hello board

Next, I realized I had to pop out the Atmega328p MCU in the Arduino. Luckily I have the DIP version and I could just pop it out with a small screwdriver

removing the MCU with screwdriver I pried the MCU from the Arduino using a small screwdriver

This should allow the built-in FTDI feature on the Arduino UNO to talk directly to the ATtiny44 on the Hello board.

This time, in the Arduino IDE I selected Tools > Serial Monitor and established a viable serial connection. I set the baud rate to 152000 (as per the tutorial), and got the output: ch.c[7F˃+#&". Not sure what that means, I started sending characters. I sent "a" and got back: hello.ftdi.44.echo.c: you typed "⸮". Not promising. I tried "b" and "c" to no avail.

error outputs from serial connection All the characters I tried to send echoed back as "⸮"

I tried numerals, punctuation marks, special characters, and always got back "⸮". The only character that I could send and get back correctly was "⸮" - and something told me that one wasn't actually working either ;¬D. On to try some debugging.

I wanted to see if I could write a simple sketch in Arduino and push it to the ATtiny44 (via the Arduino FTDI setup). It didn't work because in order to program the ATtiny44, the IDE tried to look for the USBtinyISP to program it with. Instead I wanted to just upload it directly with the IDE over the FTDI connection, but my hunch is that I would need to make a new board definition to make this connection work, and that's beyond my current skill. (I tried selecting Arduino/Genuino UNO as from the Tools > Boards menu, but I got a bunch of errors: avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x69. I assume this means that it can't sync up to upload the sketch because it's trying to talk to the Atmega328p MCU, which is disconnected and laying on my living room table.

Though I wasn't able to program my ATtiny44 over the FTDI setup, I did discover something else interesting here. When I selected Tools > Boards > Arduino/Genuino UNO for my board, I could then run the serial monitor, and get a different result.

different outputs from hello echo The board echoed back differently if I selected Arduino UNO as my board

This time the board would echo back a multi-character string which included my previous character inputs. For example, if I entered "I want to test the board" one character at a time, this is the output I would get back:

hello.ftdi.44.echo.c: you typed "I                       "
hello.ftdi.44.echo.c: you typed "I                       "
hello.ftdi.44.echo.c: you typed "I w                     "
hello.ftdi.44.echo.c: you typed "I wa                    "
hello.ftdi.44.echo.c: you typed "I wan                   "
hello.ftdi.44.echo.c: you typed "I want                  "
hello.ftdi.44.echo.c: you typed "I want                  "
hello.ftdi.44.echo.c: you typed "I want t                "
hello.ftdi.44.echo.c: you typed "I want to               "
hello.ftdi.44.echo.c: you typed "I want to               "
hello.ftdi.44.echo.c: you typed "I want to t             "
hello.ftdi.44.echo.c: you typed "I want to te            "
hello.ftdi.44.echo.c: you typed "I want to tes           "
hello.ftdi.44.echo.c: you typed "I want to test          "
hello.ftdi.44.echo.c: you typed "I want to test          "
hello.ftdi.44.echo.c: you typed "I want to test t        "
hello.ftdi.44.echo.c: you typed "I want to test th       "
hello.ftdi.44.echo.c: you typed "I want to test the      "
hello.ftdi.44.echo.c: you typed "I want to test the      "
hello.ftdi.44.echo.c: you typed "I want to test the b    "
hello.ftdi.44.echo.c: you typed "I want to test the bo   "
hello.ftdi.44.echo.c: you typed "I want to test the boa  "
hello.ftdi.44.echo.c: you typed "I want to test the boar "
hello.ftdi.44.echo.c: you typed "I want to test the board"

I also noticed that this pattern would wrap after 24 characters (see photos below).

outputs showing wrapping The character string would wrap after 24 characters

outputs showing further wrapping

This is some odd behavior, but my hunch is that this may be a problem in the C code. My challenge now is that I basically don't understand the C code well enough to debug it.

LOL. I just found this line in the tutorial which indicates that the code is working perfectly:

The characters you have typed so far are stored and echoed back along with the new character that you typed.

Guess I don't have to debug!

I'd still like to write a simple blink script in C code to teach myself how to write C for the microcontroller. It's quite different from writing within the Arduino IDE with the full suite of Arduino libraries and functions.

Writing my Own C

In order to explore writing more directly in C at a lower level, without the help of the Arduino libraries, I looked for tutorials for a simple blink sketch. I found one on youtube and went with it. This very simple program will blink my red LED every 500ms:

// simple program to blink an LED on the hello board
// using ATtiny44
//
// adapted from: https://www.youtube.com/watch?v=SxJZGqToqu4
//
// red pin is   PB2


#include <avr/io.h>
//define F_CPU 1000000UL // 1 MHz - I don't think I need to include this

#include <util/delay.h>


int main(void){
        DDRB |= (1<<DDB2); //make PB2 output

        while(1){
                PINB = (1<<PINB2);      //bit shift pin b2
                _delay_ms(500);
        }
}
    

Note: HTML doesn't seem to like when my code includes << even within the <pre> tag. Something to watch out for when pasting code... View page source here if you are confused about what I mean.

I saved this program as simpleBlink.c and made a new Makefile which set "simpleBlink" as the $PROJECT variable. I then hooked up my board, and entered make program-usbtiny and got the following output:

$ make program-usbtiny
avr-gcc -mmcu=attiny44 -Wall -Os -DF_CPU=20000000 -I./ -o simpleBlink.out simpleBlink.c
avr-objcopy -O ihex simpleBlink.out simpleBlink.c.hex;\
	avr-size --mcu=attiny44 --format=avr simpleBlink.out
AVR Memory Usage
----------------
Device: attiny44

Program:      82 bytes (2.0% Full)
(.text + .data + .bootloader)

Data:          0 bytes (0.0% Full)
(.data + .bss + .noinit)


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

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e9207
avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "simpleBlink.c.hex"
avrdude: input file simpleBlink.c.hex auto detected as Intel Hex
avrdude: writing flash (82 bytes):

Writing | ################################################## | 100% 0.12s

avrdude: 82 bytes of flash written
avrdude: verifying flash memory against simpleBlink.c.hex:
avrdude: load data flash data from input file simpleBlink.c.hex:
avrdude: input file simpleBlink.c.hex auto detected as Intel Hex
avrdude: input file simpleBlink.c.hex contains 82 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.13s

avrdude: verifying ...
avrdude: 82 bytes of flash verified

avrdude: safemode: Fuses OK (H:FF, E:DF, L:FE)

avrdude done.  Thank you.

Success! My board was simply blinking the red LED on and off every 0.5s!

This program took up 82 bytes of flash memory (2% of my available 4096 bytes). For comparison's sake, I wrote an equally simple sketch in the Arduino IDE to blink the green LED:

int greenPin = 7;

void setup() {
  // put your setup code here, to run once:
  pinMode(greenPin, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(greenPin, HIGH);
  delay(500);
  digitalWrite(greenPin, LOW);
  delay(500);
}

The IDE told me the following:
Sketch uses 960 bytes (23%) of program storage space. Maximum is 4096 bytes.
Global variables use 9 bytes (3%) of dynamic memory, leaving 247 bytes for local variables. Maximum is 256 bytes.

Even though this arduino program is functionally equivalent to the c program, and uses a similar number of lines of code, it is more than 10x as large in memory.

As a further project, I'd like to figure out a) how to write this without using the delay function and b) how to read button pushes and c) translate my whole "Blink Pattern" program into lower-level c code, and see how much smaller it is. Projects for the future.

A quick note: I watched an interesting AVR microcontroller webcast by the author of the Make: AVR Programming book. He gives a good overview of microcontroller programming, including a good section on bitwise operators, memory registers, etc. You can check it out on YouTube.

I also found a great set of Atmel Programming Tutorials from Chris Dahms on YouTube. He uses the Atmel Studio IDE which I am not using, but otherwise, these seem like a great overview.

After watching these videos and absorbing some of their content, I went on to write some simple blink programs, including programs that use the pushbutton for input. Above I showed my first, simplest blink program. This is a slight modification to alternate between the red and green LEDs:

// simple program to blink an LED on the hello board
// using ATtiny44
//
// adapted from: https://www.youtube.com/watch?v=SxJZGqToqu4
//
// green pin is PA7
// red pin is   PB2


#include <avr/io.h>
//define F_CPU 1000000UL // 1 MHz - I don't think I need to include this
#define DELAY 100
#include <util/delay.h>


int main(void){
	DDRB |= (1<<DDB2); //make PB2 output
	DDRA |= (1<<DDA7); //make PA7 output
	
	while(1){
		PINB = (1<<PINB2);	//bit shift pin b2
		_delay_ms(DELAY);
		PINA = (1<<PINA7);	//bit shift pin a7
	}
}

Next, I wrote a program to turn the green LED on when the button is pushed in:

//program to use button on board to blink green LED
//
//based on https://github.com/MicrocontrollersAndMore/Atmel_Programming_Tutorial_3_Bit_Manipulation_and_Digital_Inputs/blob/master/DigitalInputs.c

//assumes F_CPU is already setup correctly with fuses

//green LED is on PA7
//red LED is on PB2
//button is on PA3

#include <avr/io.h>

#define BIT_IS_SET(byte, bit) (byte & (1 << bit))
#define BIT_IS_CLEAR(byte, bit) (!(byte & (1 << bit)))


int main (void){
	
	DDRA |= (1 << PA7); //set PA7 to output
	DDRA &= ~(1 << PA3); //set PA3 to input

	while(1){
		if(BIT_IS_CLEAR(PINA, PA3)) {	//if button is pushed
			PORTA |= (1 << PA7);	//light the green LED
		}
		else if(BIT_IS_SET(PINA, PA3)) {	//else if button isn't pushed
			PORTA &= ~(1 << PA7);	//turn off green LED
		}
		else{
			//should never get here... not sure why included
		}
	}
	return(0);	//should never get here either
}