Overview

Purpose

Basic STDIO is a minimal stdout redirection layer for STM32. It provides quick printf output through UART, ITM (SWO), or a custom input/output interface with minimal setup and without a heavyweight logging framework. It excludes advanced logging features (no log levels, filtering mechanisms, buffering queues, or timestamp insertion) to keep the footprint small and the integration effort low, making the component easy to integrate, remove, or replace. Designed for early board startup, firmware prototyping, and quick diagnostic tracing, it also serves as a simple base that can be extended later.

Key Features

The main features of Basic STDIO are:

  • Single initialization entry point.

  • Multiple input/output interfaces: UART (HAL based), ITM (CMSIS-Core only), or a custom interface from the provided template.

  • Minimal footprint by excluding log levels, filtering, buffering, and timestamps.

  • Deterministic blocking path (each character is sent immediately).

  • Abstracts toolchain libc hook differences (_write, __write, fputc variations).

Limitations

  • Not threadsafe: Concurrent writes from multiple contexts may be interleaved unpredictably.

  • No stdin support: Only stdout redirection is provided; input via stdin is not supported.

  • UART HAL-only: The UART interface supports the STM32 HAL only.

Architecture

The following diagram illustrates the software components of the Basic STDIO module. It shows the interactions between the user application, the core layer, the input/output interfaces (ITM, UART, custom), the supporting system libraries (CMSIS-Core, HAL), and the hardware components.

@startuml

top to bottom direction

skinparam linetype ortho

<style>

componentDiagram {

   arrow {

      FontSize 8

   }

}

</style>



title Basic STDIO Architecture Overview



package "Application" {

  component APP as "User Application\n(firmware code)"

}





package "Basic STDIO" {

  component CORE as "Core Layer\n(hook adaptation + forwarding)"

  package "io_interface" {

    component B_ITM as "ITM interface" #DAE8FC

    component B_UART as "UART interface" #DAE8FC

    component B_CUSTOM as "Custom interface\n(template)" #DAE8FC

  }

}



package "System" {

  component CMSIS as "CMSIS-Core"

  component HAL as "HAL UART" #DAE8FC

  component HW as "STM32_HW"

  component PROBE as "Debug Probe\n(ST-Link, etc.)"

  component TERMINAL as "UART Terminal /\nTrace Viewer"

}



APP --> CORE : trace request

CORE --> B_ITM : trace bytes

CORE --> B_UART : trace bytes

CORE --> B_CUSTOM : trace bytes



B_ITM --> CMSIS : ITM registers

B_UART --> HAL : HAL API calls

HAL --> HW : register access

B_ITM --> PROBE : SWO line

PROBE --> TERMINAL : trace data

B_UART --> TERMINAL : UART TX

B_CUSTOM --> HW : user-defined link



CMSIS --> HW : core register access



@enduml

Component Structure

Core ( basic_stdio_core.c / basic_stdio_core.h): Handles stdout redirection by selecting the appropriate libc hook and then forwarding each character or small buffer to a neutral forwarding layer that is independent of the physical input/output interface.

Interfaces : Software layer that connects Basic STDIO to the hardware component. Three interfaces are available:

  • UART and ITM: Ready-to-use implementations that only require enabling and initialization, with no code changes.

  • Template: Empty interface that allows users to develop their own interface. Copy the file into the user space; it contains empty functions with the prototypes required by the core.

Modules and Files

The following diagram shows the Basic STDIO module and its associated files:

@startuml Basic_STDIO_modules

skinparam componentStyle rectangle

skinparam defaultFontName Courier

skinparam ArrowColor #2A4B8D

skinparam ArrowFontSize 10

skinparam RectangleBackgroundColor #FFFFFF

skinparam RectangleBorderColor #2A4B8D

skinparam Shadowing false

skinparam linetype ortho



title Basic STDIO Modules Overview



package "Application" {

  component APP as "User Application\n(firmware code)"

}



package "Basic STDIO" {

  component CORE_H as "basic_stdio_core.h"

  component CORE_C as "basic_stdio_core.c"

  component ITF_H as "basic_stdio_itf_io.h"

  component B_ITM as "basic_stdio_itfio_itm.c" #DAE8FC

  component B_UART as "basic_stdio_itfio_uart.c" #DAE8FC

  component B_TEMPLATE as "basic_stdio_itfio_template.c" #DAE8FC

}



APP --> CORE_C

CORE_C ..> CORE_H : include

CORE_C ..> ITF_H : include

CORE_C --> B_ITM : interface

CORE_C --> B_UART : interface

CORE_C --> B_TEMPLATE : interface

B_ITM ..> ITF_H : include

B_UART ..> ITF_H : include

B_TEMPLATE ..> ITF_H : include



@enduml