Developing in C for the ATmega328P: macOS Setup

Where I setup the Standard C toolchain (avr-gcc) for the ATmega328P on macOS using homebrew.

Test with the Arduino IDE!

After performing these steps on multiple machines, I’ve found it best to install and test using the Arduino IDE before going forward with the installation instructions below. This will reduce the errors to something more manageable and having the Arduino IDE is handy for its Serial Monitor as well it provides an easy method to which port the Uno is connected.

1. macOS Setup and Tool Chain Installation

For the macOS installation the installation will require using a package manager, in this case homebrew. If you don’t have it installed, you will need to do so before continuing. homebrew will require xcode command line tools to be installed as well.

Install the package manager, homebrew:

# this command installs command line tools only, not all of xcode 
xcode-select --install
# this command installs homebrew, a package manager for macOS
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# get the latest versions list
brew update

Install the tool chain

I followed these instructions for installing the AVR tool chain. It took a fair amount of time to install, I had no issues throughout the process. To install the tool chain, you will need to perform:

brew tap osx-cross/avr
# removal needed before upgrading
brew remove avr-gcc avr-binutils avr-libc
# avr-libc is now included in avr-gcc
brew install avr-gcc avr-binutils
brew install avrdude
brew install make

CHECK AND CONFIRM

Once the installation completes, perform the following commands to confirm all applications were installed correctly. The application averdude provides a lot of output, only some is shown.

avr-gcc --version
make --version
git --version
avrdude

Check and Confirm the tool chain is installed

Check and Confirm the tool chain is installed

Large Version to see detail

Now, we have the same capability as the Arduino IDE, however, we are able to use it via the command line!

2. Test the tool chain

Test Code

You will want to select the code in the box below, copy it then you will paste it into a nano editor window.

#include <avr/io.h>
#include <util/delay.h>
 
#define BLINK_DELAY_MS 100
 
int main (void)
{
 /* set pin 5 of PORTB for output*/
 DDRB |= _BV(DDB5);
 
 while(1) {
  /* set pin 5 high to turn led on */
  PORTB |= _BV(PORTB5);
  _delay_ms(BLINK_DELAY_MS);
 
  /* set pin 5 low to turn led off */
  PORTB &= ~_BV(PORTB5);
  _delay_ms(BLINK_DELAY_MS);
 }
}

Testing the Code

In this step, we’ll setup a specific folder for developing C. I called it test. We’ll add a file called main.c, the we’ll compile/link the file on to the Uno.

cd
mkdir test
cd test 
# copy the file from above and we'll call it main.c
nano main.c
# paste the file, save it and exit

Notes on the steps

  • I’m using nano as my editor to keep this simple, this will be a copy and paste from code above into a file on your system.
  • Using the command cd without folder descriptor, will take you to your home folder. Using cd test will take you to the new folder test you just created.
  • nano main.c will open a file called main.c in the nano editor. The window will be empty as main.c is a new file. Once you paste the file into nano, it will look like this:
    main.c in the nano editor

    main.c in the nano editor

    Large Version to see detail

To save and exit nano, press Ctrl-X, y (to confirm saving) and Return (to confirm file name). Once you have saved the file, you will be back at the WSL prompt. Enter the commands below to compile/link your file.

avr-gcc -Os -DF_CPU=16000000UL -mmcu=atmega328p -c -o main.o main.c
avr-gcc -mmcu=atmega328p main.o -o main
avr-objcopy -O ihex -R .eeprom main main.hex

Your window will now look similar to this (both sets of operations shown:

main.c in the nano editor

main.c in the nano editor

Large Version to see detail

Our last step is to load the main.hex file on to the Uno. We use averdude to upload code to the Uno. We’ll use the following command:

avrdude -F -V -c arduino -p ATMEGA328P -P /dev/ttyACM0 -b 115200 -U flash:w:main.hex

Notice the "/dev/ttyACM0"? You will want to change the “ttyACM0” to the port name that you wrote down in the Arduino IDE port assignment in the earlier step Install the Arduino IDE. When you run the averdude command above successfully, you will see the following:

Successful averdude upload

Successful averdude upload

Large Version to see detail AND your Uno will be blinking at a much faster rate!

If you see this instead:

Typical averdude failure

Typical averdude failure

Large Version to see detail

  • Is the Arduino IDE installed, have you tested it, and it worked?
  • Have you closed the Arduino IDE?
  • Are you sure you are using the right port? Double check the number using the Arduino IDE and make sure the port name matches the port name on your averdude command. Ex: -P /dev/ttyACM0

3. Automate using a Makefile

On this GitHub site for Elliot William’s book, he has a Makefile in the folder setupProject. This Makefile is comprehensive and delivers an Arduino IDE type of simplicity with significantly increased speed. On the page for the file, click on the Raw button, just above the first line. With the raw text, select all of it then copy it. Paste it into a new file on your system in the test folder and call it Makefile. Make sure the filename is Makefile without an extension.

There are some changes that need to be made. Using the line numbers below as the line numbers in the original, change the text as reflected below. Do not add line numbers to the lines.

 7 MCU   = atmega328p
 8 F_CPU = 16000000UL 
15 # LIBDIR = ../../AVR-Programming-Library
23 PROGRAMMER_TYPE = Arduino
25 PROGRAMMER_ARGS = -F -V -P /dev/cu.usbmodem3101 -b 115200  
48 TARGET = main
50 # TARGET = $(lastword $(subst /, ,$(CURDIR)))
60 CPPFLAGS = -DF_CPU=$(F_CPU) -DBAUD=$(BAUD) -I.
  • Line 7, change the processor type to the Uno processor, atmega328p
  • Line 8, change the clock speed to 16MHz
  • Line 23, we’ll be using the Arduino to program itself
  • Line 15, add a “#” at the beginning of the line to comment the line out
  • Line 25, be sure to confirm you use your serial port, which worked in step 2.
  • Line 48, change the name from blinkLED to main
  • Line 50, add a “#” at the beginning of the line to comment the line out
  • Line 60, remove the " -I$(LIBDIR)" text at the end of the line. This text exists for an additional library, which we won’t use right now.

Once you have made the above changes, please try the following to test your setup:

  1. Manually delete all of the files EXCEPT the led.c and Makefile in the folder test.
  2. Run make flash, this will perform all of the tasks required to compile/link/load the program onto the Arduino Uno.

Hopefully, it all works the first time. If not, look at the errors to discern what needs to be fixed. For me, I had not changed my serial port (line 25 -P /dev/cu.usbmodem3101) to be the correct one.

Now that it is working, I noticed the complete time from pressing enter to “avrdude done.” was 2-3 times faster than what the Arduino framework would take on a similar file.

Finish up

Once you have tested the Makefile and the program main.c, the folder test is no longer required.

Comments powered by Talkyard.