Getting started

If you are already an expert on the subject and already have the tools installed, you can look directy at the summary below.

This tutorial explains how to install the toolchain, build your first project and flash it to the microcontroller. If you don't have a board yet, you might still find the Under the hood section interesting. Otherwise, you will need to decide whether to use a JTAG/SWD adapter or the bootloader in order to flash your code into the microcontroller.

Prerequisites

Before making your first LED blink, you need to get a few things in order to compile your code, install it on the microcontroller, and optionally debug it. Let's go!

Toolchain

First, you need a compiler, or more precisely, a cross-compiler. This is because a compiler is usually designed to compile code for the same architecture it is running on, which is not the case here : we want to compile on the computer, but for the microcontroller. Because this compiler is quite complex and usually packaged with other tools, it is often called a toolchain.

The toolchain we'll be using is the one provided by Atmel/Microchip which you can download here (look for the latest version of the "ARM GNU Toolchain (32-bit)" for your OS). It is based (with a few modifications) on the official GNU ARM Embedded Toolchain. Don't forget to take a look at the Release Note on Microchip's download page, which gives interesting information about the tools provided by the toolchain.

Once the toolchain is downloaded, unpack it somewhere convenient. Take note of this location, you will need it later.

OpenOCD

This is not needed if you are going to use the bootloader.

OpenOCD is a tool which is able to connect to a JTAG/SWD adapter and take control of a microcontroller. We will use it as the interface to flash and debug some code into the microcontroller.

Download links and installation instruction are available on the official website. On Linux, most of the time it is available in the repositories and you only need to type sudo apt-get install openocd or something similar.

Hardware

Finally, you need a board to program. As explained here you have multiple choices on the matter, but whatever you choose, the procedure will be similar.

If you don't want to use the bootloader, you'll also need a JTAG/SWD adapter in order to communicate with the microcontroller and flash your program. Look at the JTAG/SWD vs Bootloader tutorial for more details.

Creating a new project

Alright, you should now have everything you need and you can start creating a new project. Let's begin with the mandatory initiation rite : making an LED blink (yeah!).

Two important files

Start by creating a new directory blink for this project and point your text editor to this directory. Now, create two new files : blink.cpp and Makefile, and fill them with the code available in the Blink example page (you can download them using the links below and wget for example) :

blink.cpp [download] wget https://libtungsten.io/static/code/examples/blink/blink.cpp

#include <core.h>
#include <gpio.h>

int main() {
    // Init the microcontroller
    Core::init();

    // Define the pin on which the LED is connected
    // On Carbide, this is the red LED
    const GPIO::Pin led = GPIO::PA00;

    // Enable this pin in output to a HIGH state
    GPIO::enableOutput(led, GPIO::HIGH);

    while (1) {
        // Turn the LED on
        GPIO::setLow(led);

        // Wait for half a second
        Core::sleep(500);

        // Turn the LED off
        GPIO::setHigh(led);

        // Wait for half a second
        Core::sleep(500);
    }
}

Makefile [download] wget https://libtungsten.io/static/code/examples/blink/Makefile

NAME=blink

BOOTLOADER=true

# Available modules : adc dac eic gloc i2c spi tc trng usart.
# Some modules such as gpio and flash are already compiled by default
# and must not be added here.
MODULES=

# The toolchain's bin/ path, don't forget to customize it.
# If this directory is already in your PATH, comment this line.
TOOLCHAIN_PATH=/opt/arm-none-eabi/bin/

# Include the main lib makefile
include libtungsten/Makefile

Let's look at what this code does.

First, we include two headers from the library : core.h and gpio.h. They ensure that the fonctions from the Core and the GPIO modules respectively will be available.

  • The Core module is a bit special : it is not related to a peripheral, but instead gives access to the features of the ARM Cortex M4 core itself. These features are actually not specific to Atmel, they are common to all chips embedding a Cortex M CPU. More info in the Core module documentation.
  • The GPIO module (General Purpose Input Output), as its name implies, takes care of the input/output pins of the microcontroller. We will use it to control the pin connected to the LED. More info in the GPIO module documentation.

Inside the main(), we first need to initialize some basic stuff inside the microcontroller using Core::init(). When using libtungsten you should always call this function at the beggining of your main() (when using the Carbide module this is done for you inside Carbide::init()). Then we define the pin we want to act on, using the Pin type defined in the GPIO module (therefore GPIO::Pin). A pin is defined by its port and its number, here PA00 (first pin on port A). The enableOutput() fonction is used in order to define this pin as an output and control the LED.

Since returning from the main() doesn't make any sense in the context of a microcontroller, we need an infinite loop where we will put the code which will constantly be executed. Here, this code is simple : turning the LED on and off. For this purpose, we need two things : a function for setting the desired level on the pin, and a function to wait for a certain amount of time. That would be respectively GPIO::set() and Core::sleep(). Here we use two helper functions instead of the first : GPIO::setLow() and GPIO::setHigh(). They behave exactly the same way and only make the code easier to read and quicker to write.

It might surprise you that setHigh() turns the LED off and setLow() turns the LED on. This is because the other side of the LED is connected to Vcc and the pin is used as a current sink, so it needs to be pulled to GND in order to let the current flow. The reason for doing this is that the microcontroller is not designed to supply lots of currents on its pins, however, it can tolerate to let a bit more current pass to ground. Anyway, if you plan to drive more powerful devices than a LED (e.g. a motor), remember to use a dedicated circuit for this (such as based on a transistor for example).

That's it for the code : we only need to initialize the microcontroller, define the pin on which the LED is connected as an output, and indefinitely turn it on, wait, turn it off, wait, repeat.

The Makefile is really simple : the only mandatory parameter is NAME, which indicates the name of your project. This must match the name of your main .cpp source file. Another important parameter is MODULES, which defines the list of modules that need to be compiled with your project. The list of available modules and their descriptions is detailed in the Reference but the most important and useful ones, such as core and gpio, are already compiled by default. Here, we do not use any optional module so this can be left empty. If you want to flash the program directly using a JTAG/SWD adapter, comment the BOOTLOADER=true line to compile the code accordingly. If the toolchain's bin directory is not in your PATH, you need to tell the Makefile where to find it with the TOOLCHAIN_PATH parameter (this is what you noted earlier — make sure you don't forget to append a trailing slash). When your code starts to grow, it is a good idea to divide it into separacted modules, which you can ask the library to compile for you using USER_MODULES. Finally, the main Makefile containing all the necessary rules is included from the library.

Don't forget to customize the TOOLCHAIN_PATH parameter, the one given here probably won't work for you. Either specify the full path to the arm-none-eabi/bin/ directory, or remove/comment this line if this directory is already in your PATH environment variable.

Cloning the library

Finally, we need a copy of the library in our project directory (as we saw in the Makefile). You can either clone it from the Git repository :

git clone git@github.com:Foalyy/libtungsten.git

Or download an archive : download.

Your project directory should now look like this :

  • blink/
    • blink.cpp
    • Makefile
    • libtungsten/
      • Makefile
      • sam4l/
      • ...

Compiling, uploading/flashing, and testing

Compiling your project is quite easy : just type make in a terminal. This will generate two files : blink.elf, the compiled code in the ELF format, and blink.hex, generated from the .elf and containing the code data ready to be written into the microcontroller.

There are two ways to flash your program into the microcontroller : either using the bootloader and codeuploader, or with OpenOCD and a JTAG/SWD adapter. Look at the JTAG/SWD vs Bootloader tutorial for more details.

Using the bootloader

Using the bootloader is simpler and cheaper, because you don't need an external adapter. All you need to do is :

  • plug a USB cable into the board
  • turn it on while pressing the button to enter bootloader mode (the green LED will start to flash)
  • type make upload
The blue LED will blink rapidly while the code is written into the microcontroller's flash memory. When upload is complete, the board will automatically reset and start executing your program.

You can find more details in the bootloader documentation.

Using a JTAG/SWD adapter

This method is a bit more complex because it requires OpenOCD, however don't worry, the Makefile takes care of most of the work for you. All you need to do is :

  1. Open a new terminal, go to the project directory, and type make openocd. This will start a new GDB instance which will connect to your JTAG/SWD adapter and, through it, to the microcontroller. Keep this terminal open in the background.
  2. Go back to the first terminal and type make flash : this will connect to the OpenOCD instance, read the content of the .hex file and write it into the microcontroller's flash memory. When the process is done (this can take up to one or two minutes), the microcontroller will automatically reboot and start executing your code.
Alternatively, you can simply type make autoflash, which will spawn a temporary OpenOCD session and use it to flash your code. However, you still need to use the procedure above if you want to perform other operations such as make debug or make reset.

Congratulations, the LED is now blinking !

Nice! Now what?

You can now take a look at the documentation overview and the other examples to see what this microcontroller can do!

Summary

  • mkdir blink
  • cd blink
  • git clone git@github.com:Foalyy/libtungsten.git
  • wget https://libtungsten.io/static/code/examples/blink/blink.cpp
  • wget https://libtungsten.io/static/code/examples/blink/Makefile
  • vim Makefile # Check TOOLCHAIN_PATH
  • make
  • make upload # Or make autoflash with a JTAG/SWD adapter