Source tree


This page presents the Dooba SDK source tree.
It is located at /src in the SDK distribution.


The source tree is simple: every sub-directory within it represents a Firmware Element.

Such an element can be either a library (a collection of re-usable methods and definitions) or an application (a solution built for a specific hardware target).

Element definition

Firmware elements are defined by a file placed within their directory named dfe.conf.
This file should follow a YAML structure and may contain the following fields:

  • name - The name of the element
  • type - Either app or lib
  • mmcu - ("type: app" only) Target microcontroller
  • freq - ("type: app" only) Target microcontroller CPU frequency
  • deps - List of immediate dependencies
  • compiler_options - List of compiler options
  • linker_options - List of linker options

Below is an example of a simple dfe.conf element definition: the hello_world application:

# Dooba Firmware Element Configuration

name: hello_world
type: app
mmcu: atmega1284p
freq: 10000000L

Library definitions are often very short:

# Dooba Firmware Element Configuration

name: i2c
type: lib

What can we build?

First and obvious, .c files will be compiled as C code.
Aside from that, other formats are handled by the build process:

Binary resources

Binary resources such as images, sounds, or any other non-code element can be embedded into any library or application.
Any file with a .bin extension will be converted into a C source file and header. This will ensure that the resource's data (inside the C source file) will be included in the final object.
Also, the associated header file allows accessing the resource from C code.

The resource's size will be defined (in bytes) as XXX_DATA_SIZE, where XXX is the name of the resource file without the .bin extension, capitalized and with all occurences of '.' (dot), ' ' (space) and '-' (hyphen) replaced with '_' (underscore).
For example, a file called foobar.bin containing six bytes would produce the following:

#define FOOBAR_DATA_SIZE     6
extern uint8_t foobar_data[FOOBAR_DATA_SIZE];

SSD1306 Images

The SSD1306 is an OLED controller commonly found on monochrome displays.
A library is provided with the SDK to control such devices.

Raw image data (such as exported from Gimp using "raw" output) can be placed in a firmware element with a name ending with .WIDTH.HEIGHT.ssd1306_img, where WIDTH & HEIGHT are to be replaced with the image's size in pixels.
Such a file would be transformed for easy drawing to the display (adapted to framebuffer format) and converted into a .bin resource file.

Note: image height MUST be a multiple of 8 (8, 16, 32, ...).

For example, a 32x48 (32 wide, 48 high) image called foobar could be stored as foobar.32.48.ssd1306_img, and would be accessible from the code as foobar_data and FOOBAR_DATA_SIZE.

More examples

A heavier application example is the Shiva MP3 player:

# Dooba Firmware Element Configuration

name: shiva
type: app
mmcu: atmega1284p
freq: 10000000L
  - ionode
  - fatfs
  - sdcard
  - ssd1306
  - mcp23008
  - sta013
  - lm4811
  - scom
  - i2c

Finally, a curious and rather uncommon example is the kiwi bootloader.
This one requires additional compiler and linker flags:

# Dooba Firmware Element Configuration

name: kiwi
type: app
mmcu: atmega1284p
freq: 10000000L

  - -fno-split-wide-types
  - -mrelax

  - -fno-split-wide-types
  - -mrelax
  - -Wl,--section-start=.text=0x1fc00
  - -Wl,--section-start=.version=0x1fffe
  - -nostartfiles
  - -nostdlib

A word on dependencies

Whether defining an application or a library, if you wish to rely on another library within the source tree, you need to add it to the list of dependencies - deps.
However, everything is built recursively, so you only need to list out immediate dependencies for your element. No need to worry about your dependency's dependencies.

As you may have seen in some of the examples above, defining this list is done as follows:

  - scom
  - i2c


When run, the build script (./dbuild) first collects all firmware elements and parses their definitions. All applications are then selected from the tree and built one after the other.
Building an application implies recursively building all of its dependencies. While doing so, the build scripts also recursively collects compiler & linker definitions, passing them along to dependencies.

When re-using libraries for embedded hardware designs it is fairly common to have different pin setups or connector configurations (compared to the "default" configurations of some libraries). This build model offers a transparent and simple approach to overriding compiler definitions from the application level, without needing to touch the libraries.

Build output

Applications are built as .hex files, and placed in the /out/bin folder.