DE6417 Microcontrollers 2 · Week 13
Everything on the Arduino board around the ATmega328P chip exists to make programming convenient — not to run your final product.
| Approach | Hardware needed |
|---|---|
| Arduino as ISP | Another Arduino Uno running a sketch |
| Dedicated ISP programmer | USBasp, AVRISP mkII, Atmel-ICE |
| Bootloader + USB-serial adapter | FTDI adapter; bootloader must be burned first |
| Bootloader + Uno as carrier | Remove the Uno's chip, seat the target chip in its socket |
| JTAG / debugWIRE | Atmel-ICE; adds hardware debugging |
| Component | Value / Type | Qty | Part |
|---|---|---|---|
| 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 |
Explain the ISP protocol and how it differs from the bootloader upload path.
Flash the ArduinoISP sketch to a Uno and configure the IDE correctly.
Connect all 6 ISP lines between the programmer Uno and the target chip.
Upload a sketch to the standalone chip and observe it running independently.
ISP writes directly to flash. The chip does not need to be running any code.
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.
| Signal | Port / Pin | Physical DIP Pin |
|---|---|---|
| MOSI | PB3 | 17 |
| MISO | PB4 | 18 |
| SCK | PB5 | 19 |
| RESET | PC6 | 1 |
Same pins as SPI — students already know these from earlier in the course.
| Target signal | Programmer Uno pin | Direction | Purpose |
|---|---|---|---|
| MOSI | D11 / COPI (Controller Out, Peripheral In) | Master → Slave | Programming data to target |
| MISO | D12 / CIPO (Controller In, Peripheral Out) | Slave → Master | Status and verify data back |
| SCK | D13 / SCK (same name) | Master → Slave | Clock — synchronises every bit |
| RESET (PC6, pin 1) | D10 / SS (repurposed to drive target RESET) | Master → Slave | Hold LOW to enter programming mode |
MISO direction is from the slave's perspective — data comes back from the target to confirm what was written.
| Programmer Uno Pin | Signal | Target ATmega328P DIP Pin | Note |
|---|---|---|---|
| Pin 10 | RESET | Pin 1 (PC6) | Pulls target into programming mode |
| Pin 11 | MOSI | Pin 17 (PB3) | Data out from programmer |
| Pin 12 | MISO | Pin 18 (PB4) | Data back from target |
| Pin 13 | SCK | Pin 19 (PB5) | Also the programmer Uno's onboard LED — it flickers during upload (normal) |
| 5V | VCC | Pin 7 + Pin 20 | Power the target from the programmer |
| GND | GND | Pin 8 + Pin 22 | Common ground — connect all GND pins |
| + 10 µF capacitor on programmer Uno: RESET → GND (negative to GND) | |||
| # | Menu path | What to select |
|---|---|---|
| 1 | Tools → Board | Arduino Uno — the target type, not the programmer |
| 2 | Tools → Port | The COM/tty port of the Arduino Uno |
| 3 | Tools → Programmer | Arduino as ISP |
| 4 | Upload method | Sketch → Upload Using Programmer |
IDE calls avr-gcc. Your sketch becomes a .hex file in a temp folder.
IDE calls avrdude -c stk500v1 -b 19200. Opens serial to the programmer Uno.
Programmer Uno receives hex bytes over UART, translates them into SPI transactions.
SPI clocks data into target flash, one page at a time. avrdude reads back and verifies every byte.
| Operation | How | What it does | When 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 |
In the next 1.5 hours you will:
Goal: ATmega328P blinks an LED from code you put there — no Uno board underneath it
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.
| Time | Task |
|---|---|
| 0:00 – 0:15 | Flash ArduinoISP + wire the boards |
| 0:15 – 0:45 | Upload Blink, verify, troubleshoot |
| 0:45 – 1:15 | Extension + debrief |
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.
| # | From (Arduino Uno) | To (target ATmega328P) | Signal |
|---|---|---|---|
| 1 | GND | DIP pin 8 + pin 22 | GND first — always |
| 2 | 5V | DIP pin 7 + pin 20 | VCC |
| 3 | Pin 10 | DIP pin 1 | RESET |
| 4 | Pin 13 | DIP pin 19 | SCK |
| 5 | Pin 11 | DIP pin 17 | MOSI |
| 6 | Pin 12 | DIP pin 18 | MISO |
| +cap | 10 µF: Uno RESET → Uno GND (negative leg to GND) | ||
Wiring GND first and VCC second ensures no floating supply lines before data wires are connected.
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.
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.
0010 — set from factorydelay(1000) actually waits 2 seconds — your blink runs at half speed1111 — set by "Burn Bootloader"delay(1000) = exactly 1 second; millis() / micros() correct| Part | Value / Type | Quantity | Notes |
|---|---|---|---|
| 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 |
| ATmega328P Pin | Label | Connect 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 |
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
}
| Internal 8 MHz | External 16 MHz | |
|---|---|---|
| Actual blink rate | ~2 s on / 2 s off | 1 s on / 1 s off ✓ |
| Why? | IDE targets 16 MHz; chip runs at half speed, so all delays are doubled | Clock matches IDE target — timing is accurate |
| millis() | counts at half speed | correct ✓ |
| Serial baud rate | garbled at 9600 | correct at 9600 ✓ |
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.