ATMEGA32U4 Dev Board

ATMEGA32U4 Development Board

The ATMEGA32U4 is the microprocessor used on the Arduino Leonardo boards. The board has 20 GPIO pins available.

The goal with this project is to build a development board with the ATMEGA32U4 chipset that can be integrated with a breadboard and enable the access to 2 additional GIPO pins (a total of 22 GPIO pins).

Besides having access to the 22 GPIO pins, we need to include the ISP programmer connector, a crystal, and a USB connector. The fuse and ESD protection are good practice to have in your designs but you can remove these modules if you want to design a more compact or cheap version of this board.

We can find some schematics online to support the new design. For example, Sparkfun developed an ATMEGA32U4 Breakout in the past. We can use this design as a starting point and incorporate additional features.

This stage might not be possible to do for some projects, but if possible, it is always good to test the components first before building the PCB.

Schematics (Zoom)

Layout (Zoom)

3D Rendering

3D PCB + Breadboard (Fusion360)

Interactive BOM (Link)

The boards were manufactured by PCBWay.

Assembled in house.

The ATMEGA32U4 chip doesn't come with the USB bootloader flashed in it. We need to flash it using the AVRDUDE software and an AVR programmer.

AVR Programmer

I am using the USBtinyISP AVR Programmer Kit (Link) by Adafruit.

I installed the AVR Programmer driver (Link) and the AVRDUDE software (Link).

AVRDUDE

AVRDUDE is a very popular command-line programmer for programming AVR chips. I follow this article to get familiar with the commands.

Flash the USB Bootloader

  • Connect the 6 pin cable from the USBtinyISP AVR Programmer to your board first.
  • Then connect the USB type B cable to your computer (following this order is important)
  • Don't connect the USB from your PCB board to the computer (follow the image below).
  • Download the USB Bootloader hex image (BootloaderCDC.hex) (Link)
  • Open a command window (terminal) and go to the folder where you saved the hex image.
  • Make sure that the "avrdude" software is accessible in your terminal.
  • Run the command below to check if the AVR Programmer is talking with the ATMEGA chip.
avrdude -c usbtiny -p m32u4
  • In case all good, upload the Bootloader using the command below
avrdude -c usbtiny -p m32u4 -U flash:w:BootloaderCDC.hex
  • We are good to disconnect the AVR Programmer and connect the USB cable from your PCB board.

After flashing the USB bootloader, open your Arduino IDE and set the board to "Arduino Leonardo" and the programmer to "Arduino ISP".

The figure below has the pinout for an Arduino Leonardo board. We can use it as a pinout guidance to map all the 22 GPIO pins accordingly.

Blink LED Arduino code

#include <Arduino.h>
#include <avr/power.h>

#define PF0   A5
#define PF1   A4
#define PF4   A3
#define PF5   A2
#define PF6   A1
#define PF7   A0

#define PC7   13
#define PC6   5   // LED
#define PB6   10
#define PB5   9
#define PB4   8
#define PD7   6
#define PD6   12
#define PD4   4   // LED

#define PD5   NotMappedPort_PD5   // Not Mapped on Leonardo Board
#define PD3   1   // TX
#define PD2   0   // RX
#define PD1   2   
#define PD0   3   
#define PB7   11

#define PB3   NotMappedPort_PB3   // MISO -> Not Mapped on Leonardo Board
#define PB2   NotMappedPort_PB2   // MOSI -> Not Mapped on Leonardo Board
#define PB1   NotMappedPort_PB1   // SCK -> Not Mapped on Leonardo Board
#define PB0   NotMappedPort_PB0   // SS -> Not Mapped on Leonardo Board
#define PE6   7

#define SLEEP_TIME  500

void setup() {
  if(F_CPU == 16000000) clock_prescale_set(clock_div_1);
  
  pinMode(PD4, OUTPUT);
  pinMode(PC6, OUTPUT);  
}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(PD4, HIGH);
  digitalWrite(PC6, LOW);
  delay(SLEEP_TIME);
  digitalWrite(PD4, LOW);
  digitalWrite(PC6, HIGH);
  delay(SLEEP_TIME);
}

As you probably notice from the Blink LED code, some of the pins are not mapped on the Arduino IDE for the Arduino Leonardo board.

For these pins we need to access them by affecting the respective register.

As an example, if we want to set the pin PD5 as an output, we need to affect the following register:

DDRD = DDRD | B00100000;  // PD5 as Output

To set PD5 high and low we would do the following code:

PORTD = PORTD & B11011111;  // PD5 - LOW
PORTD = PORTD | B00100000;  // PD5 - HIGH

Writing to the registers in your code can become confusing to follow and understand what is going on. That is one of the strengths of using the Arduino IDE, it abstracts this register access by using the common pinMode and digitalWrite functions.

We can write our own functions my_pinMode and my_digitalWrite and make our code easier follow and understand. The code below doesn't show those functions but you have access to them under the ATMEGA32u4_Pin_Mapping.h and .cpp files (Link).

Arduino Code

#include <Arduino.h>
#include <avr/power.h>

#include "ATMEGA32u4_Pin_Mapping.h"

#define PF0   A5
#define PF1   A4
#define PF4   A3
#define PF5   A2
#define PF6   A1
#define PF7   A0

#define PC7   13
#define PC6   5
#define PB6   10
#define PB5   9
#define PB4   8
#define PD7   6
#define PD6   12
#define PD4   4

#define PD5   NotMappedPort_PD5   // Not Mapped on Leonardo Board
#define PD3   1   // TX
#define PD2   0   // RX
#define PD1   2
#define PD0   3
#define PB7   11

#define PB3   NotMappedPort_PB3   // MISO -> Not Mapped on Leonardo Board
#define PB2   NotMappedPort_PB2   // MOSI -> Not Mapped on Leonardo Board
#define PB1   NotMappedPort_PB1   // SCK -> Not Mapped on Leonardo Board
#define PB0   NotMappedPort_PB0   // SS -> Not Mapped on Leonardo Board
#define PE6   7

#define SLEEP_TIME  200

void setup() {
  // put your setup code here, to run once:
  pinMode(PD4, OUTPUT);
  pinMode(PD7, OUTPUT);

  pinMode(PD2, OUTPUT);

  /* Non Leonardo Pin */
  //DDRD = DDRD | B00100000;  // PD5 as Output
  my_pinMode(PD5, OUTPUT);
  //DDRB = DDRB | B00001111;  // PB3 to PB0 as Output
  my_pinMode(PB0, OUTPUT);
  my_pinMode(PB1, OUTPUT);
  my_pinMode(PB2, OUTPUT);
  my_pinMode(PB3, OUTPUT);

  if(F_CPU == 16000000) clock_prescale_set(clock_div_1);

  //Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(PD4, HIGH);
  digitalWrite(PD7, LOW);
  /* Testing Code */
  digitalWrite(PD2, LOW);
  //PORTD = PORTD & B11011111;  // PD5 - LOW
  my_digitalWrite(PD5, LOW);
  //PORTB = PORTB & B11110000;  // PB3 to PB0 - LOW
  my_digitalWrite(PB0, LOW);
  my_digitalWrite(PB1, LOW);
  my_digitalWrite(PB2, LOW);
  my_digitalWrite(PB3, LOW);
  /* ------------ */
  delay(SLEEP_TIME);
  digitalWrite(PD4, LOW);
  digitalWrite(PD7, HIGH);
  /* Testing Code */
  digitalWrite(PD2, HIGH);
  //PORTD = PORTD | B00100000;  // PD5 - HIGH
  my_digitalWrite(PD5, HIGH);
  //PORTB = PORTB | B00001111;  // PB3 to PB0 - HIGH
  my_digitalWrite(PB0, HIGH);
  my_digitalWrite(PB1, HIGH);
  my_digitalWrite(PB2, HIGH);
  my_digitalWrite(PB3, HIGH);
  /* ------------ */
  delay(SLEEP_TIME);

  //Serial.println("Working");
}

Code (Arduino Leonardo Compatible)

Bootloader

Gerber Files

Sponsor

Leave a Reply

Your email address will not be published.

Index