Your First Nexus Application¶
This tutorial guides you through creating your first Nexus application from scratch. You’ll learn how to set up a project, configure the build system, and create a simple LED blinky application.
Learning Objectives¶
By the end of this tutorial, you will:
Understand the basic structure of a Nexus application
Know how to configure CMake for Nexus projects
Be able to initialize the HAL subsystem
Create and control GPIO devices
Build and flash your application to hardware
Prerequisites¶
Before starting, ensure you have:
Completed the Environment Setup guide
A supported development board (we’ll use STM32F4 Discovery)
ARM GCC toolchain installed
OpenOCD or ST-Link tools for flashing
See also
Build System - Build system overview
Hardware Abstraction Layer (HAL) - HAL API documentation
STM32F4 Platform Guide - STM32F4 platform guide
GPIO Control Tutorial - GPIO control tutorial
Kconfig Tutorial - Configuration tutorial
Step 1: Create Project Structure¶
First, create a new directory for your project:
mkdir my_first_nexus_app
cd my_first_nexus_app
Create the following directory structure:
my_first_nexus_app/
├── CMakeLists.txt
├── main.c
└── nexus/ (git submodule or copy of Nexus)
Step 2: Add Nexus as Dependency¶
You can add Nexus to your project in two ways:
Option A: Git Submodule (Recommended)
git init
git submodule add https://github.com/X-Gen-Lab/nexus.git nexus
git submodule update --init --recursive
Option B: Copy Nexus
cp -r /path/to/nexus ./nexus
Step 3: Create CMakeLists.txt¶
Create CMakeLists.txt with the following content:
cmake_minimum_required(VERSION 3.16)
# Project name and language
project(my_first_nexus_app C ASM)
# Set C standard
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Add Nexus as subdirectory
add_subdirectory(nexus)
# Create executable
add_executable(${PROJECT_NAME}
main.c
)
# Link against Nexus libraries
target_link_libraries(${PROJECT_NAME} PRIVATE
nexus::hal
nexus::platform
)
# Set output name
set_target_properties(${PROJECT_NAME} PROPERTIES
OUTPUT_NAME "app"
)
Understanding the CMakeLists.txt:
add_subdirectory(nexus)- Includes Nexus build systemnexus::hal- Links the Hardware Abstraction Layernexus::platform- Links platform-specific code
Step 4: Write Your First Application¶
Create main.c with a simple LED blinky:
/**
* \file main.c
* \brief My First Nexus Application
* \author Your Name
*/
#include "hal/hal.h"
/*-----------------------------------------------------------------------*/
/* Configuration */
/*-----------------------------------------------------------------------*/
/** LED pin definitions for STM32F4 Discovery */
#define LED_PORT HAL_GPIO_PORT_D
#define LED_PIN 12 /* Green LED */
/** Blink delay in milliseconds */
#define BLINK_DELAY_MS 500
/*-----------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------*/
/**
* \brief Initialize LED GPIO
* \return HAL_OK on success, error code otherwise
*/
static hal_status_t led_init(void) {
/* Configure GPIO as output */
hal_gpio_config_t config = {
.direction = HAL_GPIO_DIR_OUTPUT,
.pull = HAL_GPIO_PULL_NONE,
.output_mode = HAL_GPIO_OUTPUT_PP,
.speed = HAL_GPIO_SPEED_LOW,
.init_level = HAL_GPIO_LEVEL_LOW
};
/* Initialize GPIO */
return hal_gpio_init(LED_PORT, LED_PIN, &config);
}
/*-----------------------------------------------------------------------*/
/* Main Function */
/*-----------------------------------------------------------------------*/
/**
* \brief Main entry point
* \return Should never return
*/
int main(void) {
/* Initialize HAL subsystem */
if (hal_init() != HAL_OK) {
/* Initialization failed - stay in error loop */
while (1) {
/* Error state */
}
}
/* Initialize LED */
if (led_init() != HAL_OK) {
/* LED initialization failed */
while (1) {
/* Error state */
}
}
/* Main loop: blink LED */
while (1) {
/* Toggle LED state */
hal_gpio_toggle(LED_PORT, LED_PIN);
/* Wait for blink period */
hal_delay_ms(BLINK_DELAY_MS);
}
return 0;
}
Understanding the Code:
HAL Initialization:
hal_init()initializes the HAL subsystem, including system clock, SysTick timer, and platform-specific hardware.GPIO Configuration: The
hal_gpio_config_tstructure defines GPIO behavior:direction: Input or output modepull: Pull-up, pull-down, or noneoutput_mode: Push-pull or open-drainspeed: GPIO speed (low, medium, high, very high)init_level: Initial output level (high or low)
GPIO Operations:
hal_gpio_init(): Initialize GPIO with configurationhal_gpio_toggle(): Toggle GPIO output statehal_delay_ms(): Blocking delay in milliseconds
Step 5: Build for Native Platform (Testing)¶
First, let’s build for the native platform to test our code structure:
# Configure for native platform
CMake -B build-native -DNEXUS_PLATFORM=native
# Build
CMake --build build-native
# Run (LED operations will be simulated)
./build-native/app
The native platform is useful for:
Testing application logic without hardware
Running unit tests
Debugging on your development machine
Step 6: Build for STM32F4¶
Now let’s build for the actual target hardware:
# Configure for STM32F4 with ARM toolchain
CMake -B build-stm32f4 \
-DCMAKE_TOOLCHAIN_FILE=nexus/CMake/toolchains/arm-none-eabi.CMake \
-DNEXUS_PLATFORM=stm32f4
# Build
CMake --build build-stm32f4
This creates build-stm32f4/app.elf and build-stm32f4/app.bin files.
Step 7: Flash to Hardware¶
Using OpenOCD:
# Flash with OpenOCD
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg \
-c "program build-stm32f4/app.elf verify reset exit"
Using ST-Link Utility (Windows):
Open ST-Link Utility
Connect to the board
Load
build-stm32f4/app.binat address0x08000000Click “Program & Verify”
Using st-flash (Linux/macOS):
st-flash write build-stm32f4/app.bin 0x08000000
Step 8: Verify Operation¶
After flashing:
The green LED (PD12) on the STM32F4 Discovery board should blink
The LED should toggle every 500ms
Press the reset button to restart the application
If the LED doesn’t blink:
Check that the board is powered
Verify the correct LED pin is configured
Check that the application was flashed successfully
Try debugging with GDB (see Testing)
Understanding HAL Initialization¶
The hal_init() function performs several important tasks:
System Clock Configuration: Sets up the main system clock (typically 168 MHz for STM32F4)
SysTick Timer: Configures the SysTick timer for
hal_delay_ms()andhal_get_tick()FPU Initialization: Enables the Floating Point Unit (if available)
Platform-Specific Setup: Initializes platform-specific hardware
Always call hal_init() before using any HAL functions.
GPIO Configuration Options¶
The hal_gpio_config_t structure provides fine-grained control:
Direction:
HAL_GPIO_DIR_INPUT: Configure as inputHAL_GPIO_DIR_OUTPUT: Configure as output
Pull Resistors:
HAL_GPIO_PULL_NONE: No pull resistorHAL_GPIO_PULL_UP: Enable pull-up resistorHAL_GPIO_PULL_DOWN: Enable pull-down resistor
Output Mode:
HAL_GPIO_OUTPUT_PP: Push-pull output (can drive high and low)HAL_GPIO_OUTPUT_OD: Open-drain output (can only pull low)
Speed:
HAL_GPIO_SPEED_LOW: Low speed (2 MHz)HAL_GPIO_SPEED_MEDIUM: Medium speed (25 MHz)HAL_GPIO_SPEED_HIGH: High speed (50 MHz)HAL_GPIO_SPEED_VERY_HIGH: Very high speed (100 MHz)
For LED control, low speed is sufficient. Use higher speeds for high-frequency signals.
Common Issues and Solutions¶
Issue: Build fails with “nexus not found”
Solution: Ensure Nexus is properly added as a subdirectory and the path in add_subdirectory() is correct.
Issue: Linker errors about undefined references
Solution: Make sure you’re linking against the correct Nexus libraries (nexus::hal and nexus::platform).
Issue: Application doesn’t run after flashing
Solution:
- Verify the correct flash address (0x08000000 for STM32F4)
- Check that the toolchain file is specified correctly
- Ensure the platform is set to stm32f4
Issue: LED doesn’t blink
Solution:
- Verify the LED pin number matches your board
- Check that hal_init() succeeded
- Try a longer delay to make blinking more visible
Next Steps¶
Congratulations! You’ve created your first Nexus application. Now you can:
GPIO Control Tutorial - Learn advanced GPIO techniques
UART Communication Tutorial - Add serial communication
Multi-Tasking with OSAL - Create multi-tasking applications
Explore the Hardware Abstraction Layer (HAL) for more HAL features
Additional Exercises¶
Try these exercises to reinforce your learning:
Multiple LEDs: Modify the code to blink all four LEDs on the STM32F4 Discovery board in sequence
Variable Speed: Add a button to change the blink speed when pressed
Pattern: Create a custom blink pattern (e.g., two quick blinks, pause, repeat)
Error Handling: Add more robust error handling with LED error indicators
Example: Blinking Multiple LEDs¶
/* LED definitions */
#define LED_GREEN_PORT HAL_GPIO_PORT_D
#define LED_GREEN_PIN 12
#define LED_ORANGE_PORT HAL_GPIO_PORT_D
#define LED_ORANGE_PIN 13
#define LED_RED_PORT HAL_GPIO_PORT_D
#define LED_RED_PIN 14
#define LED_BLUE_PORT HAL_GPIO_PORT_D
#define LED_BLUE_PIN 15
/* Initialize all LEDs */
static hal_status_t leds_init(void) {
hal_gpio_config_t config = {
.direction = HAL_GPIO_DIR_OUTPUT,
.pull = HAL_GPIO_PULL_NONE,
.output_mode = HAL_GPIO_OUTPUT_PP,
.speed = HAL_GPIO_SPEED_LOW,
.init_level = HAL_GPIO_LEVEL_LOW
};
if (hal_gpio_init(LED_GREEN_PORT, LED_GREEN_PIN, &config) != HAL_OK) {
return HAL_ERR_FAIL;
}
if (hal_gpio_init(LED_ORANGE_PORT, LED_ORANGE_PIN, &config) != HAL_OK) {
return HAL_ERR_FAIL;
}
if (hal_gpio_init(LED_RED_PORT, LED_RED_PIN, &config) != HAL_OK) {
return HAL_ERR_FAIL;
}
if (hal_gpio_init(LED_BLUE_PORT, LED_BLUE_PIN, &config) != HAL_OK) {
return HAL_ERR_FAIL;
}
return HAL_OK;
}
/* Main loop with sequence */
while (1) {
hal_gpio_toggle(LED_GREEN_PORT, LED_GREEN_PIN);
hal_delay_ms(250);
hal_gpio_toggle(LED_ORANGE_PORT, LED_ORANGE_PIN);
hal_delay_ms(250);
hal_gpio_toggle(LED_RED_PORT, LED_RED_PIN);
hal_delay_ms(250);
hal_gpio_toggle(LED_BLUE_PORT, LED_BLUE_PIN);
hal_delay_ms(250);
}
Best Practices¶
Always Initialize HAL First: Call
hal_init()before using any HAL functionsCheck Return Values: Always check return values from HAL functions for errors
Use Appropriate GPIO Speed: Don’t use high-speed GPIO for slow signals (wastes power)
Document Pin Assignments: Clearly document which pins are used for what purpose
Error Handling: Implement proper error handling with visual indicators (LEDs)
Code Organization: Keep initialization code separate from main loop logic
Use Meaningful Names: Use descriptive names for constants and functions
Resources¶
Hardware Abstraction Layer (HAL) - Complete HAL API documentation
STM32F4 Platform Guide - STM32F4-specific information
Build System - Advanced build configuration