### CAN Bus Communication Setup and Message Handling (C) Source: https://context7.com/uni-libraries/uni.hal/llms.txt Illustrates the setup and usage of the CAN module for bus communication. It covers GPIO pin configuration, CAN initialization, setting up message filters, starting the CAN interface, transmitting messages, and receiving messages with a timeout. It also shows how to stop the CAN interface. ```c #include "uni_hal.h" // Define CAN pins uni_hal_gpio_pin_context_t can1_rx = { .gpio_bank = UNI_HAL_CORE_PERIPH_GPIO_D, .gpio_pin = UNI_HAL_GPIO_PIN_0, .gpio_type = UNI_HAL_GPIO_TYPE_ALTERNATE_PP, .alternate = UNI_HAL_GPIO_ALTERNATE_9 }; uni_hal_gpio_pin_context_t can1_tx = { .gpio_bank = UNI_HAL_CORE_PERIPH_GPIO_D, .gpio_pin = UNI_HAL_GPIO_PIN_1, .gpio_type = UNI_HAL_GPIO_TYPE_ALTERNATE_PP, .alternate = UNI_HAL_GPIO_ALTERNATE_9, .gpio_speed = UNI_HAL_GPIO_SPEED_2 }; // CAN context uni_hal_can_context_t can1_ctx = { .config = { .instance = UNI_HAL_CORE_PERIPH_CAN_1, .pin_rx = &can1_rx, .pin_tx = &can1_tx } }; void can_example(void) { // Initialize CAN if (!uni_hal_can_init(&can1_ctx)) { return; } // Set up message filter (accept IDs 0x100-0x1FF) uni_hal_can_set_filter( &can1_ctx, 0, // FIFO number 0, // Filter slot index 0x100, // Filter ID 0x700 // Filter mask (match upper bits) ); // Start CAN interface uni_hal_can_start(&can1_ctx); // Transmit a CAN message uni_hal_can_msg_t tx_msg = { .id = 0x123, .dlc = 8, .data = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08} }; uni_hal_can_transmit(&can1_ctx, &tx_msg); // Receive CAN messages (blocking with timeout) while (1) { uni_hal_can_msg_t rx_msg; // Check if messages are available uint32_t available = uni_hal_can_is_available(&can1_ctx); // Receive with 100ms timeout if (uni_hal_can_receive(&can1_ctx, &rx_msg, 100)) { // Process received message uint32_t msg_id = rx_msg.id; uint8_t msg_len = rx_msg.dlc; // rx_msg.data contains the payload } } // Stop CAN when done uni_hal_can_stop(&can1_ctx); } ``` -------------------------------- ### Complete System Initialization with Uni.HAL and FreeRTOS Source: https://context7.com/uni-libraries/uni.hal/llms.txt Initializes core hardware components like RCC, PWR, SysTick, DWT, and IRQs. Configures a debug UART for output and a GPIO pin for an LED. Sets up an independent watchdog timer. Creates and starts a FreeRTOS task for periodic LED toggling and watchdog reloading. This example requires the uni_hal.h, FreeRTOS.h, and task.h headers. ```c #include "uni_hal.h" #include #include // GPIO definitions uni_hal_gpio_pin_context_t led_green = { .gpio_bank = UNI_HAL_CORE_PERIPH_GPIO_B, .gpio_pin = UNI_HAL_GPIO_PIN_0, .gpio_type = UNI_HAL_GPIO_TYPE_OUT_PP, .gpio_speed = UNI_HAL_GPIO_SPEED_2, .gpio_init = false }; // UART definitions UNI_HAL_IO_DEFINITION(debug_io, 512, 256); uni_hal_gpio_pin_context_t debug_tx = { .gpio_bank = UNI_HAL_CORE_PERIPH_GPIO_A, .gpio_pin = UNI_HAL_GPIO_PIN_9, .gpio_type = UNI_HAL_GPIO_TYPE_ALTERNATE_PP, .alternate = UNI_HAL_GPIO_ALTERNATE_7, .gpio_speed = UNI_HAL_GPIO_SPEED_2 }; uni_hal_gpio_pin_context_t debug_rx = { .gpio_bank = UNI_HAL_CORE_PERIPH_GPIO_A, .gpio_pin = UNI_HAL_GPIO_PIN_10, .gpio_type = UNI_HAL_GPIO_TYPE_ALTERNATE_PP, .alternate = UNI_HAL_GPIO_ALTERNATE_7, .gpio_pull = UNI_HAL_GPIO_PULL_UP }; uni_hal_usart_context_t debug_uart = { .instance = UNI_HAL_CORE_PERIPH_UART_1, .baudrate = 115200, .clksrc = UNI_HAL_RCC_CLKSRC_SYSCLK, .pin_rx = &debug_rx, .pin_tx = &debug_tx, .io = &debug_io_ctx, .isr_priority = 6 }; // Watchdog uni_hal_iwdg_context_t watchdog = { .instance = UNI_HAL_CORE_PERIPH_IWDG_1, .watchdog_prescaler = 256, .watchdog_counter = 2000 }; void hardware_init(void) { // Initialize core systems uni_hal_rcc_init(); uni_hal_pwr_init(); uni_hal_systick_init(); uni_hal_dwt_init(); uni_hal_core_irq_init(); // Initialize debug UART uni_hal_io_init(&debug_io_ctx); uni_hal_usart_init(&debug_uart); uni_hal_usart_receive_enable(&debug_uart, true); uni_hal_usart_transmit_enable(&debug_uart, true); // Initialize STDIO for debug output uni_hal_io_stdio_init(&debug_io_ctx); uni_hal_io_stdio_printf("System starting...\r\n"); // Initialize GPIO uni_hal_gpio_pin_init(&led_green); // Initialize watchdog uni_hal_iwdg_init(&watchdog); uni_hal_io_stdio_printf("Hardware initialized\r\n"); } void main_task(void *params) { while (1) { // Toggle LED bool state = uni_hal_gpio_pin_get(&led_green); uni_hal_gpio_pin_set(&led_green, !state); // Reload watchdog uni_hal_iwdg_reload(&watchdog); // Task delay vTaskDelay(pdMS_TO_TICKS(500)); } } int main(void) { hardware_init(); // Create FreeRTOS task xTaskCreate(main_task, "main", 512, nullptr, 1, nullptr); // Start scheduler vTaskStartScheduler(); // Should never reach here while (1) {} } ``` -------------------------------- ### Configure and Control GPIO Pins with Uni.HAL Source: https://context7.com/uni-libraries/uni.hal/llms.txt This C code demonstrates how to initialize and control GPIO pins using the Uni.HAL library. It covers setting up output pins for LEDs and input pins with interrupt callbacks for buttons. The example shows pin initialization, interrupt configuration, and basic I/O operations. ```c #include "uni_hal.h" // Define a GPIO pin context for an LED on Port B, Pin 0 uni_hal_gpio_pin_context_t led_pin = { .gpio_bank = UNI_HAL_CORE_PERIPH_GPIO_B, .gpio_pin = UNI_HAL_GPIO_PIN_0, .gpio_type = UNI_HAL_GPIO_TYPE_OUT_PP, // Push-pull output .gpio_pull = UNI_HAL_GPIO_PULL_NO, .gpio_speed = UNI_HAL_GPIO_SPEED_2, .gpio_init = false, // Initial state LOW .inited = false }; // Define an input pin with interrupt callback uni_hal_gpio_pin_context_t button_pin = { .gpio_bank = UNI_HAL_CORE_PERIPH_GPIO_C, .gpio_pin = UNI_HAL_GPIO_PIN_13, .gpio_type = UNI_HAL_GPIO_TYPE_IN_DIGITAL, .gpio_pull = UNI_HAL_GPIO_PULL_UP, .gpio_speed = UNI_HAL_GPIO_SPEED_0, .inited = false }; // Interrupt callback function bool button_callback(void *cookie) { bool *flag = (bool *)cookie; *flag = true; return false; // Return true if context switch required } void gpio_example(void) { // Initialize GPIO pins if (!uni_hal_gpio_pin_init(&led_pin)) { // Handle initialization error return; } if (!uni_hal_gpio_pin_init(&button_pin)) { return; } // Set up interrupt on button pin (falling edge) bool button_pressed = false; uni_hal_gpio_pin_set_interrupt_callback( &button_pin, UNI_HAL_GPIO_IT_EDGE_FALLING, button_callback, &button_pressed ); // Toggle LED based on button state while (1) { if (button_pressed) { bool current_state = uni_hal_gpio_pin_get(&led_pin); uni_hal_gpio_pin_set(&led_pin, !current_state); button_pressed = false; } } } ``` -------------------------------- ### Configure and Control Timer for Input Capture - C Source: https://context7.com/uni-libraries/uni.hal/llms.txt Illustrates the configuration and usage of the Timer module for input capture. It includes setting up GPIO pins, defining timer channels, initializing the timer, registering callbacks, and performing operations like starting, stopping, and reading frequency. ```c #include "uni_hal.h" // Timer callback function bool timer_callback(void *ctx_timer, void *ctx_fn) { // Called on timer period elapsed static uint32_t counter = 0; counter++; return false; // Return true if context switch required } // GPIO for input capture uni_hal_gpio_pin_context_t tim1_ch1_pin = { .gpio_bank = UNI_HAL_CORE_PERIPH_GPIO_A, .gpio_pin = UNI_HAL_GPIO_PIN_8, .gpio_type = UNI_HAL_GPIO_TYPE_ALTERNATE_PP, .alternate = UNI_HAL_GPIO_ALTERNATE_1 }; // Timer channel for input capture uni_hal_tim_channel_t tim1_ch1 = { .channel_number = UNI_HAL_TIM_CHANNEL_1, .type = UNI_HAL_TIM_TYPE_INPUTCAPTURE, .polarity = UNI_HAL_TIM_POLARITY_RISING, .gpio = &tim1_ch1_pin }; uni_hal_tim_channel_t *tim1_channels[] = {&tim1_ch1}; // Timer context uni_hal_tim_context_t tim1_ctx = { .config = { .instance = UNI_HAL_CORE_PERIPH_TIM_1, .callback = timer_callback, .prescaler = 199, // Divide clock by 200 .reload_value = 999, // Count to 1000 .channel = tim1_channels, .channel_count = 1 } }; void timer_example(void) { // Initialize timer if (!uni_hal_tim_init(&tim1_ctx)) { return; } // Register callback (optional, can also set in config) void *callback_context = nullptr; uni_hal_tim_register_callback(&tim1_ctx, timer_callback, callback_context); // Enable auto-reload preload uni_hal_tim_set_arrpreload(&tim1_ctx, true); // Start timer uni_hal_tim_start(&tim1_ctx); // Get timer period in microseconds uint32_t period_us = uni_hal_tim_get_period_us(&tim1_ctx); // Read input capture frequency (Hz) from channel 1 uint32_t freq_hz = uni_hal_tim_get_chan_freq(&tim1_ctx, UNI_HAL_TIM_CHANNEL_1); // Get time since last capture event (ms) uint32_t age_ms = uni_hal_tim_get_chan_age(&tim1_ctx, UNI_HAL_TIM_CHANNEL_1); // Clear timer counter uni_hal_tim_clear(&tim1_ctx); // Stop timer uni_hal_tim_stop(&tim1_ctx); } ``` -------------------------------- ### Global Definitions (CMake) Source: https://github.com/uni-libraries/uni.hal/blob/main/CMakeLists.txt Adds compile definitions to the build process. This example defines `UNI_HAL_TARGET_MCU_` based on the `UNI_HAL_TARGET_MCU` variable. ```cmake add_compile_definitions(UNI_HAL_TARGET_MCU_${UNI_HAL_TARGET_MCU}) ``` -------------------------------- ### ADS1015 ADC Driver Example (C) Source: https://context7.com/uni-libraries/uni.hal/llms.txt Demonstrates the usage of the Uni.HAL driver for the TI ADS1015 12-bit I2C ADC. It covers initialization, configuration, reading raw values, and voltage measurements. Requires a pre-initialized I2C context. ```c #include "uni_hal.h" // I2C context (must be initialized first) extern uni_hal_i2c_context_t i2c1_ctx; // ADS1015 context uni_hal_ads1015_context_t adc_ext_ctx = { .config = { .i2c = &i2c1_ctx, .timeout = 100, .address = 0x48, // Default I2C address .mode = UNI_HAL_ADS1015_MODE_SINGLE, .mux = UNI_HAL_ADS1015_MUX_IN0_GND, // Single-ended input 0 .rate = UNI_HAL_ADS1015_RATE_1600HZ, .pga = UNI_HAL_ADS1015_CONFIG_PGA_4096 // +/- 4.096V range } }; void ads1015_example(void) { // Initialize I2C first uni_hal_i2c_init(&i2c1_ctx); // Initialize ADS1015 if (!uni_hal_ads1015_init(&adc_ext_ctx)) { return; } // Configure ADC settings uni_hal_ads1015_configure(&adc_ext_ctx); // Wait for conversion to complete while (uni_hal_ads1015_is_ready(&adc_ext_ctx) == UNI_HAL_ADS1015_ANSWER_NOTREADY) { uni_hal_systick_delay(1); } // Read raw ADC value int16_t raw_value = uni_hal_ads1015_get_raw(&adc_ext_ctx); // Read voltage in millivolts int16_t voltage_mv = uni_hal_ads1015_get_voltage_mv(&adc_ext_ctx); // Change input channel adc_ext_ctx.config.mux = UNI_HAL_ADS1015_MUX_IN1_GND; uni_hal_ads1015_configure(&adc_ext_ctx); } ``` -------------------------------- ### MCP23017 GPIO Expander Driver Example (C) Source: https://context7.com/uni-libraries/uni.hal/llms.txt Illustrates the use of the Uni.HAL driver for the Microchip MCP23017 16-bit I2C GPIO expander. It shows initialization, configuring ports as input/output, reading input values, and setting output states. Requires a pre-initialized I2C context. ```c #include "uni_hal.h" // I2C context (must be initialized first) extern uni_hal_i2c_context_t i2c1_ctx; // MCP23017 context uni_hal_mcp23017_context_t gpio_exp_ctx = { .config = { .i2c = &i2c1_ctx, .timeout = 100, .address = 0x20 // Default address (A0=A1=A2=0) } }; void mcp23017_example(void) { // Initialize I2C first uni_hal_i2c_init(&i2c1_ctx); // Initialize MCP23017 if (!uni_hal_mcp23017_init(&gpio_exp_ctx)) { return; } // Configure Port A as outputs (0x00 = all outputs) uni_hal_mcp23017_set_iodir(&gpio_exp_ctx, UNI_HAL_MCP23017_PORT_A, 0x00); // Configure Port B as inputs (0xFF = all inputs) uni_hal_mcp23017_set_iodir(&gpio_exp_ctx, UNI_HAL_MCP23017_PORT_B, 0xFF); // Set Port A outputs uni_hal_mcp23017_set_gpio(&gpio_exp_ctx, UNI_HAL_MCP23017_PORT_A, 0x55); // Alternate pattern // Read Port B inputs uint8_t port_b_value; if (uni_hal_mcp23017_get_gpio(&gpio_exp_ctx, UNI_HAL_MCP23017_PORT_B, &port_b_value)) { // Process input value } // Toggle specific bits on Port A uni_hal_mcp23017_set_gpio(&gpio_exp_ctx, UNI_HAL_MCP23017_PORT_A, 0xAA); } ``` -------------------------------- ### Configure and Use I2C Master Communication Source: https://context7.com/uni-libraries/uni.hal/llms.txt This snippet illustrates the configuration and usage of the I2C module in master mode. It covers pin definition, I2C context setup with speed and instance, and performing memory write and read operations to an EEPROM. It also includes raw master transmit/receive functions and bus reset. ```c #include "uni_hal.h" // Define I2C pins uni_hal_gpio_pin_context_t i2c1_scl = { .gpio_bank = UNI_HAL_CORE_PERIPH_GPIO_B, .gpio_pin = UNI_HAL_GPIO_PIN_6, .gpio_type = UNI_HAL_GPIO_TYPE_ALTERNATE_OD, .alternate = UNI_HAL_GPIO_ALTERNATE_4, .gpio_pull = UNI_HAL_GPIO_PULL_UP, .gpio_speed = UNI_HAL_GPIO_SPEED_3 }; uni_hal_gpio_pin_context_t i2c1_sda = { .gpio_bank = UNI_HAL_CORE_PERIPH_GPIO_B, .gpio_pin = UNI_HAL_GPIO_PIN_7, .gpio_type = UNI_HAL_GPIO_TYPE_ALTERNATE_OD, .alternate = UNI_HAL_GPIO_ALTERNATE_4, .gpio_pull = UNI_HAL_GPIO_PULL_UP, .gpio_speed = UNI_HAL_GPIO_SPEED_3 }; // I2C context uni_hal_i2c_context_t i2c1_ctx = { .config = { .instance = UNI_HAL_CORE_PERIPH_I2C_1, .speed = UNI_HAL_I2C_SPEED_400KHZ, .pin_sck = &i2c1_scl, .pin_sda = &i2c1_sda, .irq_enable = false, .irq_priority = 5 } }; #define EEPROM_ADDRESS (0x50 << 1) // 7-bit address shifted left #define TIMEOUT_MS 100 void i2c_example(void) { // Initialize I2C if (!uni_hal_i2c_init(&i2c1_ctx)) { return; } // Check if device is ready if (!uni_hal_i2c_isready(&i2c1_ctx, EEPROM_ADDRESS, 3, TIMEOUT_MS)) { // Device not responding return; } // Write data to EEPROM memory address 0x0010 uint8_t write_data[] = {0xDE, 0xAD, 0xBE, 0xEF}; bool write_ok = uni_hal_i2c_mem_write( &i2c1_ctx, EEPROM_ADDRESS, 0x0010, // Memory address UNI_HAL_I2C_MEMADD_SIZE_16BIT, // 16-bit memory address write_data, sizeof(write_data), TIMEOUT_MS ); // Read data back from EEPROM uint8_t read_data[4]; bool read_ok = uni_hal_i2c_mem_read( &i2c1_ctx, EEPROM_ADDRESS, 0x0010, UNI_HAL_I2C_MEMADD_SIZE_16BIT, read_data, sizeof(read_data), TIMEOUT_MS ); // Raw master transmit/receive for non-memory devices uint8_t cmd = 0x01; uni_hal_i2c_master_transmit(&i2c1_ctx, EEPROM_ADDRESS, &cmd, 1, TIMEOUT_MS); uint8_t response[8]; uni_hal_i2c_master_receive(&i2c1_ctx, EEPROM_ADDRESS, response, 8, TIMEOUT_MS); // Reset I2C bus if needed uni_hal_i2c_reset(&i2c1_ctx); } ``` -------------------------------- ### Project Initialization and Options (CMake) Source: https://github.com/uni-libraries/uni.hal/blob/main/CMakeLists.txt Initializes the CMake project, sets the project name and languages, and defines configurable options for the build. Options like `UNI_HAL_TARGET_MCU` and `UNI_HAL_CAN_USE_FREERTOS` allow customization of the build process. ```cmake cmake_minimum_required(VERSION 3.29) project(uni.hal LANGUAGES C CXX ASM) option(UNI_HAL_TARGET_MCU "Target MCU" "") option(UNI_HAL_CAN_USE_FREERTOS "use FreeRTOS for CAN driver" ON) option(UNI_HAL_I2C_USE_FREERTOS "use FreeRTOS for I2C driver" ON) if(NOT DEFINED UNI_HAL_HSE_VALUE) set(UNI_HAL_HSE_VALUE 1 CACHE STRING "HSE clock value in Hz") endif() ``` -------------------------------- ### SPI Communication Initialization and Data Transfer (C) Source: https://context7.com/uni-libraries/uni.hal/llms.txt Demonstrates how to initialize and use the SPI module for master communication. It includes setting up GPIO pins, configuring SPI parameters like clock polarity, phase, and prescaler, and performing transmit, receive, and transmit-receive operations. It also shows how to change the prescaler at runtime. ```c #include "uni_hal.h" // Define SPI pins uni_hal_gpio_pin_context_t spi1_sck = { .gpio_bank = UNI_HAL_CORE_PERIPH_GPIO_A, .gpio_pin = UNI_HAL_GPIO_PIN_5, .gpio_type = UNI_HAL_GPIO_TYPE_ALTERNATE_PP, .alternate = UNI_HAL_GPIO_ALTERNATE_5, .gpio_speed = UNI_HAL_GPIO_SPEED_3 }; uni_hal_gpio_pin_context_t spi1_miso = { .gpio_bank = UNI_HAL_CORE_PERIPH_GPIO_A, .gpio_pin = UNI_HAL_GPIO_PIN_6, .gpio_type = UNI_HAL_GPIO_TYPE_ALTERNATE_PP, .alternate = UNI_HAL_GPIO_ALTERNATE_5 }; uni_hal_gpio_pin_context_t spi1_mosi = { .gpio_bank = UNI_HAL_CORE_PERIPH_GPIO_A, .gpio_pin = UNI_HAL_GPIO_PIN_7, .gpio_type = UNI_HAL_GPIO_TYPE_ALTERNATE_PP, .alternate = UNI_HAL_GPIO_ALTERNATE_5, .gpio_speed = UNI_HAL_GPIO_SPEED_3 }; uni_hal_gpio_pin_context_t spi1_cs = { .gpio_bank = UNI_HAL_CORE_PERIPH_GPIO_A, .gpio_pin = UNI_HAL_GPIO_PIN_4, .gpio_type = UNI_HAL_GPIO_TYPE_OUT_PP, .gpio_init = true // CS active low, start high }; // SPI context uni_hal_spi_context_t spi1_ctx = { .config = { .instance = UNI_HAL_CORE_PERIPH_SPI_1, .mode = UNI_HAL_SPI_MODE_MASTER, .clock_source = UNI_HAL_RCC_CLKSRC_SYSCLK, .pin_sck = &spi1_sck, .pin_miso = &spi1_miso, .pin_mosi = &spi1_mosi, .pin_nss = nullptr, // Software CS control .polarity = UNI_HAL_SPI_CPOL_0, .phase = UNI_HAL_SPI_CPHA_0, .prescaler = UNI_HAL_SPI_PRESCALER_16, .nss_hard = false, .crc_type = UNI_HAL_SPI_CRC_DISABLE, .dma_tx = nullptr, .dma_rx = nullptr } }; void spi_example(void) { // Initialize CS pin and SPI uni_hal_gpio_pin_init(&spi1_cs); if (!uni_hal_spi_init(&spi1_ctx)) { return; } // Get current bitrate uint32_t bitrate = uni_hal_spi_bitrate_get(&spi1_ctx); // Simple transmit (write to device) uint8_t tx_cmd[] = {0x9F}; // JEDEC ID command uni_hal_gpio_pin_set(&spi1_cs, false); // Assert CS uni_hal_spi_transmit(&spi1_ctx, tx_cmd, sizeof(tx_cmd)); // Receive response uint8_t rx_data[3]; uni_hal_spi_receive(&spi1_ctx, rx_data, sizeof(rx_data)); uni_hal_gpio_pin_set(&spi1_cs, true); // Deassert CS // Full-duplex transmit/receive uint8_t tx_buf[] = {0x03, 0x00, 0x00, 0x00}; // Read command + address uint8_t rx_buf[4]; uni_hal_gpio_pin_set(&spi1_cs, false); uni_hal_spi_transmitreceive(&spi1_ctx, tx_buf, rx_buf, sizeof(tx_buf)); uni_hal_gpio_pin_set(&spi1_cs, true); // Change prescaler at runtime uni_hal_spi_set_prescaler(&spi1_ctx, UNI_HAL_SPI_PRESCALER_8); } ``` -------------------------------- ### Initialize and Read ADC Values - C Source: https://context7.com/uni-libraries/uni.hal/llms.txt Demonstrates initializing the ADC module, checking its status, and reading raw or voltage values from specified channels. It also shows how to read values by rank for multi-channel scanning and includes a loop for continuous reading. ```c #include "uni_hal.h" // ADC context (platform-specific configuration required) uni_hal_adc_context_t adc1_ctx; // Configured via platform-specific headers void adc_example(void) { // Initialize ADC if (!uni_hal_adc_init(&adc1_ctx)) { return; } // Check initialization status if (!uni_hal_adc_is_inited(&adc1_ctx)) { return; } // Read raw ADC value from channel 0 uint16_t raw_value = uni_hal_adc_get_channel_raw(&adc1_ctx, 0); // Read ADC value in millivolts from channel 0 uint16_t voltage_mv = uni_hal_adc_get_channel_mv(&adc1_ctx, 0); // Read raw value by rank (for DMA-based multi-channel scanning) uint16_t rank0_raw = uni_hal_adc_get_rank_raw(&adc1_ctx, 0); uint16_t rank1_raw = uni_hal_adc_get_rank_raw(&adc1_ctx, 1); // Continuous reading loop while (1) { // Read multiple channels uint16_t ch0_mv = uni_hal_adc_get_channel_mv(&adc1_ctx, 0); uint16_t ch1_mv = uni_hal_adc_get_channel_mv(&adc1_ctx, 1); uint16_t ch2_mv = uni_hal_adc_get_channel_mv(&adc1_ctx, 2); // Process readings... uni_hal_systick_delay(100); // Delay 100ms } } ``` -------------------------------- ### Perform Formatted Output with STDIO Module Source: https://context7.com/uni-libraries/uni.hal/llms.txt Demonstrates using the STDIO module for printf-style formatted output without heap allocation. It covers initialization with an I/O context, printing to the configured output, and formatting strings into a buffer. ```c #include "uni_hal.h" // External IO context (from UART setup) extern uni_hal_io_context_t uart1_io_ctx; void stdio_example(void) { // Initialize STDIO with UART IO context uni_hal_io_stdio_init(&uart1_io_ctx); // Printf to configured output uni_hal_io_stdio_printf("System initialized\r\n"); uni_hal_io_stdio_printf("Temperature: %d.%d C\r\n", 25, 5); uni_hal_io_stdio_printf("Voltage: %u mV\r\n", (unsigned int)3300); // Formatted string to buffer char buffer[64]; uni_hal_io_stdio_snprintf(buffer, sizeof(buffer), "Value: 0x%08X", 0xDEADBEEF); // Variable arguments printing va_list args; // uni_hal_io_stdio_vprintf(format, args); } ``` -------------------------------- ### Uni.HAL CMake Integration for Applications and Libraries (CMake) Source: https://context7.com/uni-libraries/uni.hal/llms.txt Shows how to integrate Uni.HAL into an embedded project using CMake. This includes setting target MCU, including the library, adding executables, and embedding binary files. It also demonstrates creating custom libraries that link against Uni.HAL. ```cmake # CMakeLists.txt for your application cmake_minimum_required(VERSION 3.29) project(my_firmware LANGUAGES C CXX ASM) # Set target MCU before including Uni.HAL set(UNI_HAL_TARGET_MCU "STM32H743") set(UNI_HAL_HSE_VALUE 25000000) # 25MHz external crystal # Include Uni.HAL add_subdirectory(path/to/uni.hal) # Include helper functions include(path/to/uni.hal/uni.hal.cmake) # Create executable with Uni.HAL defaults uni_hal_add_executable(my_firmware) # Add source files target_sources(my_firmware PRIVATE src/main.c src/config.c ) # Embed binary file as C array uni_hal_add_file(my_firmware "assets/logo.bin" "logo_data" "logo_bin") # Create library that links against Uni.HAL uni_hal_add_library(my_drivers) target_sources(my_drivers PRIVATE drivers/sensor.c drivers/display.c ) ``` -------------------------------- ### Initialize and Use SysTick Timer for Timing and Delays Source: https://context7.com/uni-libraries/uni.hal/llms.txt Demonstrates initializing the SysTick timer, retrieving tick counts and frequency, and performing delays. It also shows a common timeout pattern for non-blocking operations. ```c #include "uni_hal.h" void systick_example(void) { // Initialize SysTick if (!uni_hal_systick_init()) { return; } // Get current tick count (ms since boot) uint32_t current_ms = uni_hal_systick_get_ms(); // Get raw tick value uint32_t tick_count = uni_hal_systick_get_tick(); // Get tick frequency uint32_t tick_freq = uni_hal_systick_get_freq(); // Simple delay uni_hal_systick_delay(500); // Wait 500ms // Timeout pattern uint32_t start_time = uni_hal_systick_get_ms(); uint32_t timeout = 5000; // 5 second timeout while (1) { // Check for timeout if ((uni_hal_systick_get_ms() - start_time) >= timeout) { // Timeout expired break; } // Check condition... uni_hal_systick_delay(10); } } ``` -------------------------------- ### Configure Peripheral Clocks and Resets with RCC Module Source: https://context7.com/uni-libraries/uni.hal/llms.txt Shows how to initialize the RCC module, enable/disable peripheral clocks, check clock status, retrieve clock frequencies, set clock sources, and perform peripheral resets. ```c #include "uni_hal.h" void rcc_example(void) { // Initialize RCC (typically called first in system init) if (!uni_hal_rcc_init()) { return; } // Enable clock to a peripheral uni_hal_rcc_clk_set(UNI_HAL_CORE_PERIPH_GPIO_A, true); uni_hal_rcc_clk_set(UNI_HAL_CORE_PERIPH_UART_1, true); uni_hal_rcc_clk_set(UNI_HAL_CORE_PERIPH_SPI_1, true); // Check if peripheral clock is enabled bool gpio_clk_enabled = uni_hal_rcc_clk_get(UNI_HAL_CORE_PERIPH_GPIO_A); // Get peripheral clock frequency uint32_t uart_freq = uni_hal_rcc_clk_get_freq(UNI_HAL_CORE_PERIPH_UART_1); uint32_t spi_freq = uni_hal_rcc_clk_get_freq(UNI_HAL_CORE_PERIPH_SPI_1); // Set clock source for peripheral uni_hal_rcc_clksrc_set(UNI_HAL_CORE_PERIPH_UART_1, UNI_HAL_RCC_CLKSRC_SYSCLK); // Get current clock source uni_hal_rcc_clksrc_e uart_clksrc = uni_hal_rcc_clksrc_get(UNI_HAL_CORE_PERIPH_UART_1); // Reset a peripheral uni_hal_rcc_reset(UNI_HAL_RCC_RESET_UART1); // Read reset status register (check reset cause) uint8_t reset_status = uni_hal_rcc_get_status_reg(); // Disable clock to save power uni_hal_rcc_clk_set(UNI_HAL_CORE_PERIPH_SPI_1, false); } ``` -------------------------------- ### Manage System Power and Battery Charging Source: https://context7.com/uni-libraries/uni.hal/llms.txt Illustrates initializing the power management subsystem, checking and setting battery charging status, and initiating a system reset. Note that the reset function does not return. ```c #include "uni_hal.h" void pwr_example(void) { // Initialize power subsystem if (!uni_hal_pwr_init()) { return; } // Check battery charging status bool is_charging = uni_hal_pwr_is_battery_charging(); // Enable/disable battery charging uni_hal_pwr_set_battery_charging(true); // System reset // Note: This function does not return uni_hal_pwr_reset(); } ``` -------------------------------- ### Configure and Use UART Communication Source: https://context7.com/uni-libraries/uni.hal/llms.txt This snippet demonstrates how to configure and use the UART module for serial communication. It includes setting up IO buffers, GPIO pins, UART context with baud rate and clock source, and performing transmit, receive, and line reception operations. It also shows how to check available data and change the baud rate at runtime. ```c #include "uni_hal.h" // Define IO buffers for UART (RX: 256 bytes, TX: 128 bytes) UNI_HAL_IO_DEFINITION(uart1_io, 256, 128); // Define GPIO pins for UART uni_hal_gpio_pin_context_t uart1_tx_pin = { .gpio_bank = UNI_HAL_CORE_PERIPH_GPIO_A, .gpio_pin = UNI_HAL_GPIO_PIN_9, .gpio_type = UNI_HAL_GPIO_TYPE_ALTERNATE_PP, .alternate = UNI_HAL_GPIO_ALTERNATE_7, // AF7 for USART1 .gpio_speed = UNI_HAL_GPIO_SPEED_2 }; uni_hal_gpio_pin_context_t uart1_rx_pin = { .gpio_bank = UNI_HAL_CORE_PERIPH_GPIO_A, .gpio_pin = UNI_HAL_GPIO_PIN_10, .gpio_type = UNI_HAL_GPIO_TYPE_ALTERNATE_PP, .alternate = UNI_HAL_GPIO_ALTERNATE_7, .gpio_pull = UNI_HAL_GPIO_PULL_UP }; // UART context uni_hal_usart_context_t uart1_ctx = { .instance = UNI_HAL_CORE_PERIPH_UART_1, .baudrate = 115200, .clksrc = UNI_HAL_RCC_CLKSRC_SYSCLK, .pin_rx = &uart1_rx_pin, .pin_tx = &uart1_tx_pin, .io = &uart1_io_ctx, .isr_priority = 5 }; void uart_example(void) { // Initialize IO buffers uni_hal_io_init(&uart1_io_ctx); // Initialize UART if (!uni_hal_usart_init(&uart1_ctx)) { return; } // Enable reception uni_hal_usart_receive_enable(&uart1_ctx, true); uni_hal_usart_transmit_enable(&uart1_ctx, true); // Send data const char *msg = "Hello, World!\r\n"; uni_hal_usart_transmit_data(&uart1_ctx, (uint8_t *)msg, strlen(msg)); // Receive data with timeout uint8_t rx_buffer[64]; size_t received = uni_hal_usart_receive_data(&uart1_ctx, rx_buffer, 64, 1000); // Receive a complete line char line_buffer[128]; size_t line_len = uni_hal_io_receive_line(uart1_ctx.io, (uint8_t *)line_buffer, 128, 5000); // Check available bytes size_t available = uni_hal_usart_receive_available(&uart1_ctx); // Change baud rate at runtime uni_hal_usart_baudrate_set(&uart1_ctx, 9600); } ``` -------------------------------- ### DFP Library Configuration (CMake) Source: https://github.com/uni-libraries/uni.hal/blob/main/CMakeLists.txt Configures the Device Peripheral Provider (DFP) library based on the target MCU. It adds the appropriate subdirectory and sets DFP library and suffix variables. ```cmake if(UNI_HAL_TARGET_MCU STREQUAL "STM32H743") add_subdirectory(3rdparty/st_stm32h7) add_subdirectory(3rdparty/st_usb_device) set(UNI_HAL_DFP_LIBRARY st_stm32h7) set(UNI_HAL_DFP_SUFFIX "*_cm.c" "*_cm7.c" "*_stm32.c" "*_stm32h7.c") elseif(UNI_HAL_TARGET_MCU STREQUAL "STM32L496") add_subdirectory(3rdparty/st_stm32l4) set(UNI_HAL_DFP_LIBRARY st_stm32l4) set(UNI_HAL_DFP_SUFFIX "*_cm.c" "*_cm4.c" "*_stm32.c" "*_stm32l4.c") elseif(UNI_HAL_TARGET_MCU STREQUAL "PC") set(UNI_HAL_DFP_SUFFIX "*_pc.c") else() message(FATAL_ERROR "Unknown target MCU ${UNI_HAL_TARGET_MCU}. Please set `UNI_HAL_TARGET_MCU` variable") endif() ``` -------------------------------- ### Add Segger SystemView Library (CMake) Source: https://github.com/uni-libraries/uni.hal/blob/main/3rdparty/segger_systemview/CMakeLists.txt Adds the Segger SystemView library to the build system. It specifies the source files, public include directories, and links against the segger_rtt library. Language standard is set based on the compiler. ```cmake add_library(segger_systemview) target_sources(segger_systemview PRIVATE src/SEGGER_SYSVIEW.c ) target_include_directories(segger_systemview PUBLIC include) target_include_directories(segger_systemview PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/segger_systemview_config/") target_link_libraries(segger_systemview PUBLIC segger_rtt) #language standard) if(MSVC) target_compile_features(segger_systemview PRIVATE c_std_17) else() target_compile_features(segger_systemview PRIVATE c_std_23) endif() ``` -------------------------------- ### Add Segger SystemView FreeRTOS Integration (CMake) Source: https://github.com/uni-libraries/uni.hal/blob/main/3rdparty/segger_systemview/CMakeLists.txt Defines an INTERFACE library for Segger SystemView's FreeRTOS integration. It includes the FreeRTOS-specific source file and include directory, enabling SystemView to work with FreeRTOS. ```cmake add_library(segger_systemview_freertos INTERFACE) target_sources(segger_systemview_freertos INTERFACE src_freertos/SEGGER_SYSVIEW_FreeRTOS.c) target_include_directories(segger_systemview_freertos INTERFACE include_freertos) ``` -------------------------------- ### Main Source and Test Inclusion (CMake) Source: https://github.com/uni-libraries/uni.hal/blob/main/CMakeLists.txt Adds the main source directory (`src`) and optionally the test source directory (`src_tests`) to the build. The test directory is only included if the target MCU is 'PC'. ```cmake add_subdirectory(src) if(UNI_HAL_TARGET_MCU STREQUAL "PC") add_subdirectory(src_tests) endif() ``` -------------------------------- ### Generate Segger SystemView Configuration Header (CMake) Source: https://github.com/uni-libraries/uni.hal/blob/main/3rdparty/segger_systemview/CMakeLists.txt Generates the SEGGER_SYSVIEW_Conf.h configuration file. This file defines essential parameters like RTT buffer size and CPU cache line size, which are crucial for SystemView's operation. ```cmake file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/segger_systemview_config/SEGGER_SYSVIEW_Conf.h" "#ifndef SEGGER_SYSVIEW_CONF_H \n" "#define SEGGER_SYSVIEW_CONF_H \n" " \n" "#define SEGGER_SYSVIEW_RTT_BUFFER_SIZE (8192U) \n" "#define SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE (32U ) \n" "#endif \n" " \n" ) ``` -------------------------------- ### Target Include Directories for freertos_fat (CMake) Source: https://github.com/uni-libraries/uni.hal/blob/main/3rdparty/freertos_fat/CMakeLists.txt Defines the public include directories for the freertos_fat library. This allows other targets to include headers from the 'include' directory and a generated configuration directory. ```cmake target_include_directories(freertos_fat PUBLIC "include") target_include_directories(freertos_fat PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/freertos_fat_config/") ``` -------------------------------- ### Subdirectory Inclusion (CMake) Source: https://github.com/uni-libraries/uni.hal/blob/main/CMakeLists.txt Includes various third-party libraries and source directories into the build. This includes ARM CMSIS Core, Segger RTT, FreeRTOS, and DFP libraries, with conditional inclusion based on the target MCU. ```cmake add_subdirectory(3rdparty/arm_cmsis_core) if(NOT UNI_HAL_TARGET_MCU STREQUAL "PC") add_subdirectory(3rdparty/segger_rtt) #TODO: make configurable #add_subdirectory(3rdparty/segger_systemview) endif() add_subdirectory(3rdparty/freertos_kernel) ``` -------------------------------- ### Add Static Library: st_stm32h7 Source: https://github.com/uni-libraries/uni.hal/blob/main/3rdparty/st_stm32h7/CMakeLists.txt This command adds a static library named 'st_stm32h7' to the build system. Static libraries are linked directly into the executable during the build process. ```cmake add_library(st_stm32h7 STATIC) ``` -------------------------------- ### Set Include Directories for st_stm32h7 Source: https://github.com/uni-libraries/uni.hal/blob/main/3rdparty/st_stm32h7/CMakeLists.txt Configures the public include directories for the 'st_stm32h7' library. This allows the library's header files to be found during compilation. ```cmake target_include_directories(st_stm32h7 PUBLIC "include_device") target_include_directories(st_stm32h7 PUBLIC "include_hal") target_include_directories(st_stm32h7 PUBLIC "${CMAKE_CURRENT_BINARY_DIR}") ``` -------------------------------- ### Generate FreeRTOSFATConfig.h (CMake) Source: https://github.com/uni-libraries/uni.hal/blob/main/3rdparty/freertos_fat/CMakeLists.txt Writes a custom FreeRTOSFATConfig.h header file to the build directory. This file defines configuration macros for the FreeRTOS FAT library, such as byte order and thread-local storage index. ```cmake file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/freertos_fat_config/FreeRTOSFATConfig.h" "#ifndef FREERTOS_FAT_CONFIG_H \n" "#define FREERTOS_FAT_CONFIG_H \n" " \n" "#define ffconfigBYTE_ORDER (pdFREERTOS_LITTLE_ENDIAN) \n" "#define ffconfigCWD_THREAD_LOCAL_INDEX (0) \n" "#define ffconfigDEV_SUPPORT (0) \n" "#define ffconfigWRITE_BOTH_FATS (1) \n" " \n" "#endif \n" ) ``` -------------------------------- ### Specify Segger RTT Source Files Source: https://github.com/uni-libraries/uni.hal/blob/main/3rdparty/segger_rtt/CMakeLists.txt Defines the source files that constitute the segger_rtt library. These files are compiled to form the static library. ```cmake target_sources(segger_rtt PRIVATE "src/SEGGER_RTT.c" "src/SEGGER_RTT_ASM_ARMv7M.S" "src/SEGGER_RTT_printf.c" ) ``` -------------------------------- ### Add Segger RTT Static Library Source: https://github.com/uni-libraries/uni.hal/blob/main/3rdparty/segger_rtt/CMakeLists.txt Adds the Segger RTT library as a static library to the build system. This is a fundamental step for integrating the RTT functionality. ```cmake add_library(segger_rtt STATIC) ``` -------------------------------- ### Add Interface Sources to Static Library: st_stm32l4 Source: https://github.com/uni-libraries/uni.hal/blob/main/3rdparty/st_stm32l4/CMakeLists.txt This command adds interface sources to the 'st_stm32l4' static library. 'INTERFACE' means these sources are directly compiled with targets that link to this library, often used for assembly files like startup code. ```cmake target_sources(st_stm32l4 INTERFACE "src_device/startup_stm32l496xx.s" ) ``` -------------------------------- ### Set Include Directories for arm_cmsis_core (CMake) Source: https://github.com/uni-libraries/uni.hal/blob/main/3rdparty/arm_cmsis_core/CMakeLists.txt Configures the include directories for the arm_cmsis_core library. This ensures that header files within the 'include' directory are accessible when compiling code that depends on this library. ```cmake target_include_directories(arm_cmsis_core INTERFACE "include") ``` -------------------------------- ### Link Libraries (CMake) Source: https://github.com/uni-libraries/uni.hal/blob/main/src/CMakeLists.txt Links necessary libraries to the uni.hal target. This includes FreeRTOS, uni.common, nanoprintf, and conditionally DFP libraries and segger_rtt based on target MCU. ```cmake target_link_libraries(uni.hal PUBLIC freertos_kernel) target_link_libraries(uni.hal PUBLIC uni.common) target_link_libraries(uni.hal PUBLIC nanoprintf) if(DEFINED UNI_HAL_DFP_LIBRARY) target_link_libraries(uni.hal PUBLIC ${UNI_HAL_DFP_LIBRARY}) endif() if(NOT UNI_HAL_TARGET_MCU STREQUAL "PC") target_link_libraries(uni.hal PUBLIC segger_rtt) endif() ``` -------------------------------- ### Add Sources to Static Library: st_stm32l4 Source: https://github.com/uni-libraries/uni.hal/blob/main/3rdparty/st_stm32l4/CMakeLists.txt This command adds source files to the 'st_stm32l4' static library. 'PRIVATE' indicates that these sources are internal to the library and not exposed to users. It includes HAL, LL, device, and extra source files. ```cmake target_sources(st_stm32l4 PRIVATE "src_hal/stm32l4xx_hal.c" "src_hal/stm32l4xx_hal_can.c" "src_hal/stm32l4xx_hal_cortex.c" "src_hal/stm32l4xx_hal_dma.c" "src_hal/stm32l4xx_hal_gpio.c" "src_hal/stm32l4xx_hal_i2c.c" "src_hal/stm32l4xx_hal_i2c_ex.c" "src_hal/stm32l4xx_hal_rcc.c" "src_hal/stm32l4xx_hal_rcc_ex.c" src_hal/stm32l4xx_ll_adc.c src_hal/stm32l4xx_ll_dma.c src_hal/stm32l4xx_ll_gpio.c src_hal/stm32l4xx_ll_lpuart.c src_hal/stm32l4xx_ll_pwr.c src_hal/stm32l4xx_ll_rcc.c src_hal/stm32l4xx_ll_spi.c src_hal/stm32l4xx_ll_tim.c src_hal/stm32l4xx_ll_usart.c src_hal/stm32l4xx_ll_utils.c "src_device/system_stm32l4xx.c" "src_extra/systick.c" ) ```