Skip to main content

HPM Environment Setup

An HPM project is a standard HPM SDK CMake project built with a RISC-V GCC toolchain (compiler prefix riscv32-unknown-elf-). The BSPs bsp-hpm5301evklite and bsp-rmcs-slave-lite are fully buildable projects and serve as the examples on this page; Code Generation describes how libxr hpm setup generates LibXR code in such a project.

Toolchain​

The HPM SDK reads the toolchain installation directory (the parent of bin) from the environment variable GNURISCV_TOOLCHAIN_PATH, and the compiler is bin/riscv32-unknown-elf-gcc inside it; when the variable is missing, the CMake configuration fails with GNURISCV_TOOLCHAIN_PATH is not set yet. The SDK itself is pointed to by HPM_SDK_BASE.

Sources of the toolchain:

  • Windows: the HPMicro development environment package sdk_env, whose toolchains/ directory holds the toolchain; the command line opened by start_cmd.cmd sets GNURISCV_TOOLCHAIN_PATH and the other environment variables;
  • Linux x64: the riscv32-unknown-elf toolchain published as hpm-linux-gcc-release v0.1.0;
  • Docker: ghcr.io/xrobot-org/docker-image-hpm:main ships that Linux toolchain (GCC 15.2.0) in /opt/hpm-riscv32-unknown-elf, with the path recorded in both GNURISCV_TOOLCHAIN_PATH and XR_HPM_TOOLCHAIN_ROOT, see Docker Environment Setup.

Project Layout​

Taking bsp-hpm5301evklite as the example:

.
|-- CMakeLists.txt
|-- CMakePresets.json
|-- app.yaml
|-- main.c
|-- boards/
| `-- hpm5301evklite/
| |-- tool_config.hpmpc
| |-- pinmux.c
| `-- ...
|-- cmake/
| `-- LibXR.CMake
|-- User/
| `-- app_main.cpp
`-- libxr/
  • CMakeLists.txt brings in the HPM SDK with find_package(hpm-sdk REQUIRED HINTS $ENV{HPM_SDK_BASE}), points BOARD_SEARCH_PATH at boards/, and sets CONFIG_DMA_MGR 1 (the HPM drivers of LibXR depend on the SDK's dma_mgr component)
  • app.yaml declares the dependency on board_gpt_pin; boards/<board>/ contains the single .hpmpc file (the BSPs name it tool_config.hpmpc); libxr hpm setup and the VS Code extension recognize an HPM project by these two
  • boards/<board>/pinmux.c is generated by the HPM Pinmux Tool from tool_config.hpmpc and provides init_bsp_pins()
  • main.c sits in the project root: a board clock function first adds the GPIO clock to the clock group (init_board_clock() in bsp-hpm5301evklite, board_init_clock_group() in bsp-rmcs-slave-lite), then init_bsp_pins(), then the SDK board's board_init() and the clock functions of the peripherals (init_uart3_clock() and its siblings), and finally app_main(). Until the GPIO clock is in the clock group, the GPIO directions and levels set by init_bsp_pins() have no effect
  • User/ holds the generated app_main.cpp; libxr hpm setup generates libxr_config.yaml next to it
  • libxr/ is the LibXR submodule

Build​

CMakePresets.json provides the debug-flash-xip, debug-ram and release-flash-xip presets (Ninja generator, HPM_BUILD_TYPE of flash_xip or ram). The BSP uses XRobot Modules, so xrobot setup runs once before configuring; it fetches the Modules from xrobot.lock and generates Modules/CMakeLists.txt:

xrobot setup
cmake --preset release-flash-xip
cmake --build --preset release-flash-xip

The artifacts land in build/output/, for example demo.elf and demo.bin.

CMake Integration​

cmake/LibXR.CMake selects the platform with three variables and adds LibXR as a subproject:

set(LIBXR_SYSTEM None)
set(LIBXR_DRIVER hpm)
set(LIBXR_NO_EIGEN True)

xr links ${HPM_SDK_LIB_ITF}, so LibXR compiles with the same options and include paths as the SDK; the application target app and the final ELF target link xr. Toolchain detection is handled by find_package(hpm-sdk).

The LibXR HPM Drivers​

The drivers in driver/hpm are added to the build by the directory's CMakeLists.txt:

  • hpm_gpio.*: GPIO
  • hpm_i2c.*: I2C master
  • hpm_pwm.*: PWM
  • hpm_timebase.*: timebase on MCHTMR
  • hpm_dma.*: initializes the SDK's dma_mgr once, for the DMA background path of the I2C

The drivers call SDK driver functions only; pin muxing, clocks and the initialization order belong to the project (init_bsp_pins(), board_init() and the init_*_clock() functions), and the LibXR objects are created in app_main(). The drivers depend on the SDK's dma_mgr component, which the BSPs enable with CONFIG_DMA_MGR 1.

HPMI2C implements the LibXR I2C master abstraction on top of the SDK's hpm_i2c_drv: blocking byte-stream transfers and register/memory-address transfers; 7-bit master addressing by default with SetAddressMode() switching to the SDK's 10-bit master addressing; wait strategies such as POLLING and CALLBACK can use the DMA-backed path on dma_mgr; on typical master failures such as a timeout, a busy bus or no response, the driver rebuilds the controller with its most recent successful configuration.

HPMPWM takes the same constructor arguments on both code paths (peripheral address, clock, output channel index, comparator index, polarity): SoCs with a standard PWM peripheral go through the SDK's hpm_pwm_drv, the others through the GPTMR path. SetDutyCycle() accepts a duty cycle of 0.0 to 1.0, and SetConfig() sets the frequency.

Docker Build​

The image ghcr.io/xrobot-org/docker-image-hpm:main ships the RISC-V toolchain (GCC 15.2.0), CMake, Ninja and the HPM SDK v1.13.0, with GNURISCV_TOOLCHAIN_PATH and HPM_SDK_BASE already set:

docker run --rm -v "$PWD:/work" -w /work ghcr.io/xrobot-org/docker-image-hpm:main \
bash -c 'pip install xrobot==1.0.1 && xrobot setup && cmake --preset release-flash-xip && cmake --build --preset release-flash-xip'