Thursday, August 4, 2022

Tutorial on how to program an AVR ATmega328PB microcontroller using Atmel Studio and a bootloader

In this tutorial you will be learning how to use Microchip Studio (previously known as Atmel Studio) to program an AVR microcontroller over UART using the Optiboot bootloader. The hardware necessary is very inexpensive. All you need is an ISP (In System Programming) module such as USBTinyISP (around 3$) and an USB to Serial adapter that is around the same price and you can even build it yourself if you wish.


  1. Hardware requirements
  2. Burning the Optiboot Bootloader
  3. Programming the ATmega328PB using the Boot Loader, FTDI adapter and Microchip Studio

Hardware requirements

ISP module such as USBTinyISP, USBASP.

Burning Optiboot bootloader using USBtinyISP

USB to Serial adapter also known as FT232 module, USB to TTL. If you wish to build one yourself you can find a tutorial here

Programming ATmega328PB using a bootloader

A microcontroller: in this tutorial I will be using ATmega328PB but the concepts apply to other microcontrollers as well.


Burning the Optiboot Bootloader

Initially an AVR microcontroller can be programmed over SPI using the pins called MOSI, MISO, SCK and RESET. But most often you will need to transfer data from PC to microcontroller and vice-versa, using UART, for debugging purposes or data logging. That will require two modules - one for ISP and one for Serial - and that is not optimal. By using a bootloader the UART can be used for both programming and PC interface.

A bootloader is just some code that resides in a special area of the flash memory that can accept the application code over UART and write it on the application flash section.

There are many bootloaders but in this tutorial I will be using this Optiboot version because it has auto baud rate detection so you can use any speed to upload the code and has compiled files for ATmega328P and ATmega328PB. The make file can be modified for other types of microcontrollers and CPU frequencies but that requires some knowledge on the topic.

To upload the bootloader we will be using the latest version of avrdude for Windows. Note that if you have WinAVR installed, the PATH must be modified so it can use this version instead the one that comes with WinAVR. This is because the WinAVR uses an older version. The second reason and most important is that this version is compiled using libftdi that adds support for FTDI devices.

After downloading avrdude, extract the files in a folder of your choice.

Adding avrdude to Windows System PATH

For easy access of avrdude when using command prompt and Microchip Studio, first we need to let Windows know where avrdude executable is located. To do this press the Windows key or Start button and type "path". Now you should see "Edit the system environment variables". Clicking on the result will open the System Properties window in the Advanced tab. Next click on Environment Variables.

Adding avrdude to System PATH

In the second box select Path and click Edit then New and paste the path to the folder where avrdude is located. To obtain the folder path, navigate to the folder and right click on the folder name in the top navigation bar and select Copy address as text.

To check if Windows can find avrdude, press Windows key then type "cmd" and click on Command Prompt. Finally, type avrdude and press enter. Now you should see a list of available avrdude options.

Uploading the bootloader using SPI

The next step is to upload the Optiboot bootloader using an ISP module connected to SPI and the good old avrdude that can be accessed using the executable name and some arguments in a Command Prompt window. The cmd window must be opened from where the Optiboot hex files are so the avrdude can find them. To do this navigate to the Optiboot folder, pres CTRL+L then type cmd and press enter.

The avrdude parameters for ATmega328PB are:

avrdude -c usbtiny -B 10 -p atmega328pb -e -U flash:w:optiboot_m328pb.hex:i -U lfuse:w:0xFF:m -U hfuse:w:0xD2:m -U efuse:w:0xFF:m -U lock:w:0xCF:m

avrdude - the executable name

-c - programmer type. Here I use usbtiny. Type avrdude -c ? for a list of available programmers.

-B - bit clock period in us. Programming speed. A value of 10 works fine for a 16MHz crystal.

-p - AVR device.

-e - perform a chip erase.

-U - used to read/write the chip.

  • flash indicates the memory type.
  • w means we want to write that location instead of reading (r). 
  • After w: is the name of the hex file that you want to write to the microcontroller and in this case is the bootloader. Make sure you select one for your particular microcontroller. The versions that have _blink in the filename will blink a led to indicate that the bootloader works. If this is not an Arduino board, you need to connect the led through a resistor to the pin that will be toggling. The pin depends on the microcontroller and for ATmega328PB the pin was PB5.

The fuses

It is very important that you select the right fuse settings as wrong settings can make the microcontroller unusable unless you have a high voltage programmer. There are 4 fuse types: low fuse, high fuse, extended fuse and lock fuse denoted as: lfuse, hfuse, efuse and lock. I have used this site to calculate the fuse bits for the ATmega328PB that are used in the above command. On the website there is no ATmega328PB but ATmega328P works too.

The description of the fuse bits are as follows:

  • divide clock by 8 is disabled
  • the CPU clock is sourced from external crystal greater than 8MHz (16MHz in this case)
  • 512 words are allocated for the bootloader and the boot start address is $3E00
  • 1024 words are allocated for the bootloader and the boot start address is $3C00. After some time the bootloader was getting corrupted and I believe that 512 words wasn't enough
  • Boot Reset Vector enabled
  • Preserve EEPROM memory through the chip erase (optional)
  • Serial program downloading (SPI) enabled
  • Watch-dog Timer disabled (optional)
  • Brown-out detection disabled (optional)
  • Boot loader protection mode 3: LPM and SPM prohibited in Boot Loader section. This is to prevent the application code modifying the boot loader from what I understand.

If you are using a different microcontroller or other fuse bits settings you need to update the fuse hex values with the ones obtained from the online calculator. Now all you have to do is to paste the command in the cmd window and press enter to burn the boot loader. If everything was successful, now you can program the microcontroller using the UART instead of SPI.

Programming the ATmega328PB using the Boot Loader, FTDI adapter and Microchip Studio

Microchip Studio (previously known as Atmel Studio) is a very good platform for programming AVR devices and not only. Since it's a very feature-rich application, it can be overwhelming for a beginner but if you focus only on what you need it's very easy to use.

Wiring the USB to Serial

The pin port and numbers where the UART is located can be found in the datasheet in the "Pin Configurations" chapter.

ATmega328PB pin configurations

On ATmega328PB the transmit pin (TXD0) is on PD1 and receive pin (RXD0) is on PD0. Connect TXD0 to RX on the serial module and RXD0 to TX of the module. The DTR pin of the serial adapter must be connected to the Reset pin of the microcontroller through a 100n capacitor. When the DTR is pulled low it will reset the microcontroller, then the bootloader will be ready to accept the application code.

Creating a new project inside the Microchip Studio

A new project can be created using the File -> New -> Project.

Microchip Studio tutorial 01

Here, select GCC C Executable Project, select the desired folder location and give it a name.

In the next step search for atmega328pb and select it from the list.

Microchip Studio tutorial 02

That's it! After pressing OK the project will be created. In the Solution Explorer window you can open the project files or create new ones. For now we only have the main.c and as the name suggests is the main file that will include other files. The main.c has a function called main and inside is a while loop.

int main(void){


When the microcontroller starts, the code will be executed from top to bottom. The while loop will run as long 1 is 1 which means forever. Before the loop you usually put initialization functions or code that must run only once after the microcontroller starts.

Blinking a led code

First choose a port and pin where to connect the led. Then that pin must be set as output high or low. More on configuring the microcontroller pins can be found here.

Assuming the led in on port B pin 4 the code looks like this:

#include <avr/io.h>
#include <util/delay.h>

int main(void){
    PORTB |= (1 << PB4);
    DDRB |= (1 << PB4);
	PORTB ^= (1 << PB4);

Pin 4 of port B is set to 1 (high) and data direction register is also set to 1 (meaning output) for pin 4 keeping the rest of the pins as they were. Then in the while loop the pin is toggled - if it is low it will be high and if it's high it will be low. Between each toggle there is a delay of 1000 milliseconds.

Compiling the code

To generate the hex file use the Build -> Build Solution or just press F7. The Output window should open with the warning message that the F_CPU is not defined and that is because the delay.h needs to know our CPU frequency in order to calculate how many CPU cycles of do-nothing to count. You will find out that this define will be needed by many other libraries so let's define it like so:

#define F_CPU    16000000 // 16MHz

This must be placed before the includes. Now the output window should look like this:

Microchip Studio tutorial 03

Notice that we have used 248 bytes of flash memory and 0 bytes of SRAM.

Uploading code to microcontroller over UART

The standard way is to use a programmer from Atmel and that way you can benefit from many features such as debugging, burning fuses, seeing the code execution in real time, adding code break points, etc. But if you only have a cheap USB to Serial and want to experiment with it, you can still use it with Microchip Studio by using the External Tools.

To add an external tool use Tool - > External Tools:

Microchip Studio tutorial 04

If you have added tools previously, they will appear above External Tools. This list is available for all projects so make sure you add a suggestive name that indicates the programmer type, microcontroller and whether is for the Debug or Release folder.

Microchip Studio tutorial 05
  • Title is the desired name of the custom programming tool. 
  • Command: application used for programming - avrdude.exe.
  • Arguments: arguments for avrdude.

-c arduino -p atmega328pb -P COM3 -b 115200 -U flash:w:$(ProjectDir)Debug\$(TargetName).hex:i

c: programmer type. I use a custom module made using the FT232 ic but none of the programmers that had FTDI in the name worked for me except for arduino. Don't know why it works but it does.

P : the USB port where the programmer is. Use Device Manager in Windows and check the Ports with the programmer plugged in to see the port number. Mine was on COM3.

b: UART baud rate

For the Release folder, replace Debug with Release. Also be sure to check the "Use Output Window" to be able to see the output from avrdude in the Microchip Studio output window.

That's it. Now you can upload the code over UART just by pressing on the external tool that you have created.

Share it if you like it!

No comments:

Post a Comment