Using Arduino as an Embedded Development Platform

Published on by John Teel

An Arduino, or more specifically an Arduino architecture, can be successfully used in some embedded designs. This can provide a less technically complex path to market for many makers.

However, the proliferation of Arduino and Arduino-compatible boards, each with its own name, can lead to confusion as to what Arduino is, and which version you should choose for your particular project.

With names such as Uno, Leonardo, Mega, Nano, Zero, Due and lots more, simply listing their specifications is not enough information to decide which you should choose for your given application.

This article takes an integrated approach to better understanding what makes an Arduino an Arduino in the first place.

NOTE: This is a long, very detailed article so here's a free PDF version of it for easy reading and future reference.

This is a guest post by Shawn Litingtun, an amazing electronics engineer that I work with closely. He is also one of the experts inside the Hardware Academy available to help you.

From this article, I hope you can choose among existing Arduino boards, and even design your own custom boards that retain some of the main features of Arduino, including the relative ease of developing custom applications.

Arduino can be viewed from many angles. First, there is the hardware (HW). There are many versions of Arduino compatible hardware, and the only things that are common among them is they all have a microcontroller and a USB port.

Then there is the firmware. In this area, first, there is the bootloader that allows the user to download the application code to run on the hardware. Then there is the Arduino core. This core is actually not pre-loaded into the microcontroller. It is compiled, and linked along with the user application code, and then loaded.

This core is what makes Arduinos based on different microcontrollers behave in the same way, so that a person familiar with writing code on one Arduino platform can easily migrate to a different board.

Adding to the ease of transitioning to different hardware is the Integrated Development Environment, or IDE, which behaves in the same way regardless of the chosen hardware.

Finally, there is a huge library base. This, and the ever increasing capabilities of Arduino compatible modules, is what makes Arduino so ubiquitous in embedded applications of moderate complexity.

Each of the aforementioned points will be presented in more details in the next sections.

The Arduino Hardware

Arduinos originally had Atmel – now part of Microchip – AVR ATMega8 microcontrollers. This is an 8-bit microcontroller with 8 KB of flash and 1KB of SRAM. Still, as in most microcontrollers, it has an integrated USART, several timers, ADC’s, SPI, digital IO’s that can also be programmed as PWM and external interrupt inputs.

On the board, a UART to USB interface chip was added to allow communications with an external PC, and the available pins of the microcontroller were made available to the user.

The board was open-source, and the HW schematic was made available. This, in turn, gave rise to third-party daughter boards – called Shields – that augmented the capability of the Arduino board. Examples of such shields include Ethernet, WiFi, GPS, ZigBee, Sound, and more.

While there were many iterations of this line that included higher-end versions of the Mega8 such as the Mega168, or the Mega328, with 32K of flash and 2K of SRAM, they were all still based on 8-bit microcontrollers running at relatively low clock speeds, with relatively small amounts of memories.

When ARM Cortex M series of 32-bit microcontrollers became price-competitive with AVR Mega’s, several vendors started making Arduino boards based on the ARM microcontrollers.

Since this was a complete departure in the base HW of the original Arduino, the definition of what constitutes an Arduino board should be widened. So, here are some of the attributes that all Arduino boards share, regardless of the underlying solution:

1) It can run Arduino code. This means:
– It has a GCC, or similar, C++ compiler, which is the compiler behind Arduino.
– It has an Arduino core that provide a basic set of software functionalities such as digital IO, serial communication, I2C, PWM and timers.
– It has an Arduino compatible bootloader.

2) It has a USB interface to allow connection to a PC – here used generically to include Macs, Linux machines and others.

3) User code can be downloaded to be run on the board directly from the Arduino IDE. This means it has a board HW definition in the Arduino IDE. In turn, it means that the Arduino IDE has information about the clock frequency, memory layout, IO port mapping, and other details about the underlying microcontroller used in the board.

Currently, there are many such compatible boards. Some are based on Atmel’s SAM family of ARM microcontrollers. These include the Arduino Due and the Zero.

Adafruit and SparkFun also have Arduinos such as the Feather M0. ST Microelectronics also has a range of evaluation boards such as the Nucleo series that are Arduino compatible.

There is also a very inexpensive board, commonly known as STMduino or Blue Pill, that are available already Arduino compatible, or can be made Arduino compatible. It is based on an STM32F103C8T6, an ARM Cortex M3 microcontroller.

Finally, the ESP32, based on the Tensilica Xtensa microcontroller core, is also Arduino compatible.

The Arduino Core

Writing code in Arduino is almost like writing code in C/C++, except for being somewhat simpler. This is because the Arduino programming “language” is actually C++, with some simplifications targeted specifically for embedded applications that run on compatible HW.

Consider the simple test.ino example below:

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);  // Initialize digital pin LED_BUILTIN as an output
  Serial.begin(9600);                             // Set serial port to 9600 baud

// Repeat forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // Turn the LED on
  delay(1000);                                        // Wait for a second
  digitalWrite(LED_BUILTIN, LOW);   // Turn the LED off
  delay(1000);                                        // Wait for a second

If this were written for, say, an ATMega8, using Atmel’s AVR Studio IDE, this would have required at least fifty, or more, lines to write. Several header files would have to be included. LED_BUILTIN would have to be defined as a pin on a particular port.

The user would have had to write setup functions to initialize, and access, the IO ports and the USART. This would have required many lines to set up the appropriate microcontroller registers.

This code would also have been different for different microcontrollers. Here, the Arduino core provided a Hardware Abstraction Layer (HAL) that made pinMode or Serial.begin work the same way regardless of the underlying hardware. In the above example, the Arduino core took care of all this.

How, for example, Serial.println is implemented, is now transparent to the user. All that has to be done is to select the right board, and it just works, regardless of whether the board is AVR or ARM based.

The Bootloader

A bootloader is a small piece of code that is preloaded into the microcontroller, and is executed upon reset. It then tries to communicate with the PC. If this is successful, and the correct handshake is established, the PC then downloads the application code to the microcontroller.

The bootloader then flashes the microcontroller’s application flash memory, and transfers control to this application code.

If there was no handshake from the PC, then, after a timeout period, the bootloader automatically transfers control to the application code section to begin executing the application.

Of course, if there is no valid application that had been previously loaded, the microcontroller hangs. All Arduino boards have this bootloader pre-installed in the bootloader section of their microcontroller.

Remember that the bootloader cannot boot load itself. Some other means must be used to upload this bootloader code into the microcontroller.

All Arduinos have some power-on delay before executing the application code due to the bootloader needing to wait for new application code, if any, to be bootloaded.

Also, if a microcontroller does not have the ability to flash itself, then it cannot have a bootloader.

The Arduino IDE

There are many IDE’s that are compatible with Arduino, such as PlatformIO and Visual Micro. The Arduino IDE is still the most popular, and is the one discussed in this article.

This IDE is not the most sophisticated for writing and debugging code, and it cannot be used to develop modular code. However, it does support all of the features of the Arduino development ecosystem.

In the Arduino Hardware section, it was mentioned that the Arduino IDE can support many different boards that are built around different microcontrollers.

In order to add support for a given board, just go to Tools > Board > Board Manager… as shown in Figure 1 below. A pop-up such as shown below in Figure 2 will appear. Just scroll down, and choose the board to install.

Figure 1 – Getting to the Arduino Board Manager


Figure 2 – Board selection in Arduino


Sometimes, however, a board is not included in the Arduino board selections because it is not officially supported, but the board definition is still available, usually on Github.

In such cases, it is still possible to install the board. First get a link to the board definition file, which is usually a json file.

Then, go to File > Preferences, and add the link to the “Additional board Manager URLs” input field. This is shown in figure 3 below. Multiple URL’s can be entered, each separated by a comma.

Once a board is installed, it will then appear in the list of available boards, and can be chosen as the current board for which the application is being developed.

Of course, the application code can be compiled, debugged, and downloaded to the target hardware from within the IDE itself.

Figure 3 – Additional Boards Manager


The Arduino Libraries

This is the area where the Arduino really comes into its own for rapid embedded system development. There is a vast number of libraries available for Arduino-based hardware.

There are Arduino libraries for almost anything from WiFi to LCD’s and OLED’s to all kinds of sensors such as an accelerometer, temperature and humidity sensors, pressure sensors, DAC, GSM and more.

Libraries are not just limited to external HW interfacing either. For instance, there are libraries for accessing remote MQTT servers, or for doing multitasking, and much more.

Just bear in mind that Arduino libraries are user-contributed, and some are better written than others. Some libraries will just not work as expected, and need to be tweaked.

Fortunately, Arduino libraries are actually simply C++ source code modules that are meant to be compiled with the rest of the application. Thus, they can be modified, and, in some cases, they actually must be modified.

For example, the library may have embedded a filename, or it has a predefined IO pin dedicated to accessing an external hardware, but did not provide functions to allow the user to change these to suit the intended application.

The path to the libraries are found by going to File > Preferences. A pop-up as shown in Figure 4 will appear.

In the folder listed in “Sketchbook location:”, there will be a folder named “Libraries”, and inside this folder will appear many folders, each containing an already installed library. Choose the library of interest, and inside its folder, will be a folder named “src”. This contains the source files of the library.

There are basically two ways to install an Arduino library.

If the library is included in the library manager, then just go to Sketch > Include Library > Manage library. This is shown in Figure 5 below. Clicking on “Manage Libraries” will bring up a pop-up that can be scrolled through to select the library to install. A typical library selection pane is shown in figure 6 below.

Alternatively, if the library is not included in the Library manager, then download the zipped library, and instead of selecting “Manage Libraries…” as shown in Figure 5, choose “Add .ZIP Library…”, and follow the instructions from there.

Figure 4 – Sketchbook location


Figure 5 – Getting to the “Manage Libraries” menu.


Figure 6 – Typical library manager selection window


Custom Arduino Boards

Despite the large variety of Arduino boards available, sometimes they cannot be used in an embedded design usually do to space restrictions and/or profit margin.

In such cases, it is still possible to stay within the Arduino ecosystem while having a customized board.

The idea is to simply embed the Arduino microcontroller in the custom board. The thing to remember here is that, at the end of the day, regardless of the code development process, a binary file is created.

Once this is loaded to the microcontroller, it will behave exactly as it was programmed to do, whether it’s an Arduino board or a custom board.

For the hardware, a device programmer is needed for the target microcontroller. There are many device programmers available to choose from as shown in Figure 7 below.

Figure 7 – Device Programmer list from Arduino IDE


This list is not exhaustive though, and there are many others not listed that would work as well.

Next, choose a board that has the same microcontroller as the one to be used in the custom board. The custom board should be designed using the same pinout as the chosen board.

For example, the Arduino Uno pinout is shown in Figure 8 below. Most pins have multiple possible uses that can be selected in the application code.

Image result for arduino uno pinout

Figure 8 – Arduino Uno pinout


After that, write and debug the application code, using Sketch > Verify/Compile until it compiles without errors. The last step is to do Sketch > Export compiled Binary. These two options are shown in Figure 9.

Figure 9 – ST Link V2 for programming ST ARM devices


In the sketch folder, there will be several files, including .ELF, .HEX or .BIN files . These are the files that the device programmer will need in order to program the microcontroller.

Since each device programmer works differently from the others, its user manual should be consulted to get the specifics on how to use it to program the microcontroller.

Finally, note that since the Arduino IDE is still Atmel-centric, it does not list device programmers for non-Atmel microcontrollers such as ARM Cortex 32-bit microcontrollers from ST Microelectronics.

These are quite powerful microcontrollers that can also use Arduino as their development platform. These microcontrollers, if supported by the IDE, can be programed by using a ST-Link V2, or a functionally identical, but cheaper, clone. Click here for the software utility for loading the bin file.

To program these microcontrollers, simply connect the SWCLK and SWDIO pins of the device programmer to the corresponding device pins. Of course, VCC and GND have to be connected as well.


Using Arduino to develop embedded applications, even commercial ones, is a viable alternative to using the native development platform of the embedded microcontroller.

That’s because Arduino is basically just C/C++ in disguise, designed to provide a higher level of abstraction. Of course, this removes the insight that comes from a more intimate knowledge of the underlying hardware.

However, this can be an acceptable compromise if you need to speed up the development of your application.

If you read only one article about product development make it this one: Ultimate Guide – How to Develop a New Electronic Hardware Product in 2020.  

Other content you may like:

0 0 vote
Article Rating
Notify of
Oldest Most Voted
Inline Feedbacks
View all comments
Larry Nelson Sr

I would add the Digilent Chipkit UC32 (PIC32MX340F512) or MAX32 (PIC32MX795F512) boards using the Microchip PIC32 processors. These have been around for quite a while and there are many examples of code using them on the web and in the forums. In addition to using them with the Arduino development environment you can use them with the Microchip Development tools directly.


Thank you for the article, John, very useful. A few things to add:
– There is a lot of FW code examples on the Arduino community forum. Also, if you have any problems or questions you can easily get help there.
– Since Arduino HW is open source, you can re-use the schematics/layout (in Eagle format) and use it as a starting point for your board design. Then you can remove peripheral components that you don’t need and add the ones that you need. But keep all components that support the MC itself, such as quartz oscillator, USB, decoupling caps etc. Also, pads for JTAG are worth keeping because they can be used for uploading the bootloader in the production flow (when the MC is fresh from the factory and has no bootloader you can not use the USB to upload your FW, so you need a way to upload the bootloader first through the JTAG interface). Start with the Arduino board version that has as much peripherals as you are going to need, for example, BLE, WLAN or direct USB.
– Arduino Zero has a powerful SAMD21 Cortex core with plenty of features, and single USB interface for both communication and FW upload. That means that your customers will later be able to upload new FW versions to fix the bugs if needed.
– Another benefit of using Microchip MC is that, if you use USB in your application, you will need to get a USB VIN/PIN numbers that will cost you $2000. But with Microchip MC you can get a temporary VIN/PIN for free for low production volumes below 10,000/year.

BJ Raval
BJ Raval

Great article, John!! As always, you make difficult concepts so easy to learn! Kudos!
A suggestion: How about a similar companion article for Raspberry Pi?