Programming Bare AVR Chips: ATtiny85, ATtiny84, and ATmega328P with Fuses and ISP
An Arduino Uno is a great way to develop firmware and a wasteful way to deploy it. Once a project is working, most of that board — the USB-to-serial chip, the voltage regulator, the reset circuitry, the giant footprint — is dead weight if all you need is one ATmega328P running a known-good sketch in a permanent enclosure. Programming bare AVR chips directly lets you build projects around a $2-3 microcontroller instead of a $20+ dev board, at the cost of a slightly steeper setup process. This guide covers the chips worth knowing, in-system programming (ISP), and the fuse bits that trip up almost everyone the first time.
Choosing a Chip
ChipPinsFlash / RAMBest For ATtiny858-pin DIP/SOIC, 5 usable I/O8KB / 512BBlinking LEDs, simple sensors, tiny standalone gadgets ATtiny8414-pin, 11 usable I/O8KB / 512BSame as ATtiny85 with more I/O for buttons/displays ATmega328P28-pin DIP/TQFP, 20 usable I/O32KB / 2KBAnything you'd otherwise reach for an Uno for — this is the chip on the UnoThe DIP package versions of all three are breadboard and perfboard friendly, which matters more than it sounds like when you're prototyping without a custom PCB.
ISP Programming Basics
In-System Programming uses SPI to write flash memory directly, without needing a bootloader. Four signals matter: MOSI, MISO, SCK, and RESET (pulled low during programming), plus power and ground. Every ISP programmer — whether it's a dedicated device or an Arduino running as one — presents the same six-pin header (or equivalent wiring) to the target chip.
Using an Arduino as an ISP Programmer
You don't need to buy a programmer to get started — any Arduino board can become one:
- In the Arduino IDE, open File > Examples > 11.ArduinoISP > ArduinoISP and upload it to your Uno (or similar board).
- Wire the Uno's pins 10, 11, 12, 13 to the target chip's RESET, MOSI, MISO, and SCK respectively, and add a 10µF capacitor between the Uno's RESET and GND to prevent it from auto-resetting during programming.
- In Tools > Programmer, select "Arduino as ISP," then use Tools > Burn Bootloader (which also sets fuses) or Sketch > Upload Using Programmer to flash your actual sketch directly, bootloader-free.
- Install board definitions for ATtiny chips via the Boards Manager (the "ATTinyCore" or "attiny by David A. Mellis" package covers the 85/84) so they appear in the board list.
Dedicated ISP Programmers
Once you're doing this regularly, a dedicated USB programmer is faster and frees up an Arduino. A USBasp (cheap, avrdude-native) or a Pocket AVR Programmer both work well and show up directly in the IDE's programmer list or as an avrdude target from the command line.
Fuse Bits Explained
Fuses are non-volatile configuration bits separate from your program flash — they set the clock source, brown-out detection threshold, and whether the reset pin can be reused as GPIO, among other things. They're the part of bare-chip programming that catches people out, because a wrong fuse write can make the chip unresponsive to further ISP programming.
SettingWhat It ControlsCommon Trap Clock source (CKSEL)Internal RC oscillator vs external crystalSetting external clock fuses with no crystal wired makes the chip appear "bricked" — it's waiting for a clock signal that doesn't exist Brown-out detection (BODLEVEL)Voltage threshold below which the chip resets to avoid corrupt executionDisabling it saves a little power but risks flash corruption on marginal supplies RSTDISBLFrees the RESET pin as a normal GPIO pinOnce set, ISP programming (which needs RESET) no longer works — you need a high-voltage programmer to undo it. Avoid this fuse unless you have a specific pin-count need and a recovery plan SELFPRGENEnables the chip to write its own flash (bootloader support)Not needed for ISP-only workflowsThe Arduino IDE sets sensible default fuses automatically when you select a board and clock speed and use "Burn Bootloader" (which, for ISP-only use, is really just "burn fuses" — no actual bootloader is required). If you want to set fuses manually with avrdude, use an online AVR fuse calculator to translate desired settings into the low/high/extended fuse byte values rather than hand-computing them — the bit-to-feature mapping differs across chip families and is easy to get backwards.
Bootloader vs No Bootloader
A bootloader (like the one on an Uno) lets you re-flash the chip over serial/USB without a separate programmer, at the cost of flash space and a short boot delay. For a permanent, single-purpose project, skip the bootloader entirely and upload directly via ISP — it's faster, uses all available flash, and there's no reason to keep serial-reflash capability in a device you're not planning to update in the field.
Practical Example: Standalone ATtiny85 Blink Circuit
With the ATtiny85 in a breadboard: pin 1 (RESET/PB5) to your programmer's RESET line, pin 4 to GND, pin 8 to 5V (with a 0.1µF decoupling capacitor across power and ground), pins 5-7 (PB0-PB2) to your programmer's MOSI, MISO, SCK. Select "ATtiny85" and the correct clock option in the IDE, burn bootloader once to set fuses, then upload a standard Blink sketch modified to use pin 3 (PB3/PB4, whichever you've wired an LED to) instead of pin 13. That same wiring pattern — power, decoupling cap, four ISP lines — is what you'll reuse in a permanent perfboard or custom PCB build.
Troubleshooting
- "Programmer not responding" / sync errors — check the decoupling capacitor on the Arduino-as-ISP's RESET line, verify wiring, and confirm the target chip has power.
- Chip stops responding after a fuse change — if you set an external clock fuse without a crystal, or disabled RESET as GPIO, standard ISP won't reach it anymore. Recovery requires either wiring the correct external clock source temporarily, or a high-voltage parallel programmer (several open-source designs exist using another Arduino) to force fuses back to defaults.
- Sketch uploads but doesn't run — double check you selected the correct clock speed in the IDE; a sketch compiled assuming 16MHz will run at the wrong timing (including wrong Serial baud rate) on a chip fused for its default 1MHz internal oscillator.
A Word of Caution
Fuse bits are the one part of this workflow with a real "brick it" risk. Change one fuse at a time when experimenting, keep a note of your chip's default fuse values before changing anything, and avoid RSTDISBL entirely unless you specifically need that GPIO pin and have a high-voltage programmer on hand as a fallback.
Once the ISP wiring and fuse concepts click, bare-chip AVR programming turns a $20 dev board habit into a $2-3 chip habit for anything that doesn't need WiFi or the horsepower of an ESP32 — simple sensors, blinking status indicators, and small standalone gadgets that just need to run one job reliably in a tiny footprint.
Related Guides
- Raspberry Pi Pico — First Steps with MicroPython
- Arduino vs ESP32: Which Should You Use? A Practical Comparison
- Getting Started with ESP32: GPIO, WiFi, and Your First Project
- Choosing the Right ESP32 Variant: ESP32, S2, S3, C3, and C6 Compared
- CircuitPython for Makers: Getting Started on ESP32 and Raspberry Pi Pico