Simple Network Interface with STM32 Using Ethernet and Mongoose Network Library

Simple Network Interface with STM32 Using Ethernet and Mongoose Network Library

Mongoose is a C/C++ network library. For protocols including TCP, UDP, HTTP, WebSocket, MQTT, and others, it offers event-driven, non-blocking APIs. It is intended to link and bring devices online.

On the market since 2004, it has been used by a vast number of open source and commercial products; it even runs on the International Space Station! Mongoose makes embedded network programming fast, robust, and easy.

Features include:

  • Cross-platform:1. works on Linux/UNIX, MacOS, Windows, Android2. works on STM32, NXP, ESP32, NRF52, TI, Microchip, and other3. write code once, and it'll work everywhere4. ideal for the unification of the network infrastructure code across company
  • Built-in protocols: plain TCP/UDP, SNTP, HTTP, MQTT, Websocket, and other
  • Asynchronous DNS resolver
  • Built-in TCP/IP stack with drivers for bare metal or RTOS systems
  • Can run on top of an existing TCP/IP stack with BSD API, e.g. lwIP, Zephyr, Azure, etc
  • Does not depend on any other software to implement networking
  • Built-in TLS 1.3 ECC stack. Aslo can use external TLS libraries - mbedTLS, OpenSSL, or others).

Integrate Mongoose in CubeIDE with Ethernet

  • Use Cube IDE provided by ST: Install IDE
  • Start Cube IDE. Choose File / New / STM32 project
  • In the "part number" field, type the microcontroller name, for example, "H743ZI". That should narrow down the MCU/MPU list selection in the bottom right corner to a single row. Click on the row at the bottom right, then click on the Next button
  • In the project name field, type any name, click Finish. Answer "yes" if a pop-up dialogue appears
  • A configuration window appears. Click on Clock configuration tab. Find a field with a system clock value. Type the maximum value, hit enter, answer "yes" to auto-configuration question, and wait until configured
  • Switch to the Pinout tab, Connectivity, then enable the UART controller (For Debug) and pins, and choose "Asynchronous mode."
  • Click on Connectivity / ETH, Choose Mode / RMII, verify that the configured pins are like those in your ethernet hardware.
  • Click Ctrl+S to save the configuration. This generates the code and open projecy in stm32cube ide
  • Redirect Printf to UART for debug.
  • Open Mongoose in your browser, click on mongoose.h. Click on the "Raw" button and copy the file contents to the clipboard. In CubeIDE, right-click on Core/Inc, choose New/File in the menu, type mongoose.h, paste the file content, and save.
  • Repeat for mongoose.c. On Github, copy mongoose.c contents to the clipboard. In the CubeIDE, right click on Core/Src, choose New/File in the menu, type mongoose.c, paste the file content and save.
  • Right-click on Core/Inc, choose New/File in the menu, type mongoose_custom.h, and paste the following contents:

#pragma once

// See https://mongoose.ws/documentation/#build-options
#define MG_ARCH MG_ARCH_NEWLIB

#define MG_ENABLE_TCPIP 1          // Enables built-in TCP/IP stack
#define MG_ENABLE_CUSTOM_MILLIS 1  // We must implement mg_millis()
#define MG_ENABLE_DRIVER_STM32H 1  // On STM32Fxx series, use MG_ENABLE_DRIVER_STM32F        

  • Implement Layer 1 (driver), 2 (TCP/IP stack), and 3 (library) in our code. Open main.c. Add #include `mongoose.h` at the top:

/* USER CODE BEGIN Includes */
#include "mongoose.h"
/* USER CODE END Includes */        

  • Before main(), define function mg_millis() that returns an uptime in milliseconds. It will be used by the Mongoose Library for timekeeping.

/* USER CODE BEGIN 0 */
uint64_t mg_millis(void) {
  return HAL_GetTick();
}
/* USER CODE END 0 */        

  • Navigate to main() function and change the code around while loop this way:

    /* USER CODE BEGIN WHILE */
    struct mg_mgr mgr;
    mg_mgr_init(&mgr);
    mg_log_set(MG_LL_DEBUG);

    // On STM32Fxx, use _stm32f suffix instead of _stm32h
    struct mg_tcpip_driver_stm32h_data driver_data = {.mdc_cr = 4};
    struct mg_tcpip_if mif = {.mac = {2, 3, 4, 5, 6, 7},
                              // Uncomment below for static configuration:
                              // .ip = mg_htonl(MG_U32(192, 168, 0, 223)),
                              // .mask = mg_htonl(MG_U32(255, 255, 255, 0)),
                              // .gw = mg_htonl(MG_U32(192, 168, 0, 1)),
                              .driver = &mg_tcpip_driver_stm32h,
                              .driver_data = &driver_data};
    NVIC_EnableIRQ(ETH_IRQn);
    mg_tcpip_init(&mgr, &mif);

    while (1) {
      mg_mgr_poll(&mgr, 0);
  /* USER CODE END WHILE */        

  • Connect your board to the Ethernet. Flash firmware. In the serial log, you should see something like this:

bb8    3 mongoose.c:14914:mg_tcpip_driv Link is 100M full-duplex
bbd    1 mongoose.c:4676:onstatechange  Link up
bc2    3 mongoose.c:4776:tx_dhcp_discov DHCP discover sent. Our MAC: 02:03:04:05:06:07
c0e    3 mongoose.c:4755:tx_dhcp_reques DHCP req sent
c13    2 mongoose.c:4882:rx_dhcp_client Lease: 86400 sec (86403)
c19    2 mongoose.c:4671:onstatechange  READY, IP: 192.168.2.76
c1e    2 mongoose.c:4672:onstatechange         GW: 192.168.2.1
c24    2 mongoose.c:4673:onstatechange        MAC: 02:03:04:05:06:07        

If you don't, and see DHCP requests message 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
...        

The most common cause for this is you have your Ethernet pins wrong. Click on the .ioc file, go to the Ethernet configuration, and double-check the Ethernet pins and also check in your hardware.

  • Open terminal/command prompt, and run a ping command against the IP address of your board:

$ ping 192.168.2.76
PING 192.168.2.76 (192.168.2.76): 56 data bytes
64 bytes from 192.168.2.76: icmp_seq=0 ttl=64 time=9.515 ms
64 bytes from 192.168.2.76: icmp_seq=1 ttl=64 time=1.012 ms        

Now, we have a functional network stack running on our board. Layers 1,2,3 are implemented.

Implementing layer 4 - a simple web server

Let's add a very simple web server that responds "ok" to any HTTP request.


  • After the mg_tcpip_init() call, add this line that creates HTTP listener with fn event handler function:

  mg_http_listen(&mgr, "https://0.0.0.0:80", fn, NULL);        

  • Before the mg_millis() function, add the fn event handler function:

static void fn(struct mg_connection *c, int ev, void *ev_data) {
  if (ev == MG_EV_HTTP_MSG) {
    struct mg_http_message *hm = ev_data;  // Parsed HTTP request
    mg_http_reply(c, 200, "", "ok\r\n");
  }
}        

That's it! Flash the firmware. Open your browser, type board's IP address and see the "ok" message.


Commercial use

Please visit Evaluation and Commercial licensing for commercial use of mongoose library.

Mongoose Library under the GPLv2 license is ideal for non-commercial projects, open source projects, private use or evaluation purposes.

Commercial projects can also run under the GPLv2 license by fully releasing the end product’s source code under the GPLv2 license.





要查看或添加评论,请登录

社区洞察

其他会员也浏览了