ATmega328P Standalone — Wiring the Bare IC
Pulling the ATmega328P out of the Arduino socket and building a minimum viable circuit on a breadboard. Crystal, decoupling caps, reset pull-up, and an LED blinking under bare-metal C.
Why Wire It Standalone
The Arduino Uno is a development board. The ATmega328P is the chip. They’re not the same thing — the board adds a USB-serial bridge, a 5V regulator, a reset circuit, and 16 of the 28 pins broken out to headers. For anything that ships in a product or gets installed in a permanent fixture, you want the IC alone, running on the minimum it needs.
Wiring the chip standalone also forces you to understand what the Uno was quietly providing. The chip needs power, a clock source, a stable reset line, and decoupling capacitors — none of that is optional.
The ATmega328P Pinout (DIP-28)
┌──┤├──┐
PC6 ── 1 28 ── PC5
PD0 ── 2 27 ── PC4
PD1 ── 3 26 ── PC3
PD2 ── 4 25 ── PC2
PD3 ── 5 24 ── PC1
PD4 ── 6 23 ── PC0
VCC ── 7 22 ── GND
GND ── 8 21 ── AREF
PB6 ── 9 20 ── AVCC
PB7 ── 10 19 ── PB5 (SCK / pin 13)
PD5 ── 11 18 ── PB4 (MISO / pin 12)
PD6 ── 12 17 ── PB3 (MOSI / pin 11)
PD7 ── 13 16 ── PB2 (SS / pin 10)
PB0 ── 14 15 ── PB1
└───────┘
Pin 1 is PC6 — also RESET. Pin 7 and 20 are VCC. Pin 8 and 22 are GND. Pins 9–10 (PB6/PB7) are the crystal pins.
Minimum Circuit Components
| Part | Value | Purpose |
|---|---|---|
| ATmega328P | DIP-28 | The MCU |
| Crystal | 16 MHz | External clock source |
| Capacitors × 2 | 22 pF ceramic | Crystal load caps |
| Capacitor × 2 | 100 nF ceramic | Power decoupling (VCC and AVCC) |
| Resistor | 10 kΩ | RESET pull-up |
| LED | any colour | Output indicator |
| Resistor | 220 Ω | LED current limiter |
Total cost around ₹500–550 if buying loose components. The chip itself is the expensive part at roughly ₹400 for a DIP-28.
Wiring the Circuit
Power
Connect both VCC pins (7 and 20) to the positive rail and both GND pins (8 and 22) to the negative rail. Place a 100 nF decoupling capacitor between VCC (pin 7) and GND as close to the chip as possible — this suppresses high-frequency noise on the supply line that can cause erratic behaviour or reset events. Do the same for AVCC (pin 20).
AREF (pin 21) can float if you’re not using the ADC. If you plan to use analogRead, connect it to VCC through a 100 nF cap.
Crystal
The 16 MHz crystal goes between pins 9 (XTAL1 / PB6) and 10 (XTAL2 / PB7). Each crystal leg also gets a 22 pF ceramic cap to GND. The exact value depends on the crystal’s specified load capacitance — 18 pF and 22 pF are both common and interchangeable for most hobby crystals.
┌──── pin 9 (XTAL1)
│
[22pF] [16MHz crystal]
│
GND pin 9 ─── leg 1
leg 2 ─── pin 10
pin 10 ─── [22pF] ─── GND
Without the crystal the chip falls back to its internal 8 MHz RC oscillator (factory default fuse setting is actually 1 MHz internal RC, so freshly bought chips without an Arduino bootloader will run at 1 MHz until you reflash the fuses). The crystal gives you a stable 16 MHz and is required if you’re communicating over serial at higher baud rates.
Reset Line
Pin 1 (RESET, active-low) needs a 10 kΩ pull-up resistor to VCC. Without it the line floats and the chip resets randomly. The Arduino Uno has this built in — on the bare chip you supply it yourself.
VCC ──── [10kΩ] ──── pin 1 (RESET)
You can optionally add a push button between RESET and GND if you want a manual reset. Not required for blink.
LED
Connect an LED and 220 Ω resistor in series from PB5 (pin 19, the same as pin 13 on the Uno) to GND. The resistor limits current to around 14 mA at 5V — safe for the LED and within the ATmega’s 40 mA per-pin absolute maximum.
pin 19 (PB5) ─── [220Ω] ─── [LED] ─── GND
Full Breadboard Layout (described)
- Place the ATmega328P straddling the centre gap — pin 1 top-left
- Positive rail: connect pins 7 and 20 with jumpers
- Negative rail: connect pins 8 and 22 with jumpers
- Decoupling: 100 nF cap between the VCC tie and GND rail, same for AVCC
- Crystal: bridge pins 9 and 10 with the crystal, 22 pF cap from each pin to GND rail
- Reset pull-up: 10 kΩ from positive rail to pin 1
- LED: 220 Ω from pin 19 → LED anode → LED cathode → GND rail
Programming the Standalone Chip
The bare chip has no USB port. You need an ISP (In-System Programmer) to flash it. The easiest option if you already have an Arduino Uno: use it as an ISP.
Step 1 — Flash the ArduinoISP sketch onto the Uno
In the Arduino IDE: File → Examples → 11.ArduinoISP → ArduinoISP. Upload to the Uno normally. The Uno is now a programmer.
Step 2 — Wire the SPI lines
Connect the Uno’s SPI pins to the ATmega328P’s corresponding pins:
| Uno pin | ATmega328P pin | Function |
|---|---|---|
| 10 | 1 (RESET) | Chip select / reset |
| 11 | 17 (MOSI / PB3) | Data out |
| 12 | 18 (MISO / PB4) | Data in |
| 13 | 19 (SCK / PB5) | Clock |
| 5V | 7, 20 | Power (if not externally powered) |
| GND | 8, 22 | Ground |
Note: pin 19 is both SCK and the LED pin. During programming the LED will flicker with clock activity. Disconnect it if it causes issues, though in practice 220 Ω is a high enough impedance that it usually works fine.
Step 3 — Upload with avrdude
avrdude -c stk500v1 -p m328p -P /dev/cu.usbserial-1120 -b 19200 \
-U flash:w:blink.hex
The programmer type is stk500v1 (ArduinoISP), baud is 19200. Compile blink.hex the same way as the previous entry:
avr-gcc -mmcu=atmega328p -DF_CPU=16000000UL -Os -o blink.elf blink.c
avr-objcopy -O ihex blink.elf blink.hex
The Blink Code
Same as before — PB5 is the target pin:
#include <avr/io.h>
#include <util/delay.h>
int main(void) {
DDRB |= (1 << PB5); // PB5 output
while (1) {
PORTB |= (1 << PB5); // HIGH
_delay_ms(500);
PORTB &= ~(1 << PB5); // LOW
_delay_ms(500);
}
}
If the fuses are set to 1 MHz internal (factory default for chips without an Arduino bootloader), _delay_ms(500) will actually delay 8× longer — 4 seconds — because the compiler calculated the loop count assuming 16 MHz but the chip is running at 1 MHz. Either burn the fuses to use the external crystal, or change F_CPU to 1000000UL when compiling.
Setting Fuses for External Crystal
Fuses are one-time programmable configuration bits that control clock source, boot options, and more. To switch from the internal oscillator to the 16 MHz crystal:
# Low fuse: 0xFF = full crystal swing oscillator, no clock divider
# High fuse: 0xDE = SPI programming enabled, no bootloader section
avrdude -c stk500v1 -p m328p -P /dev/cu.usbserial-1120 -b 19200 \
-U lfuse:w:0xFF:m -U hfuse:w:0xDE:m
Warning: writing the wrong fuse values can lock the chip. 0xFF low fuse with no crystal connected will cause the chip to hang waiting for a clock that never arrives — and you will not be able to reprogram it over SPI without providing an external clock signal on XTAL1. Double-check the crystal is wired before setting this.
The Arduino Uno bootloader uses lfuse=0xFF, hfuse=0xDE, efuse=0x05 — burning these also installs the bootloader section config, so if you later want to re-add a bootloader you have the right fuse state.
What You Have Now
A working ATmega328P circuit built from scratch — no development board, no USB bridge, no regulator, no pre-flashed bootloader. Just the chip, a clock source, power filtering, and a pull-up on reset. This is the same circuit that goes inside most Arduino-based products once you strip away the development conveniences.