Developing in C for the ATmega328P: Introduction

5 minute read

Where I begin the process of developing in Standard C (and only C) on the Arduino Uno (also known as the ATmega328P).



This series is similar to the one on developing in C on the RP2040. It will cover adding the toolchain to your system of choice, executing the toolchain on examples and (possibly) advancing the ability to debug using a hardware debugging tool. Or stated more formally:

  1. (OPTIONAL) Install the tool chain necessary to cross-compile C and link code for the ATmega328P on the platform of choice. OR use the same tools as the Arduino IDE, however, use them via the command line.
  2. Test #1 using an Arduino Uno (without the Arduino software framework!) using some examples from the web as well as my own.
  3. (TBD) Advance the ability to debug by adding a hardware debugger in the form of a hardware debugger.

For each of the platforms, there is a level of complexity to accomplish each step. Its important to understand that the tools that exist to accomplish cross-compiling and linking C for an embedded microcontroller are designed for Linux. Therefore, the closer a system “looks like Linux”, the easier it is to follow the three steps. This isn’t a problem. It is simply something to understand and account for. Specifically, the level of difficulty of the three steps in each operating system is:


  1. Intall Toolchain Easy.
  2. Develop C code Easy
  3. Hardware Debug Moderate


  1. Install Toolchain Easy.
  2. Develop C code Easy
  3. Hardware Debug TBD


  1. Install Toolchain Intermediate, requires a different approach than usual in Windows.
  2. Develop C code Easy.
  3. Hardware Debug TBD

Why It Is Worth It

You might ask yourself, if you have already done this for the Pico/RP2040, a far more advanced microcontroller, why would I pursue this? Because while the Pico is a great bargain, and having a 32-bit microcontroller with hardware debugger for only $15 is a steal. The RP2040 is a powerful and extremely complex microcontroller even with all of the great documentation. I wanted to explore performing the same task (developing in C) on a far less complex microcontroller such as the ATmega328P.

The AVR series of processors is incredibly broad, absurdly inexpensive and very easy to use. One can purchase an ATtiny13 for less than $1 which, “combines 1 KB ISP Flash memory, 64B SRAM, 64B EEPROM, a 32B register file, and a 4-channel 10-bit A/D converter. The device supports a throughput of 20 MIPS at 20 MHz and operates between 2.7-5.5 volts.” In an easy to integrate DIP package.

I found this passage In Elliott William’s book, enlightening as to why to learn how to do this without the Arduino:

“The price paid for the Arduino pin/timer abstraction is that what we do in one or two lines of code, and two or three cycles of CPU time, the Arduino does in 50+ clock cycles. It tests if you want the pin fully on or off, and it uses a whole switch() expression and memory lookup to figure out which timer registers to write to—and all of this just so that you don’t have to look up the pin in the datasheet.”

“If you’re calling analogWrite() infrequently in your code, this will probably work OK, and you’ll never notice the speed penalty. If you’re setting the OCR bits frequently, as we will be in Chapter 13, this extra code overhead means the difference between the possible and impossible. If you’re coming from the Arduino world, you’ll probably be annoyed by how much detail about the chip you’re required to learn, but once you learn how to actually use the hardware peripherals as they’re intended, you’ll be surprised by how much more is possible. And once you know how the internal peripherals work, it’s not much harder to configure them yourself.”

–Excerpt From: Elliot Williams. “Make: AVR Programming.” Apple Books. "

OK, now what?

Get started!

Be aware that there might be some difficulty in the initial steps of installing and confirming the operation of the tool chain required. Understand that you might need to download and install a fair number of software applications. And that some of those applications might use commands and a language that is difficult to understand.

That said, if developing code on an embedded microcontroller is important to you, the steps you take to accomplish these tasks are very important. And learning what it takes to implement and use the tool chain will be very useful.

One Last Thing

While we will use the Arduino IDE to confirm things are working, don’t use it to follow these examples. In this series, we want to explore programming only in C (not C++) and we want to learn more about the process. This point is very similar to the point that I made in the RP2040/C series…[I was asking not to use Visual Studio Code as compared to the Arduino IDE]

IDE’s can be great in that they automate a lot of the development experience. This is paramount if you are an engineer developing code for a living. An IDE will raise their productivity. The engineer using the IDE has already spent a tremendous amount of time, understanding the intricacies of compiling, linking, loading and debugging code, more than likely via the command line.

If this content how to develop C on an RP2040 is new, particularly using gcc, CMake, make, openocd and gdb, then embrace using those tools by themselves. This will help you understand them much better. And understanding them now will make you much more proficient later when you are sufficiently knowledgeable to use an IDE.

After I wrote the above text, I ran across this commentary on which processors to use. I strongly agree with the author and note that they do say “The Arduino Uno/Nano is still the best introduction to UCs though.” Which is the point of this series.

Update October 23, 2022

This article is an end-depth discussion as to the issues of using an IDE and is also recommended reading.

Good luck and have fun!

Next entry: Developing in C for the ATmega328P: Setup Introduction

Comments powered by Talkyard.