The library follows the internal organisation of the micontroller (or MCU for MicroController Unit, or simply the microcontroller), so let's look at that first.
There are 4 main components inside the microcontroller :
These two other components are also useful to make your life easier :
DMAmodule for more details)
With the exception of the RAM and the JTAG/SWD controller, every one of these hardware components is matched by a dedicated module in the library. The CPU is grouped with some other central features inside the
The library itself is only a folder. Its only dependencies are a working toolchain (as explained in the Getting Started tutorial), GNU make, and optionally OpenOCD. You will usually want to copy it inside your project folder (yes, there will be a copy for every project, but don't worry : it's very small and this will allow you to customize the library).
The two main parts of the library are the modules' code (inside
sam4l/) as explained above, and the Makefile.
A Makefile is some sort of script that is read and executed by the GNU make tool. It allows you to define settings and rules that can be used to compile your code or do about anything you want. All the operations defined by the library (such as compiling your program, flashing it into the microcontroller, …) are implemented with these rules. When compiling code, a Makefile is also smart : it will only compile the files that have been modified to save time.
This may sound complicated, but it is actualy really easy. For example, in order to compile your code, just go to your project directory with a terminal and type
make. That's it!
In order to execute a rule, type
make rule. Omiting the argument will execute the default rule which is, you guessed it, compiling the program. Here is the complete list of available rules :
make clean: clear every compiled files, to make sure the next
makewill re-compile everything from scratch (if you have modified the Makefile, make sure to do this to avoid weird behaviour)
make openocd: start a pre-configured OpenOCD session and connect to your JTAG/SWD adapter (you will usually do that in another terminal in background)
make flash: flash your program into the microcontroller using OpenOCD
make autoflash: flash your program into the microcontroller by automatically launching a temporary OpenOCD session
make erase: erase the microcontroller's Flash memory (i.e. the current program inside the microcontroller)
make pause: pause the microcontroller execution
make reset: reset the microcontroller
make debug: start a debug session with GDB
make flash-debug: shortcut to flash and immediately start a debug session
make bootloader: compile the bootloader
make flash-bootloader: flash the bootloader into the microcontroller using an existing OpenOCD session
make autoflash-bootloader: flash the bootloader into the microcontroller by automatically starting a temporary OpenOCD session
make debug-bootloader: start a debug session aimed at the bootloader
make flash-debug-bootloader: shortcut to flash the bootloader into the microcontroller and immediately start a debug session
make codeuploader: compile the codeuploader
make upload: flash your program using the bootloader using USB by default
make upload-usb: flash your program using the bootloader using USB
make upload-serial: flash your program using the bootloader using a Serial port
You probably won't have to modify the main library Makefile. As explained in the Getting Started tutorial, all you need to do is to create a Makefile in your project directory, set up a few settings, and include the main Makefile.
All the modules are built around the same structure : a namespace shared between a
.cpp file containing the code and a
.h header describing the module interface. In order to call a function inside a module namespace, use the following notation :
Module::function(), for example
Core::init(). Feel free to look inside the modules code if you are curious about how something works!
What are all those
const uint32_t OFFSET_... inside the header files?
At the lowest level, the program interacts with the microcontroller using registers. A register is a small memory space (usually 32-bit (4-byte) long), that have a defined address and a documented content. You can access it exactly like if it was in RAM, even though it is actually located inside a peripheral. Reading and writing registers is the most common way to control peripheral components. For example, there are write-only registers that allow you to issue commands, read-only registers that give you details about the controller status, and read-write registers with configuration settings.
OFFSET_... are register addresses. They are used internally by the module in order to operate, but you usually won't need to mess with them.
If you want more information about the registers, the datasheet is the place to go. You can also find more information in the Hacking section in the documentation of each module.
libtungsten can be used for projects ranging from very simple to very complex, and for this reason, some functions are aimed at more advanced users. Throughout the documentation, modules and functions follow a simple color code so that you know quickly if this is the feature you are looking for :