Skip to content

matek-dev/STM32_Comms

Repository files navigation

STM32 HAL Communication Templates (C++)

These templates provide clean, reusable C++ interfaces for STM32 HAL-based communication peripherals - including UART, I²C, SPI, and CAN.
They serve as a foundation for developing firmware that needs structured communication layers without relying on autogenerated or overly complex code.


Overview

Each communication class wraps STM32’s HAL drivers with simple, consistent APIs that handle initialization, blocking or DMA data transfers, and common helper functions (e.g. register access, buffer management).
The goal is to make embedded communication code easy to read, reuse, and extend - while still keeping full control over low-level HAL handles and timing.


Implemented Interfaces

Interface Description Key Features
UART Universal Asynchronous Receiver/Transmitter DMA circular RX buffer, blocking TX, string and binary send helpers
I²C Inter-Integrated Circuit 8/16-bit register access, memory read/write, device scanning
SPI Serial Peripheral Interface Manual CS control, blocking TX/RX, register read/write helpers
CAN Controller Area Network (optional) Standard ID transmit/receive, configurable filters

File Structure

/Core
  /Inc
    CommStatus.hpp
    UartComm.hpp
    I2cComm.hpp
    SpiComm.hpp
    CanComm.hpp
  /Src
    UartComm.cpp
    I2cComm.cpp
    SpiComm.cpp
    CanComm.cpp
  main.cpp

Each class is self-contained. You only need to include the header for the peripheral you’re using.


Example Usage

#include "main.h"
#include "UartComm.hpp"
#include "I2cComm.hpp"
#include "SpiComm.hpp"
#include "CanComm.hpp"

extern UART_HandleTypeDef huart2;
extern I2C_HandleTypeDef  hi2c1;
extern SPI_HandleTypeDef  hspi1;

static uint8_t rxBuf[256];

int main() {
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART2_UART_Init();
  MX_I2C1_Init();
  MX_SPI1_Init();

  UartComm uart(&huart2, rxBuf, sizeof(rxBuf));
  I2cComm  i2c(&hi2c1);
  SpiComm  spi(&hspi1, GPIOA, GPIO_PIN_4);

  uart.begin();
  uart.writeStr("System initialized.\r\n");

  // Example: I²C scan
  auto addr = i2c.scanFirst();
  if (addr != 0xFFFF) {
      char msg[32];
      snprintf(msg, sizeof(msg), "I2C device found at 0x%02X\r\n", addr);
      uart.write(reinterpret_cast<uint8_t*>(msg), strlen(msg));
  }

  // Example: SPI read register
  uint8_t whoami = 0;
  if (spi.readReg(0x00, whoami) == CommStatus::OK) {
      char msg[32];
      snprintf(msg, sizeof(msg), "WHOAMI=0x%02X\r\n", whoami);
      uart.write(reinterpret_cast<uint8_t*>(msg), strlen(msg));
  }

  while (1) {
      uint8_t in[32];
      auto n = uart.read(in, sizeof(in));
      if (n) uart.write(in, n); // echo
  }
}

CubeMX Configuration

Each class expects its HAL handles to be generated by STM32CubeMX (or CubeIDE).
Enable the following:

UART

  • Mode: Asynchronous
  • DMA: RX enabled (Circular)
  • NVIC: Enabled
  • Baud rate, parity, word length as needed

I²C

  • Mode: Standard or Fast
  • Internal or external pull-ups on SDA/SCL
  • No special interrupts required

SPI

  • Mode: Full-Duplex Master
  • Add manual GPIO for chip select (set high in init)

CAN

  • Configure bit timing
  • Activate filter bank 0 (or custom)
  • Set standard ID mask to open filter if needed

Design Philosophy

  • Simplicity first: HAL handles are passed into constructors, not hidden.
  • Low overhead: No dynamic memory or STL dependencies.
  • Deterministic: No heap, no interrupts unless configured by HAL.
  • Extensible: Add DMA TX or IRQ callbacks easily without changing the API.
  • Portable: Works across STM32 series with minimal CubeMX reconfiguration.

Why C++ with HAL

While STM32 HAL is written in C, C++ enables clearer abstraction layers and safer APIs:

  • Constructors ensure peripheral handles are initialized before use.
  • Encapsulation prevents global-variable sprawl typical in HAL projects.
  • Function overloading and enums reduce parameter errors.

This hybrid approach keeps firmware readable and maintainable while preserving low-level control.


Future Additions

  • Non-blocking TX queues with DMA
  • Interrupt-driven receive callbacks
  • LL (Low-Level) versions using direct register access
  • Common base class for all comm interfaces

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages