C SDK
STM32

STM32 Guide

The Plexus C SDK supports STM32F4, STM32F7, and STM32H7 series microcontrollers with LwIP for networking. This guide covers static allocation (no malloc), FreeRTOS integration, and HTTP configuration.

Prerequisites

Step 1: Add the SDK

Copy src/ and hal/stm32/ into your STM32 project:

your-project/
├── Core/
│   ├── Inc/
│   └── Src/
│       └── main.c
├── Plexus/
│   ├── src/
│   │   ├── plexus.h
│   │   ├── plexus.c
│   │   ├── plexus_config.h
│   │   ├── plexus_internal.h
│   │   └── plexus_json.c
│   └── hal/
│       └── stm32/
│           └── plexus_hal_stm32.c

Add Plexus/src to your include paths and add all .c files to your build.

LwIP Configuration

The STM32 HAL requires these settings in lwipopts.h:

#define LWIP_SOCKET      1
#define LWIP_DNS         1
#define LWIP_SO_RCVTIMEO 1
#define LWIP_SO_SNDTIMEO 1

Step 2: Static Allocation (No Malloc)

On STM32, you typically want to avoid heap allocation. Use PLEXUS_CLIENT_STATIC_BUF to declare a statically-allocated client:

#include "plexus.h"
 
#define API_KEY   "plx_xxxxx"
#define SOURCE_ID "stm32-sensor-001"
 
// Static allocation — no malloc needed
PLEXUS_CLIENT_STATIC_BUF(plexus_buf);
 
int main(void) {
    HAL_Init();
    SystemClock_Config();
 
    // Initialize Plexus client in static memory
    plexus_client_t* px = plexus_init_static(
        &plexus_buf, sizeof(plexus_buf), API_KEY, SOURCE_ID);
 
    if (!px) {
        printf("ERROR: Failed to init Plexus\r\n");
        return -1;
    }
 
    // Use HTTP endpoint (see HTTPS section below)
    plexus_set_endpoint(px, "http://app.plexus.company/api/ingest");
    plexus_set_flush_interval(px, 5000);
 
    printf("Plexus SDK v%s, client: %u bytes\r\n",
           plexus_version(), (unsigned)plexus_client_size());
 
    // Telemetry loop
    for (;;) {
        plexus_send(px, "temperature", (double)read_temperature());
        plexus_send(px, "pressure", (double)read_pressure());
 
        plexus_err_t err = plexus_tick(px);
        if (err != PLEXUS_OK) {
            printf("Error: %s\r\n", plexus_strerror(err));
        }
 
        HAL_Delay(1000);
    }
}

plexus_free() is safe to call on static clients -- it marks the client as uninitialized but does not call free().

Step 3: FreeRTOS Integration

When FreeRTOS is available, run telemetry in a dedicated task:

PLEXUS_CLIENT_STATIC_BUF(plexus_buf);
 
void telemetry_task(void* arg) {
    plexus_client_t* px = plexus_init_static(
        &plexus_buf, sizeof(plexus_buf), API_KEY, SOURCE_ID);
 
    plexus_set_endpoint(px, "http://app.plexus.company/api/ingest");
    plexus_set_flush_interval(px, 5000);
 
    for (;;) {
        plexus_send(px, "temperature", (double)read_temperature());
        plexus_send(px, "pressure", (double)read_pressure());
 
        plexus_err_t err = plexus_tick(px);
        if (err == PLEXUS_ERR_AUTH) {
            printf("FATAL: Auth failed — check API key\r\n");
            break;
        }
 
        osDelay(1000);  // yields CPU to other tasks
    }
 
    vTaskDelete(NULL);
}
 
int main(void) {
    HAL_Init();
    SystemClock_Config();
 
    osThreadDef(telemetry, telemetry_task, osPriorityNormal, 0, 2048);
    osThreadCreate(osThread(telemetry), NULL);
    osKernelStart();
 
    for (;;) {}
}

When FreeRTOS is present, the HAL uses osDelay() instead of HAL_Delay() during retry backoff, so other tasks continue running.

HTTP vs HTTPS

The STM32 HAL uses plain HTTP by default. HTTPS requires mbedTLS integration.

For development and trusted networks, HTTP works. Set the endpoint explicitly to acknowledge this:

plexus_set_endpoint(px, "http://app.plexus.company/api/ingest");

For production with HTTPS, integrate mbedTLS with LwIP's altcp_tls layer:

  1. Enable mbedTLS in CubeMX (Middleware > mbedTLS)
  2. Add these settings to lwipopts.h:
    #define LWIP_ALTCP          1
    #define LWIP_ALTCP_TLS      1
    #define LWIP_ALTCP_TLS_MBEDTLS 1
  3. Load the server's root CA certificate
  4. Modify the HAL to use altcp instead of raw sockets

Alternatively, use a TLS-terminating proxy on your network edge.

Security note: Without TLS, the API key is transmitted in cleartext. Do not use plain HTTP on untrusted networks.

Peripheral Configuration

The STM32 HAL references these peripheral handles by default:

PeripheralDefault HandleOverride Flag
Debug UARThuart2-DPLEXUS_STM32_DEBUG_UART=huart3
RTChrtc-DPLEXUS_STM32_RTC=hrtc1

Override them in your build flags if your hardware uses different peripherals:

-DPLEXUS_STM32_DEBUG_UART=huart1
-DPLEXUS_STM32_RTC=hrtc1

These handles must be declared as extern in your code (the HAL references them). For example, in your main.c:

UART_HandleTypeDef huart1;  // used by PLEXUS_STM32_DEBUG_UART
RTC_HandleTypeDef  hrtc;    // used by PLEXUS_STM32_RTC

The RTC is used for wall-clock timestamps. If the RTC is not configured, plexus_hal_get_time_ms() returns 0 and the server assigns timestamps on ingest.

Supported Series

The STM32 HAL auto-detects your target via preprocessor defines:

DefineSeries
STM32F4STM32F4xx (e.g., F446RE)
STM32F7STM32F7xx (e.g., F767ZI)
STM32H7STM32H7xx (e.g., H743ZI)
STM32_HALGeneric STM32 HAL (auto-defined by CubeMX)

Make sure your build defines one of these (CubeMX projects do this automatically).

Next Steps