Skip to content

Programming the ATtiny 412:

I used a lot of help from Teddy Warner’s website that has a well-documented page for UPDI usage and jtag2updi programming. I used a standard ATtiny412 for this part of the assignment and the Arduino IDE. I also installed megatinycore by SpenceKonde. Although I did it directly in the library manager tab in the Arduino IDE. I also installed the latest version of the jtag2updi library, which will be accessible in this week’s files.

Pinouts and soldering:

This is the pinouts for the Attiny412.

I soldered the surface-mount board to a SOIC pad on a breadboard, making sure that the dimple is set on pin 1:

Following Teddy Warner’s instructions, I downloaded the required libraries. First, I tested to see that the UPDI on Pin 6 of Arduino worked by plugging the anode of the LED into the pin, and its cathode into ground:

As seen, the LED glows dimly.

Then, I wired the LED to the ATtiny412:

I used an output pin for the data pin of the LED and the following code:

void setup() {
  // put your setup code here, to run once:

  pinMode(3, OUTPUT);

}

void loop() {
  // put your main code here, to run repeatedly:

  digitalWrite(3, HIGH);
  delay(1000);
  digitalWrite(3, LOW);
  delay(1000);

}

However, I went into some problems, as there was an error displayed in the Arduino IDE:

I checked Teddy’s page again and found that the board I chose was wrong, and that it had the optiboot option. So I went to the Tools menu and selected the board again:

However, when I uploaded the code again, I saw that the programmer wasn’t responding:

I looked back at Teddy’s website and found that you must upload the program using the jtagupdi programmer, which I found under the Sketch menu. The programmer is jtag2updi, which I selected in the Tools menu:

Here is the jtag2updi program that I uploaded on to my Arduino Uno:

Here is the LED working:

Button Program

Next, I implemented a push button in the program that will turn on the LED when you push and hold the button. This is the wiring for the button:

I took inspiration from the official Arduino website as well as the following images to wire the button:

I learned that the vertical pins of each column of the push button are internally connected, and so the data line and the ground line must be separate from the power line. This way, when the button is pressed, the middle of the button forms the connection and the horizontal pins are connected.

Here is my final wiring:

here is the code I used:

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(3, OUTPUT);
  pinMode(4, INPUT);
}

// the loop function runs over and over again forever
void loop() {
  bool button_press = digitalRead(4);
  if (button_press == true){
    digitalWrite(3, HIGH);
  }
  else{
    digitalWrite(3, LOW);
  }
}

Here is the program working:

Using Baremetal Programming

I used baremetal programming, which is a low-level type of programming that is hard-coded to a system at the hardware level, according to this website

I decided to look at Dylan Ferro’s code for inspiration.

It looks like baremetal programming is more complicated because it uses less memory and programs the board at a lower level.

Button Program Version 2

I decided to keep the wiring the same like this:

Then, I asked chatGPT to convert the following code to baremetal code. This code allows the LED to stay turned on when the push button is pressed, with a 300 milliseconds buffer for the finger to leave the push button:

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(2, OUTPUT);
  pinMode(4, INPUT);
}

// the loop function runs over and over again forever
void loop() {
  bool button_press = digitalRead(4);
  if (button_press == true && digitalRead(2) == LOW){
    digitalWrite(2, HIGH);
    delay(300); // delay is there in order to ensure that there is time for the finger to leave the button
  }
  else if (button_press == true && digitalRead(2) == HIGH) {
    digitalWrite(2, LOW);
    delay(300);f
  }
}

Here is what ChatGPT gave me:

#define F_CPU 16000000UL  // Assuming a 16 MHz clock

#include <avr/io.h>
#include <util/delay.h>

void setup() {
    // Set pin 2 (PD2) as output
    DDRD |= (1 << PD2);
    // Set pin 4 (PD4) as input
    DDRD &= ~(1 << PD4);
    // Disable internal pull-up for pin 4
    PORTD &= ~(1 << PD4);
}

void loop() {
    // Read pin 4 (PD4)
    bool button_press = PIND & (1 << PD4);
    // Check the state of pin 2 (PD2)
    bool led_state = PIND & (1 << PD2);

    if (button_press && !led_state) {
        // Set pin 2 (PD2) high
        PORTD |= (1 << PD2);
        _delay_ms(300);
    } else if (button_press && led_state) {
        // Set pin 2 (PD2) low
        PORTD &= ~(1 << PD2);
        _delay_ms(300);
    }
}

int main() {
    setup();
    while (1) {
        loop();
    }
}

Although it looked in intimidating at first, the AI explained the code for me. Essentially, the #include headers included definitions for input/output port manipulation, and set up the delay system. The DDRD |= (1<<PD2) sets pin 2 as an output. DDRD is the Data Direction Register for Port D, and PD2 is the bit corresponding to pin 2.

PORTD &= ~(1<<PD4) disables the internal pull-up resistor on pin 4 by clearing the bit in the PORTD register.

In the loop function, PIND & (1<<PD4) reads the state of pin 4 by checking the corresponding bit in the PIN Data Register, which is PIND.

Similarly, PIND & (1<<PD2) reads the state of pin 2 to se if the LED is currently on or off.

The PORTD |= (1<<PD2) line turns the LED on by setting the bit in PORTD, and similarly PORTD &= ~(1<<PD2) turns the LED off by clearing the bit in PORTD.

Finally, the main function continuously calls void loop.

Here is the code working:


Last update: June 18, 2024