I’ve been using the Arduino Uno board for quite some time, including as examples for many of my articles. I’ve always wondered what it would take to get the ATmega328P (the original chip used on the older Uno boards) working completely on its own. With the Arduino making it so accessible via its bootloader, nice GUI software, and C++ abstraction, you’d wonder why on earth I would want to even attempt this. Sometimes, in order to appreciate what others have done, it’s important to try doing it yourself. This project really demonstrated how much work the Arduino folks put into this and changed the world with that friendly little product.
In this article, we’ll walk through bringing up the chip completely on its own using only an external power source and an Atmel-ICE programmer. We’ll demonstrate how to communicate with the chip via the onboard serial interface and also blink an LED or two.
There are a few ways to configure an ATmega328P. One such way, intentionally not covered as you can tell by the title, is by dropping in your ATmega328P chip into an Arduino Uno, programming it, and then moving it over to a breadboard. Based on feedback on forums some folks want to skip the Arduino process and use a more traditional approach with programmers such as the Atmel-ICE from Microchip. The most straightforward way to start with a Microchip (formerly Atmel) microprocessor is to install Microchip Studio. At the time of writing this article the full Microchip Studio suite is only supported in Windows. Since I like to have all my build environments run in CI (Continuous Integration) I opted for an alternative approach.
The GNU Compiler Collection (GCC) is one of the most popular compilers out there for the C language. It compiles certain platforms and architectures but not for the AVR (ATmega) family of chips. There is, however, a set of compilers for the AVR and other Microchip families hosted on their website. Luckily, some kind folk have even packaged these compilers into nice Debian packages that can easily be installed in Debian or Ubuntu like so:
$ apt-get install gcc-avr binutils-avr avr-libc avrdude
With these tools installed we’re now able to compile and program the ATmega328P with only an Atmel-ICE programmer and an external power supply (set at 5V). We’ll use the AVR version of GCC to compile the code and AVRDUDE to flash the ATmega328P chip.
For this project, my goal was to demonstrate some basic, but functional, capabilities of the ATmega328P. A simple external blinky LED and some serial commands back and forth were all I needed to prove that this chip could stand on its own. In the project’s repository I’ve created a few folders in addition to the source code (named “src”) that assist with the development of this project.
An important component to software development (even software that goes on hardware) is unit testing. Unit testing validates that the functions or pieces of the larger system are working as expected. If someone comes along and modifies a piece of that functionality the unit test will prevent regressions from happening (i.e. you unintentionally broke something else by introducing a new feature). In this example I’ve written a basic unit test that mocks out the hardware and runs through the initialization scheme of serial communication library (USART).
In addition to unit testing (located in the “tests” folder), there is also a folder called “hil” which stands for Hardware in the Loop. This folder contains the scripts necessary to run testing with actual hardware in the loop (as discussed in many of my previous articles). This ensures that my code is functional not only in the virtual world (using mocks) but also in the real world by running tests on real hardware.
Consulting the README.md will provide you with a pinout diagram to connect to the Atmel-ICE programmer to the ATmega328P chip:
Figure 1: Atmel ICE Pinout
Adding a few LEDs, hooking up the serial communication port to a Raspberry Pi, and picking off the Raspberry Pi’s +5V line and you now have a full assembly ready to go:
Figure 2: ATmega328P using a breakout board with the Raspberry Pi and Atmel-ICE programmer
As you develop new features, use the Makefile to run unit tests and compile the code. After validating that your desired code does what it is intended to do (via unit test validation), build the binary, flash it onto the device (also via the Makefile), and run Hardware in the Loop (HIL) testing using the Raspberry Pi’s serial communication port.
One of the most important pieces is correctly flashing the fuse bits to enable the internal 8 MHz clock. This is documented in the README but also added to the flashing command in the Makefile:
avrdude -c atmelice_isp -p m328p -B 32 -U lfuse:w:0xe2:m
After that you should be able to use the chip’s serial interface with the assumption that the onboard clock runs at 8 MHz (as defined in the top of main.c). From here you should be able to add more functionality such as support for additional serial commands, interfaces to external components and sensors, and anything you can think of with this fun little microcontroller.
In this article, you learned how to get started with the ATmega328P chip without any external circuitry as commonly seen with the original Arduino Unos and Microchip evaluation boards. You now know the concept of unit testing, binary builds, flashing the chip, and running hardware in the loop testing. Additionally, there was an important detail, often overlooked, about programming the fuse bits to set the internal clock to 8 MHz. At this point you should be able to add more functionality with additional unit and HIL tests and run everything with just an Atmel-ICE programmer and an external 5V supply. For simplicity, utilizing a Raspberry Pi for its power source and serial communication capabilities would be the easiest way to control the process end-to-end.
The project’s source code can be found here:https://gitlab.com/embedded-designs/atmega328p-serial-led-control.