# Stand-alone programming AVRs using CircuitPython

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/049/926/medium800/hacks_icon_t.png?1515373660)

If you've ever wanted a _stand alone_ AVR programmer, that is super easy to use, you've come to the right place!

This guide will show you how to turn any CircuitPython powered board with 4+ GPIO pins into an AVR progammer all on its own. **No software like avrdude is needed** , this software will program the chip all on its own, just drag the HEX file onto the CircuitPython disk drive.

Perfect to putting bootloaders on empty chips, or field-reprogramming a project!

# Supported Chips

In theory, any and all AVR chips with SPI-programming interfaces are supported. However, we only have examples for **ATmega328P** chips (used in Arduino compatibles), **ATtiny85** (used in original Trinket/Gemma), and **ATmega2560** (Arduino Mega compatibles)

To program other chips, you'll need to find out the signature, size of the flash, and the flash-page size. You can find this in the datasheet or in `avrdude.conf`

Warning: 

# Stand-alone programming AVRs using CircuitPython

## Wiring

Nearly all AVRs have a 'serial' programming interface, that's what we'll be using to program them. If your chip requires SWD, JTAG or parallel, this software won't work!

In this example we'll show how to wire up an existing Arduino 328P compatible or raw 328P chip to a Feather M0 for programming

For other chips, the wiring is similar, but you'll need to look up which pins are Power, Ground, Reset, and SCK/MOSI/MISO

## Power Pins

Do these pins first because they're easy to forget!

- If connecting to a Arduino-compatible: connect **GND** on the Arduino to **GND** on the Feather. Then either plug the Arduino into USB, or connect the Arduino **5V** to Feather **USB**
- If connecting to a bare chip: connect both **GND** pins together and to the Feather **GND**. Connect **AVCC** to **VCC** to the Feather **3V** pin

Warning: 

# Data Pins

- Connect the **CircuitPython**  **SCK** pin to the target **SCK** (on Uno/Atmega328 this is also known as Digital #13)
- Connect the **CircuitPython**  **MISO** pin to the target **MISO** (on Uno/Atmega328 this is also known as Digital #12)
- Connect the **CircuitPython**  **MOSI** pin to the target **MOSI** (on Uno/Atmega328 this is also known as Digital #11)
- Connect **CircuitPython D5** (or any digital pin, as long as you change the code too) to the target **RESET**

If you are breadboarding a chip, it may need a clock or crystal and it needs to be there to program the chip! If your board has a crystal or oscillator already, skip this. If you're programming a 'raw' ATmega328, you'll want to add it:

- Connect CircuitPython D9 (or any digital pin with PWM out, as long as you change the code to) to the target **XTAL1**

# Wiring Diagram for Raw ATMega328 Chip
![](https://cdn-learn.adafruit.com/assets/assets/000/049/998/medium800/hacks_rawchip.png?1515718660)

[Fritzing for diagram](https://cdn-learn.adafruit.com/assets/assets/000/050/008/original/featherchip.fzz?1515724984)
- **VCC** lines are **Red**
- **Ground/GND** lines are **Black**
- **SCK** is green
- **MOSI** is blue
- **MISO** is yellow
- **RESET** is purple
- **XTAL** is grey

Notice that the notch on the chip is to the _right_ - away from the Feather!

![hacks_328p_pins.png](https://cdn-learn.adafruit.com/assets/assets/000/049/999/medium640/hacks_328p_pins.png?1515718791)

# Wiring for Arduino Compatible
![](https://cdn-learn.adafruit.com/assets/assets/000/050/000/medium800/hacks_unoprog.png?1515719126)

[Fritzing for diagram](https://cdn-learn.adafruit.com/assets/assets/000/050/009/original/featheruno.fzz?1515725024)
For Arduino UNO and compatibles, we recommend powering from USB or DC power. Then connect **GND** pins together, and wire up&nbsp; **Reset** , **SCK** , **MOSI** , and **MISO** as seen above.

**XTAL** pin is not required, Arduinos have on-board crystals.

# Stand-alone programming AVRs using CircuitPython

## Software Setup

# Installing Library

To use the AVR programming library you'll need to install the&nbsp;[Adafruit CircuitPython AVRprog](https://github.com/adafruit/Adafruit_CircuitPython_AVRprog) library on your CircuitPython board.

First make sure you are running the&nbsp;[latest version of Adafruit CircuitPython](../../../../welcome-to-circuitpython/installing-circuitpython)&nbsp;for your board.

Next you'll need to install the necessary libraries&nbsp;to use the hardware--carefully follow the steps to find and install these libraries from&nbsp;[Adafruit's CircuitPython library bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle).&nbsp; Our introduction guide has&nbsp;[a great page on how to install the library bundle](../../../../welcome-to-circuitpython/circuitpython-libraries)&nbsp;for both express and non-express boards.

Remember for non-express boards like the Trinket M0, you'll need to manually install the necessary library from the bundle:

- **adafruit\_avrprog.mpy**

You can also download the&nbsp; **adafruit\_avrprog.mpy** &nbsp;from&nbsp;[its releases page on Github](https://github.com/adafruit/Adafruit_CircuitPython_AVRprog/releases).

Before continuing make sure your board's lib folder or root filesystem has the&nbsp; **adafruit\_avrprog.mpy** file copied over.

![](https://cdn-learn.adafruit.com/assets/assets/000/049/927/medium800/hacks_lib.png?1515373870)

Next&nbsp;[connect to the board's serial REPL&nbsp;](../../../../welcome-to-circuitpython/the-repl)so you are at the CircuitPython&nbsp; **\>\>\>** &nbsp;prompt.

Info: 

## Imports

You'll need to import a few libraries

- `board` - for assigning hardware pins
- `busio` - we use SPI bus to talk to the target device
- `adafruit_avrprog` - the library that we're using!

```auto
>>> import board
>>> import busio
>>> import adafruit_avrprog
```

![](https://cdn-learn.adafruit.com/assets/assets/000/049/928/medium800/hacks_imports.png?1515374293)

## Initialize hardware

Next, create the hardware interface, you'll need an SPI port and one extra pin for the reset line. We'll use `board.D5` to match our diagrams on the previous page, but it can be _any_ pin you like!

```auto
>>> spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
>>> avrprog = adafruit_avrprog.AVRprog()
>>> avrprog.init(spi, board.D5)
```

## Communication / Signature Check

Next we'll verify that we can talk to the chip, once that works we are best off crafting our programmer into a full **main.py** project but at least we can quickly determine if things worked out.

1. Start by initializing the programming interface with `avrprog.begin()` which will pull the **reset** line low and send some commands to get the chip to listen.
2. Then read the signature, you'll get an array of numbers - its probably best to turn this into hex values before printing since they're referred to as hex values in datasheets.
3. Finally, call `avrprog.end()`

```auto
>>> avrprog.begin()
>>> [hex(i) for i in avrprog.read_signature()]
['0x1e', '0x95', '0xf']
>>> avrprog.end()
```

![](https://cdn-learn.adafruit.com/assets/assets/000/049/930/medium800/hacks_sigtest.png?1515374642)

You can see here we have a 0x1E950F chip attached, also known at an **ATmega328P**

# Full Example

You can save this code to **main.py** and use the REPL to see the signature data, it also includes the code for setting up the crystal-driving PWM output

https://github.com/adafruit/Adafruit_CircuitPython_AVRprog/blob/main/examples/avrprog_read_signature_simpletest.py

## SPI / Wiring Errors

If something went wrong, you'll get an `SPI transaction failed` exception. Check your wiring! Also, sometimes the chip doesn't quite hear us, try connecting again.

**Common problems:**

- The target isn't powered - make sure it is powered via USB or via the CircuitPython board. A shared Ground wire is _required_
- Make sure you have the reset pin on the target connected to whatever pin you setup when you created the `avrprog` object
- On ATmega2560, MOSI and MISO are connected opposite than the way you think. Either way, its OK to try swapping those two wires, see if that helps!
- The target is expecting a crystal but you don't have one, for example the UNO bootloader requires that the chip have a crystal or oscillator connected up, it's not optional!

# Stand-alone programming AVRs using CircuitPython

## Programming Chips

OK now that you've read the signature, you can write some code!

[We have a few examples available you can use 'out of the box' - all are available here](https://github.com/adafruit/Adafruit_CircuitPython_AVRprog/tree/master/examples). You can [download the library zip to get all the files](https://github.com/adafruit/Adafruit_CircuitPython_AVRprog/archive/master.zip). For each programming demo, we also have a matching 'hex' file, that's a requirement - it's the file you'll be programming into the chip!

Copy the programming sketch into **main.py** and also grab the matching hex file. For example:

```auto
"""
UNO Optiboot programming example, be sure you have the UNO wired up so:
  UNO Ground to CircuitPython GND
  UNO 5V to CircuitPython USB or make sure the UNO is powered by USB
  UNO Pin 13 -> CircuitPython SCK
  UNO Pin 12 -> CircuitPython MISO
  UNO Pin 11 -> CircuitPython MOSI
  UNO RESET  -> CircuitPython D5 (or change the init() below to change it!)
Drag "optiboot_atmega328.hex" onto the CircuitPython disk drive, then open REPL!
"""
```

Indicates you need **optiboot\_atmega328.hex**

![](https://cdn-learn.adafruit.com/assets/assets/000/050/007/medium800/hacks_files.png?1515722077)

Then run the REPL and look for the `Ready to GO, type 'G' here to start >` prompt and type the letter G into the REPL. You should see the code begin by checking the identity of the chip (the signature), erasing the chip, then programming it.

![](https://cdn-learn.adafruit.com/assets/assets/000/050/001/medium800/hacks_flash_start.png?1515720290)

It will skip most of the flash 'pages' because they're empty. At the end you'll get to the pages that are flashed and verified:

![](https://cdn-learn.adafruit.com/assets/assets/000/050/002/medium800/hacks_flashdone_verified.png?1515720332)

It's very very rare for something to go wrong during verification. But if it does you'll see something like this. Just start over by hitting ^C and ^D in the REPL to begin again.

![](https://cdn-learn.adafruit.com/assets/assets/000/050/003/medium800/hacks_verifyfail.png?1515720410)

That's it! You've programmed the chip. For more details, keep reading.

# Stand-alone programming AVRs using CircuitPython

## AVRprog API

# Defining Chips

Before you can really do anything you need to tell AVRprog library what the chip is. We'll use a python dict for that. Define **name** (that's for your information and printing errors), **sig** - a list of the three-byte signature, **flash\_size** - the size of the flash memory in _bytes_, **page\_size** - the size of each flash memory _page in_ bytes, and **fuse\_mask** - a list of the four fuses in a list `[low, high, ext, lock]`

Fuse mask is the oddest one, but basically it defines which bits are actually used in each fuse. For example, the ext fuse is often only the bottom three bits, so its **0x07**. If you're not sure, you can set all four to **0xFF** and then when you burn fuses, set all the high bits to 1.

Here are some chip examples:

```auto
attiny85 = {'name': "ATtiny85"}
attiny85['sig'] = [0x1E, 0x93, 0x0B]
attiny85['flash_size'] = 8192
attiny85['page_size'] = 64
attiny85['fuse_mask'] = (0xFF, 0xFF, 0x07, 0x3F)
```

```auto
atmega328p = {'name': "ATmega328P"}
atmega328p['sig'] = [0x1E, 0x95, 0x0F]
atmega328p['flash_size'] = 32768
atmega328p['page_size'] = 128
atmega328p['fuse_mask'] = (0xFF, 0xFF, 0x07, 0x3F)

```

```auto
atmega2560 = {'name': "ATmega2560"}
atmega2560['sig'] = [0x1E, 0x98, 0x01]
atmega2560['flash_size'] = 262144
atmega2560['page_size'] = 256
atmega2560['fuse_mask'] = (0xFF, 0xFF, 0x07, 0x3F)
```

# Verify Signature

`avrprog.verify_sig(chip_dict, verbose=True)`

We suggest calling this first, you can call it whenever you like, and it will return True/False. `chip_dict` is that dictionary you made above

# Erasing Chip

This one is easy, just call` avrprog.erase_chip()` - the chip erase command is the same for all chips. It may take a second on bigger chips. **You must do this before programming new firmware!**

Also, if your chip has the lock-firmware-fuse set, you may have to erase the flash before you can change the lock fuse.

# Fuses

You can read, write and verify fuses.

**Read fuses** with

`avrprog.read_fuses(chip_dict)`

Which will return a list of the four fuses [low, high, ext, lock]

**Write fuses** with

`avrprog.write_fuses(chip_dict, low=0xll, high=0xhh, ext=0xee, lock=0xkk)`

Only arguments that are passed in will be written, so you can choose to write one fuse, or all 4.

**Verify fuses** with

`avrprog.verify_fuses(chip_dict, low=0xll, high=0xhh, ext=0xee, lock=0xkk)`

Only arguments that are passed in will be verified, so you can choose to verify one fuse, or all 4.

# Flash

OK this is the good part, here's how you can write and verify flash memory. Reading memory to disk is not supported yet!

`avrprog.program_file(chip_dict, "filename.hex", verbose=True, verify=True)`

This function does all the work really, give it the chip information dictionary, and the name of a file (full path is OK). If `verify` is True, it will verify each page manually after writing. This is way faster than writing the whole file and then verifying the whole file so we recommend it.

If you really want, you can also verify against a file with:

`verify_file(chip_dict, "filename.hex", verbose=True)`

**But** it will check every single byte of the flash chip, so for example, if its a sparse hex file, like most bootloaders are where only a small portion of flash is data and the rest is empty, the empty parts are still checked. So it's very slow!

# EEPROM

Not supported at this time!


## Featured Products

### Circuit Playground Express

[Circuit Playground Express](https://www.adafruit.com/product/3333)
 **Circuit Playground Express** is the next step towards a perfect introduction to electronics and programming. We've taken the original Circuit Playground Classic and made it even better! Not only did we pack even more sensors in, we also made it even easier to...

In Stock
[Buy Now](https://www.adafruit.com/product/3333)
[Related Guides to the Product](https://learn.adafruit.com/products/3333/guides)
### Adafruit Trinket M0 - for use with CircuitPython & Arduino IDE

[Adafruit Trinket M0 - for use with CircuitPython & Arduino IDE](https://www.adafruit.com/product/3500)
The&nbsp;Adafruit Trinket M0 may be small, but do not be fooled by its size! It's a tiny microcontroller board, built around the Atmel ATSAMD21, a little chip with _a lot_ of power. We wanted to design a microcontroller board that was small enough to fit into any project, and low...

In Stock
[Buy Now](https://www.adafruit.com/product/3500)
[Related Guides to the Product](https://learn.adafruit.com/products/3500/guides)
### Adafruit METRO M0 Express - designed for CircuitPython

[Adafruit METRO M0 Express - designed for CircuitPython](https://www.adafruit.com/product/3505)
Metro is our series of microcontroller boards for use with the Arduino IDE. This new **Metro M0 Express** board looks a whole lot like our&nbsp;[original Metro 328](https://www.adafruit.com/product/2488), but with a huge upgrade. Instead of the ATmega328, this Metro...

Out of Stock
[Buy Now](https://www.adafruit.com/product/3505)
[Related Guides to the Product](https://learn.adafruit.com/products/3505/guides)
### Adafruit Feather M0 Express

[Adafruit Feather M0 Express](https://www.adafruit.com/product/3403)
At the Feather M0's heart is an ATSAMD21G18 ARM Cortex M0+ processor, clocked at 48 MHz and at 3.3V logic, the same one used in the new&nbsp;[Arduino Zero](https://www.adafruit.com/products/2843). This chip has a whopping 256K of FLASH (8x more than the Atmega328 or 32u4) and...

In Stock
[Buy Now](https://www.adafruit.com/product/3403)
[Related Guides to the Product](https://learn.adafruit.com/products/3403/guides)

## Related Guides

- [Adafruit Feather M0 Express](https://learn.adafruit.com/adafruit-feather-m0-express-designed-for-circuit-python-circuitpython.md)
- [Adafruit Metro M0 Express](https://learn.adafruit.com/adafruit-metro-m0-express.md)
- [Adafruit Trinket M0](https://learn.adafruit.com/adafruit-trinket-m0-circuitpython-arduino.md)
- [Adafruit Circuit Playground Express](https://learn.adafruit.com/adafruit-circuit-playground-express.md)
- [Game Clock with Circuit Playground & MakeCode](https://learn.adafruit.com/game-clock-with-circuit-playground-makecode.md)
- [Infrared Receive and Transmit with Circuit Playground Express](https://learn.adafruit.com/infrared-ir-receive-transmit-circuit-playground-express-circuit-python.md)
- [How to Program SAMD Bootloaders](https://learn.adafruit.com/how-to-program-samd-bootloaders.md)
- [DAC Hacks for Circuit Playground Express & other ATSAMD21 Boards](https://learn.adafruit.com/circuit-playground-express-dac-hacks.md)
- [Dance-Reactive Tutu Sparkle Skirt](https://learn.adafruit.com/dance-reactive-tutu-sparkle-skirt.md)
- [Trinket / Gemma Mini-Theremin](https://learn.adafruit.com/trinket-gemma-mini-theramin-music-maker.md)
- [Esenciales para CircuitPython](https://learn.adafruit.com/esenciales-para-circuitpython.md)
- [Using WebUSB with Arduino and TinyUSB](https://learn.adafruit.com/using-webusb-with-arduino-and-tinyusb.md)
- [UART Communication Between Two CircuitPython Boards](https://learn.adafruit.com/uart-communication-between-two-circuitpython-boards.md)
- [NeoTrellis Game](https://learn.adafruit.com/neotrellis-box-game.md)
- [3D-Printed Bionic Eye](https://learn.adafruit.com/3d-printed-bionic-eye.md)
- [Makecode para la Circuit Playground Express](https://learn.adafruit.com/makecode-es.md)
- [Pushrod Garage](https://learn.adafruit.com/pushrod-garage.md)
- [How to Choose a Microcontroller](https://learn.adafruit.com/how-to-choose-a-microcontroller.md)
- [Installing Microsoft MakeCode for Adafruit](https://learn.adafruit.com/installing-makecode-for-adafruit.md)
