ð Creating a new Project
In this example we create a project using the CMake build system.
In order to make a project you need 5 files:
conanfile.txt: list of project dependencies.CMakeLists.txt: instructions describing the project's source files, executables and how to build them.main.cpp: application softwarelibhal.tweaks.hpp: configuration file for libhalnewlib.cpp: definitions of low level C functions
Quick Start
Clone this starter project:
git clone https://github.com/libhal/libhal-starter.git
Creating the conanfile.txt
A standard libhal conanfile.txt will look like this:
[requires]
libhal-lpc40/1.1.6
[tool_requires]
gnu-arm-embedded-toolchain/11.3.0
cmake-arm-embedded/0.1.1
[generators]
CMakeToolchain
CMakeDeps
[requires]lists the project dependencies.- Each libhal project needs a target library and this example uses
libhal-lpc40which is used for the SJ2 board or the LPC4078 micromod.
- Each libhal project needs a target library and this example uses
[tool_requires]lists the tools that are needed to build the project.gnu-arm-embedded-toolchain/11.3.0brings in the ARM GCC cross compiler which is used to compile to the code for ARM Cortex microcontroller.cmake-arm-embedded/0.1.1brings in cmake helper scripts and toolchain files for configuring cmake for the cross compiler.
[generators]list the generators which generate files for the project build systems.CMakeToolchain: Generates toolchain cmake scripts based on the conan package recipe information.CMakeDeps: Generates cmake package/configuration files for each library which can be
Making the CMakeLists.txt file
Below is the minimal amount of cmake code needed for a libhal project:
cmake_minimum_required(VERSION 3.20)
project(project_name.elf VERSION 0.0.1 LANGUAGES CXX)
find_package(libhal-lpc40 REQUIRED CONFIG)
add_executable(${PROJECT_NAME} main.cpp newlib.cpp)
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
target_include_directories(${PROJECT_NAME} PUBLIC .)
target_link_libraries(${PROJECT_NAME} PRIVATE libhal::lpc4078)
arm_cortex_post_build(${PROJECT_NAME})
If you are unfamiliar with cmake, please take a look at the guide An Introduction to Modern CMake.
There are a few elements of the CMakeList.txt file which do not standard CMake:
libhal::lpc4078: Defines the specific package component for the thelpc4078micro-controller. Using this component will automatically use the minimum required compiler and link flags for the microcontroller as well as use the standard linker script for the device.arm_cortex_post_build(${PROJECT_NAME}): Provided by the toolchain file in thecmake-arm-embeddedtool package. Generates the.hex(intel hex),.bin(binary),.S(disassembly) and.lst(disassembly with source interweaved).
Writing main.cpp
Read through the source code below to get an idea of whats needed:
#include <libhal-armcortex/dwt_counter.hpp>
#include <libhal-armcortex/startup.hpp>
#include <libhal-armcortex/system_control.hpp>
#include <libhal-lpc40/output_pin.hpp>
#include <libhal-lpc40/system_controller.hpp>
#include <libhal-util/steady_clock.hpp>
int
main()
{
using namespace hal::literals;
using namespace std::literals;
// Initializing the data section initializes global and static variables and
// is required for the standard C library to run.
hal::cortex_m::initialize_data_section();
hal::cortex_m::system_control::initialize_floating_point_unit();
// Create a hardware counter
auto& clock = hal::lpc40xx::clock::get();
auto cpu_frequency = clock.get_frequency(hal::lpc40xx::peripheral::cpu);
static hal::cortex_m::dwt_counter steady_clock(cpu_frequency);
// Get an output pin to use as the LED pin control
auto& led_pin = hal::lpc40xx::output_pin::get<1, 18>().value();
while (true) {
(void)led_pin.level(true);
(void)hal::delay(steady_clock, 500ms);
(void)led_pin.level(false);
(void)hal::delay(steady_clock, 500ms);
}
return 0;
}
// When libhal.tweaks.hpp includes:
//
// #define BOOST_LEAF_EMBEDDED
// #define BOOST_LEAF_NO_THREADS
//
// Then Boost.LEAF needs this function to be defined
namespace boost {
void
throw_exception([[maybe_unused]] std::exception const& p_error)
{
std::abort();
}
} // namespace boost
The newlib.cpp file
The newlib.cpp contains low level APIs used by the standard C library. With an
OS these are implemented with OS APIs. For example, the function that provides
memory to malloc() is the newlib API sbrk().
To learn more about how to write newlib.cpp see From Zero to main():
Bootstrapping libc with
Newlib.
See libhal-starter/newlib.cpp for the default empty implementations.
Compiling the project
The command for building the project:
conan build .