ATMEGA328p Microcontroller
Getting started with the ATMEGA328p microcontroller.
Designed by: Colin "MrSwirlyEyes" Keef

Introduction

ATMEGA AVR microcontrollers are awesome programmable chips that are great for simple stand alone projects. The Arduino UNO R3 spots an ATMEGA328p microcontroller at its core. So when you are "programming an Arduino UNO", you are programming the ATMEGA328p microcontroller in which the Arduino UNO is built around. There have been several occasions where we found ourselves making a project with an Arduino UNO and find ourselves stuck between a rock and a hard place. We could buy a new Arduino UNO for approximately $25, or we dismantle our project to use the Arduino UNO in a new project. The better option is neither of these. The better option is to create your own "custom Arduino" that simply utilizes the ATMEGA328p at its core - just like the Arduino UNO. That way, you are not restricted to the Arduino UNO form factor and you can make your own custom circuit on a breadboard or custom PCB with the ATMEGA328p right on it. This is perfect for higher-order prototyping especially in the start-up community. The ATMEGA328p microcontroller price is a small fee of approximately $2 and you only need a few capacitors and a crystal to make a bare minimum "breadboard Arduino UNO". Of course, you can still program the ATMEGA328p using the Arduino IDE as if it was its own Arduino UNO.

In this tutorial, we explore the ATMEGA328p and get you started making a breadboard Arduino UNO using the ATMEGA328p. At the end of the tutorial you can find other related projects and tutorials that utilize AVR microcontrollers and we encourage you to try and port your next project to an ATMEGA328p!

Overall Learning Objectives

Configure Arduino UNO (ATMEGA328p) board settings
Bootload ATMEGA328p
Program ATMEGA328p

Required Tools and Equipment

Laptop Computer
IC/Chip Remover

Required Downloads and Installations

Bill of Materials

DEVICE VENDOR URL QUANTITY NOTES
Arduino UNO R3 Digikey 2 May use other variants, but may need minor changes to code.
USB Cable (A Male to B Male) Digikey 2
ATMEGA328p MCU IC 8BIT 32KB FLASH 28DIP Digikey 1
CRYSTAL 16.0MHZ 18PF T/H Digikey 1
CAP CER 12PF 50V RADIAL Digikey 2 Any value between 12pF-22pF is fine.
CAP CER 0.1UF 50V RADIAL Digikey 1
LED BLUE CLEAR T-1 3/4 T/H Digikey 13 Can substitute for any desired color LED.
RES 10K OHM 1/4W 5% AXIAL Digikey 13 Can substitute for appropriate sized resistor(s).
CAP ALUM 10UF 20% 50V RADIAL Digikey 1 Aluminum Electrolytic Capacitor (polarized). Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too. Any similar value will work too.
Breadboard (small) Digikey 2 Used for prototyping.
Jumper Wire M/M 6 (20pcs) Digikey 2 Used for prototyping.
SERIAL PROGRAMMER IC BRIDGE USB-UART 3.3V MODULE Digikey 1 Used to program ATMEGA328p (BT RC Car vehicle).
[Optional] POCKET AVR PROGRAMMER Digikey 1 Optional if using Arduino UNO as ISP. Used to bootload AVR microcontrollers.
[Optional] USB Cable (A Male to Mini B Male) Digikey 1 Accessory to both AVR Pocket Programmer and Serial Programmer.

01 Introduction to ATMEGA Microcontrollers

Objective

In this module, we introduce you to ATMEGA AVR microcontrollers in general. Most of them operate largely the same including their set up, configuration, and programming them.

AVR Microcontrollers

Most AVR microcontrollers behave the same where they are an ATtiny variant or ATMEGA variant. We have a tutorial that introduces AVR microcontrollers and what is necessary to get started using them. Pay close attention to this tutorial as we describe how to work with AVR microcontrollers in general. You need to decide whether you would like to use an Arduino UNO as an ISP to program your ATMEGA328p, or the Sparkfun Pocket AVR Programmer. The tutorial covers AVR microcontrollers and is mostly split up between ATtiny AVR microcontrollers and ATMEGA AVR microcontrollers - we want to follow the ATMEGA specfic parts! After you go through the tutorial, return here and we will dive specifically into the ATMEGA328p. Now, we direct you to the tutorial here: AVR Microcontrollers

Returning from the AVR Microcontrollers tutorial. We should know what device we will use to bootload and program the ATMEGA328p (Arduino as ISP or Pocket AVR Programmer), and some of the bootloading process (again, explicitly covered here).

In the next module, we explore the ATMEGA328p.

02 The ATMEGA328p Microcontroller

Objective

Now we focus on the ATMEGA328p microcontroller explicitly. We will cover its pinout, capabilities and explore the process for which we program the ATMEGA328p in detail.

Overview of the ATMEGA328p

The specifications of the ATMEGA328p are outlined as follows:

Specifications
Flash (program memory) 32 KB
RAM (Random Access Memory) 2 KB
EEPROM (Electrically Erasable Programmable Read-Only Memory) 1 KB
Bootloader yes
GPIO pins 23
ADC (Analog-to-Digital Converter) Channels 6 (including the one on RESET)
PWM (Pulse-Width Modulation) Channels 6
Interfaces USI, UART, I2C
Clock options internal 1/8 MHz, external crystal or clock up to 8/12/16/18.432/20 MHz

The following shows the pinout diagram for the ATMEGA328p:

The pins of interest are the following:

Analog Pins - Your typical analog pins the same as any Arduino and in the Arduino IDE.
Timer/PWM Pins - Your typical PWM pins the same as any Arduino and in the Arduino IDE.
Arduino Pins - The labels here are what pins you need to define in your code on the Arduino IDE. Observe that some of the pins have multiple uses (Analog, Digital, PWM, and even all 3 on a single pin).
Crystal Oscillator (External Clock) Pins - XTAL1 and XTAL2 are the pins we connect an external oscillator to so we can run the ATtiny at a higher clock rate (speed).
Serial Interface Pins - The UART (Universal Asynchronous Receiver-Transmitter) pins are RXD and TXD. Also on board are the I2C pins: SDA (Serial Data) and SCL (Serial Clock). Both of these serial interfaces are methods of communication.
In-System ATMEGA328p (ISP) Pins - The pins we need to use to program the ATtiny! These should be familiar from the ISP pins on the Arudino UNO.

In-System Programmer (ISP) Pins paralleled with that of those on the Arduino UNO are the same as the ATMEGA328p:

MISO (Master In Slave Out) – Slave line used to send data to the Master (e.g. Arduino UNO).
MOSI (Master Out Slave In) – Master line used to send data to the peripherals (e.g. ATtiny).
SCK (Serial Clock) – Clock pulses for synchronized data; transmitted/set by Master.
RESET – Used by the Master to perform a software reset on the ATtiny.

Observe that both the Arduino UNO and ATMEGA328p have a SS (Slave Select) pin. When programming the ATMEGA328p we will need the SS pin on the Arduino UNO (master device) connected to the RESET pin on the ATMEGA328p (slave device).

Even for such a small chip, there is a ton of information that we are not able to cover. Feel free to checkout the complete documentation of the ATMEGA328p from its datasheet linked in the Resources and References at the bottom of the page.

Observe the similarities of the ATMEGA32p to the Arduino UNO - which are identical devices. The Arduino UNO has a built-in serial programmer, so that you use the familiar USB Cable (Male A to Male B) to program the Arduino UNO, as well as some other circuitry to power and protect the ATMEGA328p (on the Arduino UNO) and allow for a power supply via the barrel jack connector. The Arduino UNO is shown below for reference:

Now that we have familiarized with the ATMEGA328p, we are ready to bootload the microcontroller now!

03 Bootloading the ATMEGA328p

Objective

In this module, we will walk through the process in which we bootload the ATMEGA328p. Bootloading AVR microcontrollers is an essential step to ensure that the microcontroller behaves appropriately. In some AVR microcontrollers that do not have a hardware UART, the same method to bootload the microcontroller is employed to program the microcontroller. However, the ATMEGA328p has a dedicated (hardware) UART interface. That is, it has RX and TX pins in its pinout. With this programming the ATMEGA328p can do done through a typical USB.

Unfortunately, we cannot just connect a USB directly to the TX and RX pins of the ATMEGA328p. We need another chip that translates the USB signals to into serial signals to program the ATMEGA328p. The Sparkfun FTDI Basic Breakout can do this. There are also specialized serial ICs that can perform this task as well. So we will demonstrate how to use the Sparkfun FTDI Basic Breakout to program our ATMEGA328p. If we made a custom PCB or project with the ATMEGA328p and do not want to rely on an external breakout, and just want to usb a USB cable of some sort. Then we need to integrate a serial IC and a USB connector.

Let us see how we can program our ATMEGA328p!

Bootloading the ATMEGA328p

To bootload the ATMEGA328p, we need to use an external master device to program our ATMEGA328p (slave device). There are several ways we can do this. The most common way is to use an Arduino UNO to program the ATMEGA328p. This is usually easy because it is assumed that you already have an Arduino UNO on hand. Another common method is to use the FTDI Basic Breakout by Sparkfun.

From the AVR Microcontrollers tutorial, configure your Arduino IDE and/or programming device. Assuming the ATMEGA328p board settings in the Arduino IDE are configured appropriately.

Next, we have to burn the bootloader to the ATMEGA328p.

Burn the Bootloader to ATMEGA328p using Arduino UNO as an In-System Programmer

If you have not done so yet, make sure your Arduino UNO is configured as an In-System Programmer, which is outlined in the Programming AVR Microcontrollers module in the AVR Microcontrollers tutorial.

With your Arduino UNO configured, we need to build the following circuit to connect the Arduino UNO to the ATMEGA328p:

Pay close attention to the schematic. The ATMEGA328p physical pins (numbers protruding from the symbol) and Arduino or programming pins (in the description inside the symbol) are labeled on the schematic.

The 10µF capacitor prevents the Arduino UNO from automatically resetting when we program the ATMEGA328p.

Observe that the Serial pins of the Arduino UNO are connected to the ISP pins of the ATtinyX5. Furthermore, the ATtinyX5 needs to be powered when we program it, we can just tap off the Arduino UNO power rail pins with it connected to your computer USB port. We outline these connections in the following table:

Arduino UNO (physical pin) ATMEGA328p (physical pin)
3.3V or 5V VCC (pin 7, 20)
SCK (pin 13) SCK (pin 19)
MISO (pin 12) MISO (pin 18)
MOSI (pin 11) MOSI (pin 17)
SS (pin 10) RESET (pin 1)
GND GND (pin 8, 22)

Do not confuse the physical pin with the Arduino or programming pin.

Although the schematic shows the connection to 3.3V, 5V will also work just as well.

Please use the Chip Remover when removing ATMEGA microchips, the pins are extremely fragile. If you break a pin, the chip practically becomes useless.

With the appropriate settings selected in the Arduino IDE, first select Burn Bootloader to burn the selected settings to the ATMEGA328p.

Be sure you have selected Arduino as ISP for the programmer setting.

To burn the bootloader, on the Arduino IDE navigate to Tools and click Burn Bootloader.

Selecting Burn Bootloader will act instantly!

You should always Burn Bootloader when first using the ATMEGA variant chip. You never know what fuse settings came with the board by default.

Be sure all the settings we have discussed during this tutorial are set appropriately.

There is an implicit Clock setting that is burned by the bootloader here. We are essentially programming the ATMEGA328p to be a literal Arduino UNO - or at least function like one. The Arduino UNO utilizes an external 16 MHz clock (hence why we have one connected on our schematic). If we do NOT have a 16 MHz crystal connected correctly, we will not be able to program out ATMEGA328p after we bootload it.

If your connections are correct, you should receive a successful Burn Bootloader message.

If you do NOT get a successful Burn Bootloader message, please check your circuit, the board settings, and make sure the ArduinoISP sketch has been uploaded to your Arduino UNO.

Burn the Bootloader to ATMEGA328p using Pocket AVR Programmer

If you have not done so yet, make sure you have the Pocket AVR Programmer configured appropriately, which is outlined in the Bootloading AVR Microcontrollers module in the AVR Microcontrollers tutorial.

With your Pocket AVR Programmer configured, we need to build the following circuit to connect the Pocket AVR Programmer 2x3 ISP header to the ATMEGA328p:

You need to use your imagination (since we do not have a physical picture here - only a schematic representation). The Pocket AVR Programmer 2x3 ISP header has a key sticking out of one end of the connector (which is illustrated in the schematic). This is also from a top-view perspective.

Pay close attention to the schematic. The ATMEGA328p physical pins (numbers protruding from the symbol) and Arduino or programming pins (in the description inside the symbol) are labeled on the schematic.

Observe that the Serial pins of the Pocket AVR Programmer are connected to the ISP pins of the ATMEGA328p. Furthermore, the ATMEGA328p needs to be powered when we program it, we can just tap off an Arduino UNO power rail pins with it connected to your computer USB port or using the Pocket AVR Programmer itself by toggling the switch between Power Target and No power.

Careful if you chose to power the ATMEGA328p using the Pocket AVR Programmer, it provides 5V when Power Target is selected. This is convenient for breadboard prototyping in general, however it is common to not to use the Pocket AVR Programmer to power the target (e.g. ATMEGA) when it is on its own (custom) PCB because you may be using a voltage less than 5V which may damage your custom circuitry.

We outline these connections in the following table:

Pocket AVR Programmer
(2x3 ISP header)
ATMEGA328p
(physical pin)
5V (pin 2) or NC VCC (pin 7, 20)
SCK (pin 3) SCK (pin 19)
MISO (pin 1) MISO (pin 18)
MOSI (pin 4) MOSI (pin 17)
RESET (pin 5) RESET (pin 1)
GND (pin 6) GND (pin 8, 22)

NC = NOT connected or NO connection.

Do not confuse the physical pin with the Arduino or programming pin for the ATtiny.

The connection to the Pocket AVR Programmer VCC (5V) pin may NOT need to be connected if you will power your microcontroller with an external power source.

Please use the Chip Remover when removing ATMEGA microchips, the pins are extremely fragile. If you break a pin, the chip practically becomes useless.

With the appropriate settings selected in the Arduino IDE, first select Burn Bootloader to burn the selected settings to the ATMEGA328p.

Remember the Pocket AVR Programmer will NOT show up in Port, so it is OK to have nothing selected.

Be sure you have selected USBtinyISP for the programmer setting.

There is an implicit Clock setting that is burned by the bootloader here. We are essentially programming the ATMEGA328p to be a literal Arduino UNO - or at least function like one. The Arduino UNO utilizes an external 16 MHz clock (hence why we have one connected on our schematic). If we do NOT have a 16 MHz crystal connected correctly, we will not be able to program the ATMEGA328p after we bootload it.

To burn the bootloader, on the Arduino IDE navigate to Tools and click Burn Bootloader.

Selecting Burn Bootloader will act instantly!

You should always Burn Bootloader when first using the ATMEGA variant chip. You never know what fuse settings came with the board by default.

Be sure all the settings we have discussed during this tutorial are set appropriately.

If your connections are correct, you should receive a successful Burn Bootloader message.

If you do NOT get a successful Burn Bootloader message, please check your circuit, and the board settings.

Burning the bootloader is a one time thing. You can reburn it later with different fuse settings if necessary, but is not necessary for general use and is out of the scope of this tutorial.

We no longer need the bootloader circuit here on out. To program the ATMEGA328p, we employ a different circuit.

With the bootloader burned to your ATMEGA328p, we are finally ready to program it with custom code!

04 Programming the ATMEGA328p

Objective

In this module, we will program the ATMEGA328p. The program we upload to the ATMEGA328p is trivial, however we encourage you to explore its capabilities further in your own application!

It is not unheard of to program the ATMEGA328p using the AVR ISP configuration - the same set up we had to burn the bootloader. However, a more common method is to use a USB cable, as is done with the Arduino UNO and other Arduino variants. So, we will use the hardware UART to program the ATMEGA328p which requires a different circuit and an external breakout module.

We first start by introducing UART Serial communication. Then we will construct the necessary circuit to program the ATMEGA328p. Finally, we will program the ATMEGA3289p!

UART Serial Communication

A Universal Asynchronous Receiver-Transmitter (UART) is a block of circuitry responsible for implementing serial communication. Internally, there is a bus of parallel data lines and control pins managed by the microcontroller. Externally, what the user uses are the simple TX and RX pins of the microcontroller or serial device. Most microcontrollers today come with one or more UARTs. The ATMEGA328p has one. The asynchronous aspect means data is transferred without utilizing an external clock signal. This is why we only need 2 pins, TX for transmitting and RX for receiving. In order for this to work well, the microcontroller puts effort into framing and packaging our data in transmission to increase reliability.

The TX and RX pins are labeled with respect to the device itself. Thus the TX of one device is connected to the RX of the reciprocal device and vice-versa. That is, the transmitter of device A is communicating to the receiver of device B, and device B is transmitting to the receiver of device A.

Some microcontrollers do not have a UART (e.g. most ATtinys), however can use a Software UART. Even microcontrollers that do have a hardware UART, but need another serial communication interface can use a Software UART in addition to their dedicated UART. A Software UART is directly controlled by the processor, not as reliable as a dedicated UART, and is processor intensive.

If you have worked with Arduino a bit, you have probably been exposed to the Serial Monitor. The Serial Monitor is a terminal that connects us to the Arduino UNO. This is convenient for debugging statements, and a more powerful means of communicating between user and Arduino or your computer and the Arduino. Commonly when we use the Serial Monitor, we do not need any extra connections using Arduino pins because we have the USB Cable connected between our computer and the Arduino, which allows for the Serial communication by default. All we need to add is the appropriate code in our program.

Unfortunately, since we have a barebones ATMEGA328p we need the extra circuitry, hence the Sparkfun FTDI Basic Breakout to approximate this luxury. However, in your own custom product you can integrate all of this into single printed circuit board.

Now with some familiarity with the circuitry necessary to program our ATMEGA328p, let us now construct the appropriate circuit.

Hardware Configuration to Program the ATMEGA328p

As mentioned previously, the ubiquitous way to program microcontrollers is through a USB cable. However, the USB cable cannot talk directly to the microcontroller hardware UART (TX/RX pins). In order to translate the USB signals to Serial signals, an extra piece of hardware is necessary. This is generally a serial IC. To make things easier, Sparkfun has already made a device that does just this, called the Sparkfun FTDI Basic Breakout - or Serial Programmer.

We need to build the following circuit to connect the Sparkfun FTDI Basic Breakout to the ATMEGA328p:

Pay close attention to the schematic. The ATMEGA328p physical pins (numbers protruding from the symbol) and Arduino or programming pins (in the description inside the symbol) are labeled on the schematic.

The ATMEGA328p TX pin is connected to the Serial Programmer RX pin!

The ATMEGA328p RX pin is connected to the Serial Programmer TX pin!

Careful if you chose to power the ATMEGA328p using the Sparkfun FTDI Basic Breakout, it provides 3.3V or 5V (depending on which you buy, we linked the 3.3V version). This is convenient for breadboard prototyping in general, however it is common to NOT to use the Serial Programmer to power the target when it is on its own (custom) PCB because you may be using a voltage that is not exactly the same as the Serial Programmer which may damage your custom circuitry.

Observe that the Serial pins (TX/RX) of the ATMEGA328p are connected to the Serial pins (TX/RX) of the Serial Programmer. Furthermore, the ATMEGA328p needs to be powered when we program it, we can just tap off and Arduino UNO power rail pins with it connected to your computer USB port. We outline these connections in the following table:

Sparkfun FTDI Basic Breakout
(physical pin)
ATMEGA328p
(physical pin)
3.3V, 5V, or NC VCC (pin 7, 20)
RX TX (pin 3)
TX RX (pin 2)
GND GND (pin 8, 22)

NC = NOT connected or NO connection.

Do not confuse the physical pin with the Arduino or programming pin.

Please use the Chip Remover when removing ATMEGA microchips, the pins are extremely fragile. If you break a pin, the chip practically becomes useless.

With the appropriate circuit in place, we are finally ready to program the ATMEGA328p!

Programming the ATMEGA328p

We demonstrate a trivial example of programming the ATMEGA328p, the typical blink sketch. You may now open a new sketch and write your own code or copy-paste the following code into the sketch:

// Trivial program to test the ATMEGA328p.
//
// Toggles LED on and off for a fixed period of time.
//  Typical blink sketch.


#define led 9

void setup() {
  // Initialize ATMEGA328p digital physical pin 15
  //	(programming pin 0) as an output.
  pinMode(led, OUTPUT);
}

void loop() {
  // Toggle LED on
  digitalWrite(led, HIGH);
  delay(1000);

  // Toggle LED off
  digitalWrite(led, LOW);
  delay(1000);
}

Since we have bootloaded/configured the ATMEGA328p with the same settings as an Arduino UNO. We need to select the Arduino/Genduino UNO for the board setting in the Arduino IDE.

Since we are using the Sparkfun FTDI Basic Breakout Serial Programmer, we need to select USBtinyISP for the Programmer setting in the Arduino IDE.

Furthermore, the Sparkfun FTDI Basic Breakout Serial Programmer has a port setting that needs to be selected to program the target device.

Navigate to Tools > Port and select the serial programmer.

The characters following "/dev/cu.usbserial-" will vary from device to device.

If your Sparkfun FTDI Basic Breakout does not show up in the port device options. Then you may need to install the FTDI driver. We redirect you to Sparkfun's How to Instal FTDI Drivers tutorial here:

https://learn.sparkfun.com/tutorials/how-to-install-ftdi-drivers/all

Finally, to program the ATMEGA328p with the sketch, simply upload (CTRL/CMD + U) your sketch to the board as you would with any sketch!

You should receive the typical successful programming message.

With the code given above, the ATMEGA328p will toggle one of the digital pins. The following circuit blinks an LED using the appropriate digital pin designated in the uploaded code:

The results should be similar to:

And that is it! Your ATMEGA328p should be blinking an LED. This was a trivial example, but it is the start of many possibilities to reduce your overall hardware footprint and cost.

Conclusion

The concept of programming AVR microcontrollers is the take away from this tutorial. Prototyping using Arduino development boards is still the way to go. The ATMEGA328p as we have configured it is effectively a cloned Arudino UNO. The understanding ATMEGA328p uncovers some of the mystery of the Arduino UNO which is also based on the (same) ATMEGA328p AVR microcontroller. (Disclaimer, there is still a lot more to learn out there - we are still learning ourselves)! Technically you can take any Arduino UNO project that you have done and use the circuit that you have built to replace your Arduino UNO - and at a significantly cheaper cost.

However, we warn that, as is, we are powering the ATMEGA328p using the Arduino UNO or Sparkfun FTDI Basic Breakout. For this to be truly standalone, we would need a battery or power source to power our ATMEGA328p Arduino UNO clone. We encourage you to keep exploring this concept and make your own custom project prototyped with your new Arduino UNO clone and perhaps make your own PCB (printed circuit board) to perhaps make your own custom embdeeded product! If you want to make your own custom hardware or product, then making and breaking the development board is necessary to make your own embedded project!