Mongoose Integration Guide: STM32 with built-in Ethernet
This guide shows how to Mongoose to an existing STM32 firmware project. The example uses CubeMX, which is the most common STM32 workflow. Mongoose can run on top of existing TCP/IP stack like lwIP or Zephyr - however this guide explains how to integrate Mongoose in stanalone mode using Mongoose's built-in TCP/IP stack.
By the end of this guide, your STM32 board will:
- use Mongoose's built-in TCP/IP stack
- get an IP address over Ethernet using DHCP
Configure peripherals
Open CubeMX and make sure to configure the following peripherals:
- In Pinout & Configuration → Security, enable RNG
- In Pinout & Configuration → Connectivity, enable USART in Asynchronous mode and configure the TX and RX pins. See board pinouts for correct pins
- In Pinout & Configuration → Connectivity, enable ETH in RMII mode and configure the Ethernet pins. Again, see board pinouts for correct pins
NOTE: Do not enable Ethernet IRQ handler in CubeMX, as it enables Cube's Ethernet driver. Instead, we're going to use Mongoose's Ethernet driver
- In "Pinouts & Configuration" → "Software Packs" → "Manage Software Packs", click on "Cesanta", and click on "Refresh". Install the latest "I-CUBE-Mongoose" pack
- In "Pinouts & Configuration" → "Software Packs" → "Select Components", enable Mongoose
- In "Pinouts & Configuration" → "Middleware and Software Packs", click on "I-CUBE-Mongoose", enable "Mongoose Networking Core"
- Click "Generate Code"
That should add the "Middlewares/Third_Party/Cesanta_Mongoose/" directory
with 3 files: mongoose.c, mongoose.h, and mongoose_config.h - exactly
what we need.
Update linker script
Open the .ld linker script file in the project root, and verify the configured
memory region for the .data section. If that memory region is not accessible by
the Ethernet DMA controller, add the following line after the .data rules - you
may need to change RAM_D2 to the DMA-accessible region:
/* Mongoose driver puts DMA buffers into the .eth_ram ELF section - it should be accessible by the ETH DMA */
.eth_ram : { *(.eth_ram .eth_ram*) } > RAM_D2 AT > FLASH
Modify main.c
In Core/Src/main.c, add Mongoose include - make sure to add the following snippets inside the BEGIN/END markers, to prevent CubeMX from deleting them on code regeneration:
/* USER CODE BEGIN Includes */
#include "mongoose.h"
/* USER CODE END Includes */
In Core/Src/main.c, add _write override for console logs redirection:
/* USER CODE BEGIN 0 */
int _write(int fd, unsigned char *buf, int len) {
HAL_UART_Transmit(&huart3, buf, len, HAL_MAX_DELAY);
return len;
}
/* USER CODE END 0 */
In Core/Src/main.c, init event manager and run event loop:
/* USER CODE BEGIN WHILE */
struct mg_mgr mgr;
mg_mgr_init(&mgr);
while (1)
{
mg_mgr_poll(&mgr, 1);
/* USER CODE END WHILE */
Build and run
Start serial console, rebuild and reflash the device. In the serial logs, you should see something like this:
0 2 mongoose.c:26153:mg_phy_init PHY ID: 0x07 0xc131 (LAN87x)
6 2 mongoose.c:5834:mg_mgr_init Driver: stm32h, MAC: 2a:37:94:03:d5:74
d 3 mongoose.c:5841:mg_mgr_init MG_IO_SIZE: 512, TLS: builtin
13 3 mongoose.c:5758:mg_listen 1 0 http://0.0.0.0:80
19 1 mongoose.c:6260:onstatechange Link down
7d6 3 mongoose.c:28424:mg_tcpip_driv Link is 100M full-duplex
7db 3 mongoose.c:6404:tx_dhcp_discov DHCP discover sent. Our MAC: 2a:37:94:03:d5:74
831 3 mongoose.c:6382:tx_dhcp_reques DHCP req sent
836 2 mongoose.c:6559:rx_dhcp_client Lease: 3600 sec (3602)
83c 2 mongoose.c:6249:onstatechange READY, IP: 192.168.2.31
842 2 mongoose.c:6250:onstatechange GW: 192.168.2.1
847 2 mongoose.c:6253:onstatechange MAC: 2a:37:94:03:d5:74
Now you can ping the device using the IP address printed in the logs, and integrate a Web UI device dashboard.
Check the Troubleshooting section if it goes not as expected
Troubleshooting
No IP address is printed
Check Ethernet cable, PHY pins, RMII configuration, DHCP server, and board pinout.
No free descriptors
If you see the "No free descriptors:" message, the likely cause is the
missing/incorrect .eth_ram snippet in the linker script, or the wrong Ethernet
pins - double check the list against your device documentation.
No DHCP server
If you see logs messages like this:
130b0 3 mongoose.c:4776:tx_dhcp_discov DHCP discover sent. Our MAC: 02:03:04:05:06:07
13498 3 mongoose.c:4776:tx_dhcp_discov DHCP discover sent. Our MAC: 02:03:04:05:06:07
One possible reason for that is the transmission side of the driver is not working. Run Wireshark on that Ethernet network, filter for UDP ports 67 and 68. If you do not see the messages from your device, then the transmission does not work - check the pins and the linker script.
The other reason could be that there is no DHCP server is running in the network your device is connected to. That usually happens when a device is connected back-to-back to the workstation.
The easiest option is to use a USB to Ethernet dongle and enable Internet sharing on the Ethernet interface.
FAQ
Do I need LwIP for this?
No. This guide uses Mongoose's built-in TCP/IP stack instead of LwIP.
Should I enable the Ethernet IRQ handler in CubeMX?
No. Do not enable CubeMX's Ethernet IRQ handler, because that enables Cube's Ethernet driver. This guide uses Mongoose's Ethernet driver.
Why is .eth_ram needed on STM32H7?
STM32H7 Ethernet DMA needs buffers in DMA-accessible memory. The .eth_ram
section ensures Ethernet buffers are placed correctly.
How do I know the network is working?
Check the serial log for READY, IP: ..., then open that IP address in a
browser.