Skip to content

Discover modm

modm uses the lbuild code generator to discover available modules and their configuration options. Let's use the lbuild CLI to poke around modm!

Make sure you've installed all tools required for building modm and you've cloned the modm repository recursively and change directory into modm:

git clone --recurse-submodules --jobs 8 https://github.com/modm-io/modm.git
cd modm

lbuild operates on repositories which contain modules and options in a tree format. The modm/repo.lb file must be declared to find all modm modules:

 $ lbuild --repository repo.lb discover
Parser(lbuild)
╰── Repository(modm @ .)   modm: a barebone embedded library generator
    ├── Option(target) = REQUIRED in [stm32f469ngh6, stm32f469nih6, stm32f469vet6, ...
    ├── Config(modm:disco-f469ni:b-03) in [b-01, b-03]   STM32F469IDISCOVERY
   ...

This gives you an overview of the repositories and their options and configurations. Here you can see the modm:target option is marked as REQUIRED, since the HAL modules obviously depend on the target device, so we need to discover the option in detail:

 $ lbuild -r repo.lb discover modm:target
>> modm:target  [TargetOption]

Meta-HAL target device

Value: REQUIRED
Inputs: [at90can128-16ai, at90can128-16au, at90can128-16mi, at90can128-16mu,
         ... a really long list ...
        stm32l4s9aii6, stm32l4s9vit6, stm32l4s9zij6, stm32l4s9zit6, stm32l4s9ziy6]

Options are checked

lbuild checks all your project options against the possible values in the module and outputs an error if they are incorrect. Try passing a wrong value to see what happens.

You can now choose a value for this repository option and discover the available modules for this specific target. We will choose the stm32f469nih6 device:

 $ lbuild -r repo.lb --option modm:target=stm32f469nih6 discover
Parser(lbuild)
╰── Repository(modm @ .)   modm: a barebone embedded library generator
    ├── Option(target) = stm32f469nih6 in [stm32f407vgt6, stm32f469nih6, ...
    ├── Config(modm:disco-f469ni:b-03) in [b-01, b-03]   STM32F469IDISCOVERY
   ...
    ├── Module(modm:board)   Board Support Packages
    │   ╰── Module(modm:board:disco-f469ni)   STM32F469IDISCOVERY
   ...
    ├── Module(modm:build)   Build System Generators
    │   ├── Option(build.path) = build/parent-folder in [String]
    │   ├── Option(project.name) = parent-folder in [String]
    │   ╰── Module(modm:build:scons)  SCons Build Script Generator
   ...
    ├── Module(modm:platform)   Platform HAL
    │   ├── Module(modm:platform:cortex-m)   ARM Cortex-M Core
    │   │   ├── Option(float-abi) = hard in [hard, soft, softfp]   Floating point ABI
    │   │   ├── Option(main_stack_size) = 3Ki (3072) in [256 .. 3Ki .. 64Ki]
    │   │   ├── Option(vector_table_location) = rom in [ram, rom]   Vector table location
   ... ...
    │   ├── Module(modm:platform:uart)   Universal Asynchronous Receiver Transmitter (UART)
    │   │   ├── Module(modm:platform:uart:1)   Instance 1
    │   │   │   ├── Option(buffer.rx) = 0 in [0 ... 64Ki-2]
    │   │   │   ╰── Option(buffer.tx) = 0 in [0 ... 64Ki-2]

Since there are no more REQUIRED options, you can now discover all module and option descriptions. Let's have a look at the modm:platform:cortex-m module, which deals with the startup code of Cortex-M devices. Note that you can leave out parts of any name as long as it remains unique:

 $ lbuild -r repo.lb -D :target=stm32f469nih6 discover ::cortex-m
>> modm:platform:cortex-m  [Module]

# ARM Cortex-M Core

This module generates the startup code, vector table, linkerscript as well as
initialize the heap, deal with assertions, provide blocking delay functions,
atomic and unaligned access and the GNU build ID.

>>>> modm:platform:cortex-m:vector_table_location  [EnumerationOption]

# Vector table location in ROM or RAM

The vector table is always stored in ROM and copied to RAM by the startup script
if required. You can modify the RAM vector table using the CMSIS NVIC functions:

- `void NVIC_SetVector(IRQn_Type IRQn, uint32_t vector)`
- `uint32_t NVIC_GetVector(IRQn_Type IRQn)`

Value: rom
Inputs: [ram, rom]

Once you've made your choices about which modules and options you want, you can generate a custom modm library using the build command:

lbuild -r repo.lb -D :target=stm32f469nih6 -D :::vector_table_location=ram \
    build --module ::cortex-m

Which will create a folder modm at the callsite which contains the minimal startup code for the STM32F469NIH6 device.

 $ tree modm
modm
├── ext
│   └── cmsis
│       └── device
│           ├── stm32f469xx.h
│           └── system_stm32f4xx.h
└── src
    └── modm
        ├── platform
        │   ├── core
        │   │   ├── reset_handler.sx
        │   │   ├── startup.c
        │   │   └── vectors.c
        │   └── device.hpp
        └── platform.hpp

However, declaring everything on the command line is a bit annoying, so instead we can create a project.xml with the same information:

<library>

  <repositories>
    <repository>
      <path>repo.lb</path>
    </repository>
  </repositories>

  <options>
    <option name="modm:target">stm32f469nih6</option>
    <option name="modm:platform:cortex-m:vector_table_location">ram</option>
  </options>

  <modules>
    <module>modm:platform:cortex-m</module>
  </modules>

</library>

This file is now automatically used for all calls to lbuild:

lbuild discover
lbuild build

You can read the lbuild reference manual if you want to know the details about config inheritance, collectors and queries. You can discover the whole repository view with the --developer option:

lbuild discover --developer