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
- STM32CubeIDE or your preferred STM32 toolchain
- LwIP middleware enabled in CubeMX
- Ethernet or WiFi module configured
- A Plexus API key from app.plexus.company (opens in a new tab)
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.cAdd 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 1Step 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:
- Enable mbedTLS in CubeMX (Middleware > mbedTLS)
- Add these settings to
lwipopts.h:#define LWIP_ALTCP 1 #define LWIP_ALTCP_TLS 1 #define LWIP_ALTCP_TLS_MBEDTLS 1 - Load the server's root CA certificate
- 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:
| Peripheral | Default Handle | Override Flag |
|---|---|---|
| Debug UART | huart2 | -DPLEXUS_STM32_DEBUG_UART=huart3 |
| RTC | hrtc | -DPLEXUS_STM32_RTC=hrtc1 |
Override them in your build flags if your hardware uses different peripherals:
-DPLEXUS_STM32_DEBUG_UART=huart1
-DPLEXUS_STM32_RTC=hrtc1These 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_RTCThe 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:
| Define | Series |
|---|---|
STM32F4 | STM32F4xx (e.g., F446RE) |
STM32F7 | STM32F7xx (e.g., F767ZI) |
STM32H7 | STM32H7xx (e.g., H743ZI) |
STM32_HAL | Generic STM32 HAL (auto-defined by CubeMX) |
Make sure your build defines one of these (CubeMX projects do this automatically).
Next Steps
- Memory Configuration -- Reduce RAM usage to ~1.5 KB
- API Reference -- Full function and macro reference
- ESP32 Guide -- ESP-IDF walkthrough with WiFi and NTP