Generating PDF…

Preparing…
← Back
Reference

Arduino as ISP

Programming the Standalone ATmega328P

DE6417 Microcontrollers 2  ·  Week 13

Arduino Uno + ATmega328P Required

Why Program a Bare Chip?

The Arduino board is a development tool

Everything on the Arduino board around the ATmega328P chip exists to make programming convenient — not to run your final product.

  • Real products are built around the chip itself, soldered onto a custom PCB
  • Cost: An ATmega328P chip costs ~$2. An Arduino Uno costs ~$25. You ship the chip, not the board.
  • Size: The chip is 3 cm long. The Uno board is 7× bigger.
  • Power: The Uno's USB-serial chip and regulators draw current even when idle
  • Flexibility: On a custom PCB you place only the components your circuit needs

Ways to get code onto a bare ATmega328P

ApproachHardware needed
Arduino as ISPAnother Arduino Uno running a sketch
Dedicated ISP programmerUSBasp, AVRISP mkII, Atmel-ICE
Bootloader + USB-serial adapterFTDI adapter; bootloader must be burned first
Bootloader + Uno as carrierRemove the Uno's chip, seat the target chip in its socket
JTAG / debugWIREAtmel-ICE; adds hardware debugging
All approaches ultimately write bytes to flash. They differ only in what hardware acts as the bridge between your PC and the chip.

Today's Approach: Arduino as ISP

Why Arduino as ISP?

  • No extra hardware to buy — you already have an Arduino Uno
  • Works on macOS, Windows, and Linux without special drivers
  • Supported natively by the Arduino IDE and avrdude
  • Can both upload sketches and burn bootloaders — the most versatile option with what we have
The Arduino Uno becomes the programmer. The bare ATmega328P on the breadboard is the target.

🛒 Components for Today

ComponentValue / TypeQtyPart
Arduino Uno Any revision 1 1 & 2
ATmega328P-PU DIP-28 package 1 1 & 2
Breadboard Full or half size 1 1 & 2
Electrolytic capacitor 10 µF 1 1
Jumper wires Male-to-male 6+ 1
Crystal oscillator 16 MHz 1 2
Ceramic capacitor 22 pF 2 2

Learning Outcomes

🔌

Understand ISP

Explain the ISP protocol and how it differs from the bootloader upload path.

💾

Configure programmer

Flash the ArduinoISP sketch to a Uno and configure the IDE correctly.

🔧

Wire correctly

Connect all 6 ISP lines between the programmer Uno and the target chip.

Flash and prove

Upload a sketch to the standalone chip and observe it running independently.

Quick Check — Before We Start

Q1: What does ISP stand for?

Q2: Which physical interface does ISP use?

Two Ways to Program the ATmega328P

Bootloader Path (what you know)
PC → USB cable
CH340 / ATmega16U2 chip on Uno
UART (RX / TX pins)
Optiboot bootloader (already in flash)
Flash memory
ISP Path (today)
PC → USB cable
Programmer Uno (running ArduinoISP)
SPI: MOSI / MISO / SCK + RESET
AVR hardware programming interface (built in silicon)
Flash memory

ISP writes directly to flash. The chip does not need to be running any code.

What is ISP?

In-System Programming

  • A standard AVR hardware feature — not software
  • Uses 4 SPI lines to read and write flash, EEPROM, and fuse bits
  • Available on every ATmega328P — even a blank, factory-fresh chip
  • The programmer holds RESET LOW to put the chip in programming mode, then clocks data in via MOSI
ISP can recover a bricked chip because it does not depend on any software already running on the target.

Example: you accidentally set the wrong clock-source fuse — the chip now expects an external crystal that isn't there. Every power-up, the CPU stalls before a single line of code runs, so the bootloader never starts and Serial upload is permanently dead. ISP bypasses all of that: the programmer drives RESET LOW, sends the SPI clock from outside, and reads/writes flash directly. It restores the correct fuse, burns a fresh bootloader, and hands the chip back working — without the chip ever needing to run code first.

The 4 ISP pins on ATmega328P

SignalPort / PinPhysical DIP Pin
MOSIPB317
MISOPB418
SCKPB519
RESETPC61

Same pins as SPI — students already know these from earlier in the course.

SPI Recap: Master and Slave Roles

Who is who today

  • Master: Programmer Uno (running ArduinoISP sketch)
  • Slave: Target ATmega328P on the breadboard
Target signalProgrammer Uno pinDirectionPurpose
MOSID11 / COPI (Controller Out, Peripheral In)Master → SlaveProgramming data to target
MISOD12 / CIPO (Controller In, Peripheral Out)Slave → MasterStatus and verify data back
SCKD13 / SCK (same name)Master → SlaveClock — synchronises every bit
RESET (PC6, pin 1)D10 / SS (repurposed to drive target RESET)Master → SlaveHold LOW to enter programming mode
RESET ≠ SS — they are different pins on different chips: MOSI/MISO/SCK share the same SPI bus with only a naming change. RESET (PC6 on the target) and SS (D10 on the programmer) are wired together in the ISP setup — the programmer simply repurposes its SS pin to pull the target's RESET line LOW.
Programmer Uno
(ArduinoISP sketch)
MOSI (COPI) →
← MISO (CIPO)
SCK →
RESET →
Target ATmega328P
(standalone chip)

MISO direction is from the slave's perspective — data comes back from the target to confirm what was written.

Signal Direction Check

Match each signal to its correct direction during ISP programming

MOSI
MISO
SCK
RESET

The ArduinoISP Sketch

What it does

  • A sketch you flash to the programmer Uno — once, before the lab
  • Turns that Uno into a protocol translator between your PC and the target chip
  • Translates STK500v1 serial commands from avrdude into SPI signals to the target
Location in Arduino IDE:
File → Examples → 11.ArduinoISP → ArduinoISP
The programmer Uno stays connected to the PC the entire session. It is the bridge.
PC / avrdude
USB serial (STK500v1 protocol)
Programmer Uno
ArduinoISP sketch
SPI (MOSI / MISO / SCK / RESET)
Target ATmega328P
standalone chip
Flash memory

The 10 µF Capacitor — Critical Detail

Why it's needed

  1. When avrdude opens the serial port, it pulses the DTR line
  2. DTR normally travels through the auto-reset circuit and resets the Uno
  3. A reset mid-programming crashes ArduinoISP → upload fails
  4. A 10 µF capacitor blocks the brief DTR pulse from reaching RESET
Placement: Capacitor goes on the programmer Uno RESET → GND.
NOT on the target chip.

Wiring the capacitor

Negative leg (stripe) → GND on programmer Uno
Positive legRESET pin on programmer Uno
Value: 10 µF (electrolytic, polarised — polarity matters)
The heartbeat LED on pin 13 of the programmer Uno should pulse slowly after ArduinoISP is running. If the Uno resets repeatedly, the cap is wrong.

Wiring: Full Connection Table

Programmer Uno PinSignalTarget ATmega328P DIP PinNote
Pin 10RESETPin 1 (PC6)Pulls target into programming mode
Pin 11MOSIPin 17 (PB3)Data out from programmer
Pin 12MISOPin 18 (PB4)Data back from target
Pin 13SCKPin 19 (PB5)Also the programmer Uno's onboard LED — it flickers during upload (normal)
5VVCCPin 7 + Pin 20Power the target from the programmer
GNDGNDPin 8 + Pin 22Common ground — connect all GND pins
+ 10 µF capacitor on programmer Uno: RESET → GND (negative to GND)
Arduino Uno to ATmega328P wiring diagram

Pin Mapping Check

Q3: On the ATmega328P DIP-28 package, which physical pin is MOSI?

Q4: You connect programmer pin 10 to target pin 1. What is this wire for?

Arduino IDE Configuration

Four things to set before uploading

#Menu pathWhat to select
1Tools → BoardArduino Uno — the target type, not the programmer
2Tools → PortThe COM/tty port of the Arduino Uno
3Tools → ProgrammerArduino as ISP
4Upload methodSketch → Upload Using Programmer

The critical mistake to avoid

Do NOT click the normal Upload arrow (▶).

That uploads to the programmer Uno and overwrites ArduinoISP. You will need to reflash it.
Use Sketch → Upload Using Programmer every single time.

What Happens When You Upload

1

Compile

IDE calls avr-gcc. Your sketch becomes a .hex file in a temp folder.

2

Connect

IDE calls avrdude -c stk500v1 -b 19200. Opens serial to the programmer Uno.

3

Translate

Programmer Uno receives hex bytes over UART, translates them into SPI transactions.

4

Write + Verify

SPI clocks data into target flash, one page at a time. avrdude reads back and verifies every byte.

Expected terminal output:
avrdude: 176 bytes of flash written
avrdude: verifying flash memory...
avrdude done. Thank you.

Burn Bootloader vs Upload Sketch

OperationHowWhat it doesWhen to use
Upload Using Programmer Sketch → Upload Using Programmer Writes your sketch .hex directly to the application flash section Every normal programming session
Burn Bootloader Tools → Burn Bootloader Erases flash, sets correct fuses, writes Optiboot to the Boot Flash Section Fresh chip, bricked chip, restoring USB upload capability
After Burn Bootloader, the chip can receive sketches via USB-to-serial / FTDI again.
After Upload Using Programmer, the bootloader is still there if it was before — but "Burn Bootloader" erases everything first.

Lecture Summary

What we covered

  • ISP uses 4 SPI wires + RESET to write directly to AVR flash hardware
  • ArduinoISP sketch turns a Uno into a protocol translator — upload it once to the programmer Uno
  • 10 µF cap on programmer RESET → GND blocks the DTR pulse that would crash ArduinoISP
  • "Upload Using Programmer" is the correct method — never the normal Upload arrow
  • "Burn Bootloader" restores the Optiboot bootloader for USB uploading later

Lab preview

In the next 1.5 hours you will:

  1. Flash ArduinoISP to the Arduino Uno
  2. Wire the 6 ISP connections + capacitor
  3. Upload Blink to the standalone chip
  4. Observe the chip running independently
The Uno board will be the programmer. The bare ATmega328P on the breadboard will be the computer running your sketch.

Lab Block

Flash a Sketch to the Standalone Chip

Goal: ATmega328P blinks an LED from code you put there — no Uno board underneath it

Lab Brief

Goal

Flash a Blink sketch to the standalone ATmega328P using Arduino as ISP. At the end, a bare chip on a breadboard blinks an LED. The Uno board is the programmer, not the computer running the sketch.

Materials per group

  • 1× Arduino Uno R3 (the programmer)
  • 1× ATmega328P-PU with bootloader (the target, on the breadboard)
  • 1× 10 µF electrolytic capacitor
  • 1× LED + 220 Ω resistor
  • Breadboard + jumper wires

Time box

TimeTask
0:00 – 0:15Flash ArduinoISP + wire the boards
0:15 – 0:45Upload Blink, verify, troubleshoot
0:45 – 1:15Extension + debrief
The Arduino Uno is the programmer. The ATmega328P chip on the breadboard is the target. Keep them clearly separated.

Step 1: Flash ArduinoISP to the Arduino Uno

Instructions

  1. Connect the Arduino Uno to your PC via USB
  2. In Arduino IDE: File → Examples → 11.ArduinoISP → ArduinoISP
  3. Confirm Board = Arduino Uno, Port = the Uno's port
  4. Click the normal Upload button ▶ (this is the only time you use the normal upload button today)
  5. Wait for "Done uploading"
  6. Do not unplug the Uno — it stays connected to the PC all session

How to verify it worked

The pin 13 LED on the Uno should now pulse slowly (once every ~1 second). This is the ArduinoISP heartbeat — it means the programmer sketch is running.
If the LED blinks fast or is solid, the sketch did not upload correctly. Repeat step 4.

The ArduinoISP source code deliberately blinks pin 9 (error), pin 8 (programming), and pin 7 (heartbeat) — but on a standard Uno, pin 13 acts as the visible heartbeat indicator.

Step 2: Wire the Boards

Wire in this order (reduces mistakes)

#From (Arduino Uno)To (target ATmega328P)Signal
1GNDDIP pin 8 + pin 22GND first — always
25VDIP pin 7 + pin 20VCC
3Pin 10DIP pin 1RESET
4Pin 13DIP pin 19SCK
5Pin 11DIP pin 17MOSI
6Pin 12DIP pin 18MISO
+cap10 µF: Uno RESET → Uno GND (negative leg to GND)

Chip orientation

Locate the notch on the ATmega328P. The notch marks pin 1 (RESET). All pin numbering counts from here — down one side, back up the other.
The chip must straddle the centre gap of the breadboard. If it does not, opposite pins will be shorted together.

Wiring GND first and VCC second ensures no floating supply lines before data wires are connected.

Pre-Upload Checklist

Hardware checklist

Software checklist

Step 3: Upload Blink and Observe

Upload

  1. Open File → Examples → 01.Basics → Blink
  2. Click Sketch → Upload Using Programmer
  3. Watch the IDE progress bar and the flickering LEDs on the Uno
  4. Wait for "Done uploading" in the IDE output
The LED on DIP pin 19 of the target chip should now blink at 1-second intervals.

Observation questions

  • Which components are currently powering the target chip?
  • Is the target using its own USB connection to run the sketch?
  • What would happen if you disconnected the Uno right now?
  • Which parts of the Uno board are NOT needed for the sketch to run?
The sketch is in flash. Once uploaded, it runs forever — no USB, no PC, no Uno board required on the target.

Troubleshooting Guide

What symptom do you see?

Debug order

  1. Power: Is the target getting 5V from the Uno?
  2. Capacitor: Is the 10 µF cap on the Uno, correct polarity?
  3. Wiring: Check all 6 connections against the table
  4. IDE settings: Programmer = Arduino as ISP, correct port?
  5. ArduinoISP: Is the heartbeat LED pulsing on the Uno?
Read the exact avrdude error message. Each one points to a different cause.

Extension: Burn a Bootloader

What this proves

Any ATmega328P chip — fresh from the factory, blank, or bricked — can have Optiboot burned onto it using exactly this setup. This is how the "bootloaded" chips you purchased were made.

Steps

  1. Keep the ISP wiring exactly as-is
  2. In Arduino IDE: Tools → Burn Bootloader
  3. Wait for IDE output: "Done burning bootloader."
  4. The chip can now receive sketches over USB-to-serial (FTDI adapter) or back in the Uno socket

What happens inside

  • Fuses are written to configure 16 MHz external crystal, correct reset behaviour, and boot flash section size
  • Optiboot hex is written to the Boot Flash Section (last 512 bytes of flash)
  • After reset, the chip checks for a serial upload for ~2 seconds before jumping to the sketch
This is the single highest-value extension: students leave understanding that the bootloader is software that someone installed — using exactly the workflow they just practised.
🔮

Part 2 — External Crystal Clock

Right now your chip is running on its internal RC oscillator. In this part you will wire a 16 MHz crystal and see — and measure — the difference.

Two Ways to Clock the ATmega328P

🕐 Internal RC Oscillator (default)

  • Speed: 8 MHz (factory default)
  • Extra parts: none — it's built in
  • Accuracy: ± 10 % across temperature
  • Fuse (CKSEL): 0010 — set from factory
  • Problem: Arduino IDE expects 16 MHz for an Uno, so delay(1000) actually waits 2 seconds — your blink runs at half speed

💎 External Crystal (target)

  • Speed: up to 20 MHz — we use 16 MHz to match the Uno
  • Extra parts: 1× crystal + 2× 22 pF caps
  • Accuracy: < 50 ppm (< 0.005 %)
  • Fuse (CKSEL): 1111 — set by "Burn Bootloader"
  • Result: delay(1000) = exactly 1 second; millis() / micros() correct
Burning the bootloader does two things: writes Optiboot and sets the fuses to use the external crystal.

What You Need for Part 2

PartValue / TypeQuantityNotes
Crystal oscillator 16 MHz 1 HC-49/S or HC-49/U package — polarity does not matter
Ceramic capacitor 22 pF 2 One on each XTAL pin to GND — keeps oscillation stable
ATmega328P circuit from Part 1 ISP wiring must still be connected for the fuse write step
Keep leads short. The crystal and its caps must be as close to the chip as possible on the breadboard. Long leads pick up noise and can prevent stable oscillation.

Wiring the Crystal

Connection table

ATmega328P PinLabelConnect to
Pin 9 (PB6) XTAL1 Crystal leg 1 and 22 pF cap → GND
Pin 10 (PB7) XTAL2 Crystal leg 2 and 22 pF cap → GND
Order matters: wire the crystal before burning the bootloader. Once the fuses say "external crystal", the chip needs it present to run — if you burn first and add it later the chip will appear dead.

Steps

  1. Keep your Part 1 ISP wiring intact
  2. Insert the crystal across XTAL1 (pin 9) and XTAL2 (pin 10)
  3. Add a 22 pF cap from XTAL1 to GND and another from XTAL2 to GND
  4. In Arduino IDE: Tools → Burn Bootloader
  5. Upload your blink sketch via ISP (Sketch → Upload Using Programmer)
Schematic view

Pin 9 (XTAL1) ─┬─── [Crystal] ───┬─ Pin 10 (XTAL2)
              │                   │
            [22pF]         [22pF]
              │                   │
            GND             GND
Pins 9 and 10 are dedicated crystal pins — they cannot be used as GPIO while an external crystal is connected.

Lab Task: Spot the Difference

The sketch (same both times)

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}
Nothing changes in the code — the only difference is what clock source the chip is using when it runs it.

What to observe

Internal 8 MHzExternal 16 MHz
Actual blink rate~2 s on / 2 s off1 s on / 1 s off ✓
Why?IDE targets 16 MHz; chip runs at half speed, so all delays are doubledClock matches IDE target — timing is accurate
millis()counts at half speedcorrect ✓
Serial baud rategarbled at 9600correct at 9600 ✓
Key takeaway: The Arduino IDE does not auto-detect your clock speed — it trusts the board setting. Using the right crystal locks your hardware to that expectation.

Week 13 Summary

What you proved today

  • ISP communicates over SPI at hardware level — no bootloader, no USB-serial chip required on the target
  • ArduinoISP turns a Uno into a programmer — upload it once, use it all session
  • The 10 µF cap on the programmer RESET is not optional
  • "Upload Using Programmer" bypasses the bootloader — "Burn Bootloader" restores it
Key insight: The ATmega328P does not need the Arduino board. It needs power, clock, and flash contents. You just proved you can put code there with 4 wires.

Exit question

Name one thing the Arduino board was doing for you that the standalone chip cannot do by itself.

Good answers: provide USB communication, provide auto-reset circuit, provide the 5V regulator, provide the bootloader.

Preview: Week 14

Now that we can program the chip with 4 wires — what if we wrote the code without the Arduino framework? No setup(), no loop(), no digitalWrite(). Just C and registers.