Add TCP/IP stack to STM32

This guide shows how to add a TCP/IP stack to an existing STM32 firmware project. The example uses STM32 Cube and CubeMX, which is the most common STM32 workflow.

The target board is Nucleo-H723ZG with built-in Ethernet, but the same integration approach applies to other STM32 devices and networking hardware.

Mongoose includes a built-in TCP/IP stack and networking library. In this guide, we integrate Mongoose into an STM32 firmware project and run a minimal HTTP server.

Copy Mongoose files

Mongoose is distributed as two core source files. The easiest way to integrate it is to copy them directly into your project.

Create a mongoose/ directory in the project root:

project/
  mongoose/
    mongoose.c
    mongoose.h
    mongoose_config.h
  ...  rest of the project files ...

Download mongoose.c and mongoose.h from the Mongoose repository and create mongoose_config.h:

#define MG_ARCH MG_ARCH_CUBE
#define MG_ENABLE_TCPIP 1

MG_ARCH_CUBE enables the STM32 Cube environment.
MG_ENABLE_TCPIP enables the built-in TCP/IP stack.

Set Network Driver

Embedded networking typically follows a layered architecture:

driver → TCP/IP stack → TLS → protocols (HTTP, WebSocket, MQTT) → application

See TCP/IP stack for embedded devices for a detailed explanation.

In this section, we configure the lowest layer - the network driver, which connects your device to the network.

STM32 and other microcontrollers support multiple networking options:

  • built-in Ethernet MAC
  • external Ethernet controllers (e.g., W5500)
  • WiFi modules (e.g., CYW43439)
  • cellular modems

Mongoose provides built-in drivers for common embedded networking hardware, making it easy to bring up connectivity and build web-based device interfaces.

In particular, Mongoose includes drivers for STM32 microcontrollers with a built-in Ethernet MAC. The Nucleo-H723ZG uses its internal Ethernet MAC, so enable the STM32 Ethernet driver in mongoose_config.h:

#define MG_ENABLE_DRIVER_STM32H 1
#define MG_ETH_RAM __attribute__((section(".eth_ram")))

For STM32F devices, use MG_ENABLE_DRIVER_STM32F.

The MG_ETH_RAM definition places Ethernet DMA buffers into a memory region accessible by the MAC DMA engine. This part matters - if buffers land in the wrong RAM, Ethernet simply will not work.

Then configure the hardware in CubeMX:

  • enable the Ethernet peripheral
  • configure Ethernet pins
  • enable a UART for debug output

Update the linker script

Ethernet DMA buffers must be placed into a valid RAM region. Update the linker script and define the .eth_ram section.

Example:

MEMORY {
  RAM_D2(rwx): ORIGIN = 0x30000000, LENGTH = 32K
}

.eth_ram : { *(.eth_ram .eth_ram*) } > RAM_D2 AT > ROM

The exact RAM region depends on the STM32 model.

Create a minimal HTTP server

Open Core/Src/main.c. Include Mongoose header at the top:

#include "mongoose.h"

Before the main() function, add the following two functions:

// Redirect `printf()` to UART so debug output is visible:
int _write(int fd, unsigned char *buf, int len) {
  HAL_UART_Transmit(&huart3, buf, len, HAL_MAX_DELAY);
  return len;
}

// HTTP server event handler
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
  if (ev == MG_EV_HTTP_MSG) {
    struct mg_http_message *hm = (struct mg_http_message *) ev_data;

    if (mg_match(hm->uri, mg_str("/api/hello"), NULL)) {
      mg_http_reply(c, 200, "", "{%m:%d}\n", MG_ESC("status"), 1);
    } else {
      mg_http_reply(c, 200, "", "hello world\n");
    }
  }
}

Modify your main() function main loop - before the loop, add Mongoose instance initialisation, and inside the loop, add mg_mgr_poll() call:

struct mg_mgr mgr;
mg_mgr_init(&mgr);
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);

while (1) {
  mg_mgr_poll(&mgr, 0);

The mg_mgr_poll() processes packets, parses protocols, and calls your event handler when something happens.

Build and run

Add the mongoose/ directory to the project include paths and build the firmware.

Open a serial console. Mongoose prints the assigned IP address during startup. Open that address in a browser and the board should reply with:

hello world

At this point your STM32 firmware has a working TCP/IP stack and HTTP server powered by Mongoose.