Library 52- Ethernet peripheral on STM32F4xx

One of the greatest features on STM32F4xx for me was to get ethernet to work properly as server and client. I got it working pretty quickly and I was investigating how to make a library to be very useful and easy to use.

Ethernet library is built on LwIP TCP/IP stack version 1.4.1.

Library is pretty hard to “install” for first time, so I decided to provide you source files (on my Github) for Keil uVision and Coocox.

Examples for Keil uVision and Coocox are finally available on my Github.



  • Supports RMII or MII interface with PHY and STM32F4 ETH interface
  • Built on LwIP TCP/IP stack
  • Support for TCP client and TCP server
    • 4 TCP client connections at a time
  • Built-in support for opening files from SD card or any other source
  • Support to disable server access to IP address
  • DNS support for receive IP from domain
  • DHCP support for receive IP in your network
    • Support for custom device name on router
  • Support for callbacks with full control on your work
    • Callbacks for client (when connected, disconnected, data available, create headers)
    • Callbacks for server (new client connected to server, disconnected)
    • Callbacks for DNS (DNS has started, DNS has found IP)
    • Callbacks for DHCP (DHCP has IP for us, DHCP error)
    • Callbacks for link status (Link down, link up)
    • Callbacks for POST requests
  • Support for dynamic MAC address
  • Support for STATIC/DYNAMIC IP address
  • Support for monitoring how many bytes we sent/received over client/server mode
  • Enable/Disable server mode
  • User selectable PORT for server
  • Support for SSI tags and CGI handlers
    • SSI: You can display variables from MCU (RTC clock for example, LEDs status, etc)
    • CGI: You can control MCU from web (control leds)
  • Support for POST request
  • Support for TCP communication between 2 STM devices without router using crossover cable


    • STM32F4xx
    • STM32F4xx RCC
    • STM32F4xx GPIO
    • STM32F4xx ETH (included in library)
    • STM32F4xx SYSCFG
  • TM
    • DELAY
    • GPIO
    • defines.h
    • attributes.h
  • LwIP TCP/IP stack (Included in library)


Ethernet works with ETH peripheral. For this purpose, you can’t use any STM32F4xx device (F401, F405, F411, F415 don’t have ethernet). As of version 1.1, MII or RMII connection is supported. In table below is RMII pinout with 2 possible pinspacks. Look a little bit below to see table for MII connection.

ETHERNET PHY STM32F4xx Description
MDIO PA2 PA2 Management Data I/O pin
MDC PC1 PC1 Management Interface clock input
REF_CLK PA1 PA1 50 MHz reference clock from PHY to STM32F4xx
CRS PA7 PA7 Carrier Receive/Sense Data Valid
RX0 PC4 PC4 Receive data line 0
RX1 PC5 PC5 Receive data line 1
TX_EN PB11 PG11 Enable transmitted
TX0 PB12 PG13 Transmit data line 0
TX1 PB13 PG14 Transmit data line 1
PA8 PA8 Possible bug, check below

Default pinout is the left one (PINSPACK1) but if you want for some reason right one, use define below:

Example works without problems on STM32F4-Discovery with pinspack1. To get it working on STM32F429-Discovery, you must “damage” your board. You must remove gyro and so on. Not nice to try it there. I have 2 boards F429, so I take apart one to get it working.

I believe, this is a bug, but if you can ensure me that is not, please report that to me:

  • PA8 HAVE to be declared as MCO alternate function, even if not used for ethernet, or ETHERNET will not work.
  • So keep in mind that if you don’t use this pin for ethernet source clock you shouldn’t connect anything to this pin.
    • Some devices (like KSZ8081RNA can acceps 25MHz input clock and with internal PLL convert to 50MHz which is needed for RMII)

MII table

ETHERNET PHY STM32F4xx Description
MDIO PA2 Management Data I/O
MDC PC1 Management Interface clock input
REF_CLK PA1 25 MHz reference clock from PHY to STM32F4xx
CRS PH2 Carrier Receive/Sense Data Valid
COL PH3 Collision
RXD0 PC4 Receive data 0
RXD1 PC5 Receive data 1
RXD2 PH6 Receive data 2
RXD3 PH7 Receive data 3
RX_ERR PI10 Receive error
RX_DV PA7 RX Data valid
RX_CLK PC3 RX clock
TX_EN PG11 Transmit enable
TXD0 PG13 Transmit data 0
TXD1 PG14 Transmit data 1
TXD2 PC2 Transmit data 2
TXD3 PB8 Transmit data 3
PA8 Possible bug, check above

After you design your board for MII mode, you have to enable it with my lib. Open defines.h file and add define:


Library was built in using DP83848 Ethernet PHY. I have 2 DP modules for testing on both discovery boards at the same time and works well on both.

You can get DP83848 module here.

PHY is connected to STM using RMII mode. Basically, every PHY should work with this configuration because they have standard registers locations inside. Of course, every PHY has something different but they should work from start.

According to the datasheet, I’ve made 3 supported PHY-s. To select your PHY, open defines.h file and make a define below:

I also have some functions for ethernet PHYs, which can be used for set custom pinouts, which will overwrite default pinouts and function for setting custom PHY settings. In example below, LEDs configuration in DP83848 will be changed.


In common I will set things which HAVE to be used, no matter which configuration you use. One of them is Initialize function, which is used to initialize LwIP TCP/IP stack and prepare Ethernet PHY in working state.

Function will return something from result enumeration. It’s structure is below:

To be able to get ethernet properly in working state, you also have several functions which HAVE TO be called.

First function is Ethernet update which is used to update LwIP stack, and second is Time update which is used to update “local time” for LwIP stack. They are below:

Both function must be called periodically. Time update must be called in specific time. According to periodic time you call it, you have parameter for millis. If you call this function every 10ms, then pass into function parameter “10” which will increase local time for 10ms.

Update function should be called as fast as possible. It’s not necessary to call it at specific time intervals.

You might also use other common functions, which are described below:


Each device in your network has own MAC address and IP address, default gateway and netmask address.

My library allows you to set “dynamic” or “static” MAC address and IP.

Dynamic MAC means, that you apply MAC address when you initialize library (useful in case you have more than just one device in one network and you need different MAC addresses, you can use unique ID inside STM32F4). In case of STATIC MAC, you can set it using defines which are in my lib. In case you want to overwrite it, you can do this (defines.h file):

So, the same thing you can apply for other 3 settings too. All settings are below:


DHCP is a great protocol, which can be used to assign device IP from your router. This basically means, that you (STM device) sends packet to router with “I want IP address” and then router sends you IP address and question “Is this IP OK?”. If it is OK, STM returns “Ok” and IP is assigned.

By default, DHCP assignment is disabled in my library, so IP which is set on defines (chapter above) or passed on initialization function is used. If you want to activate DHCP features, open defines.h file and add line below:

One feature, you can use with DHCP, is that when you request a IP with DHCP, then you are displayed in control panel of your router. You can see device name and it’s IP and MAC address.

My library allows you, that you choose device name, which will be displayed in your router DHCP client list:

DHCP client list on TP-Link router

DHCP client list on TP-Link router

DHCP is also a part of my callback functions.

If DHCP is enabled, when it will start with IP assignment, callback will be called.

DHCP makes 4 tries to get IP. If it fails, or not, a IP is set callback is called, which can be defined by user.


Another great feature in my lib is DNS. Domain Name Server allows you to get IP address from given doman name. For example, if you want to get IP address for “” domain, you call DNS function and packet will be sent to DNS servers, with IP response (

To start DNS request, call my function:

Function uses 2 callbacks in case DNS status. One callback is called when DNS found IP address, second is to told user that we have error:

  • IP address is not found
  • Invalid data passed to DNS function


Client mode is one of 2 main features of ethernet. With client mode, you can request and receive data from another server, for example, you can make “data logger” which will make GET request method to another server where you want to collect and store your data.

So when you are ready (IP is set) you can start with connection to another server at desired IP and port. Library allows you to make 4 connections at the same time. So you can call Connect function 4 times before any connection is closed.

To connect, call function below:

Function will start a TCP connection to specific IP address and PORT. Remember, this function must return TM_ETHERNET_Result_Ok which means that function succedded. In case it returns anything else, connect won’t work.

Another thing here are client callbacks. Because connecting to some server may take a while, but STM is too fast for waiting callbacks are used here. I’ve made several callbacks. Here are just defines, how to use it you will see on examples.

Every client callback, has first parameter TM_TCPCLIENT_t* connection. This is special structure, which is used for client to easily work with multiple connections at a time. It’s structure is below:

You might want to know some time how many data you sent/receive as a client over ethernet and  how many connections you’ve made as a client. I’ve made some macro functions, which can be used in your project:


Server mode is a little bit difficult for explain it’s configuration, but I will try to be clear.

First, when you initialize library, server is disabled. Because, you don’t want that someone just come to your device if you don’t want. if you want to use server mode, then you have to enable it and tell on which PORT you will use your server.

Enable function is a little bit weird I would say. So only first time parameter will work. It means, that if you call this function multiple times, PORT will be used the one, which was used on first function call. Future calls don’t have affect of this parameter.

Ok, our server is enabled, and is accessible on our local IP. You can get local IP address using TM_ETHERNET_GetLocalIP function. But, it has no effect, if we don’t show anything to user.

In file fsdata.c are 3 files, which are displayed to user in case you don’t make your own. They are just for demonstration and I suggest you to remove them, or at least short data to minimum to free memory in flash.

The useful feature become when you are able to open custom files (from SD card or USB flash). This library allows you this also. It is designed to allow 10 opened files at a time by default. If you want to change this, open defines.h file and change:

In the examples below, you will see how to implement server with FatFs library from Chan. Which file should be opened will LwIP tell to you, you just have to make sure that you open file (if existing) that is in parameter.

All 3 functions have special file pointer parameter. It’s structure is below:

Like client, server has also some other callbacks to work with connected clients. One of them is to know, when client is connected or disconnected. It allows you to block access to client if you detect bad remote IP address. Callbacks below:

Other statistical functions which correspond to server are below:

Our server works, web site is displayed to user.

Two most asked questions now probably are:

  • How to display useful data to user?
  • How to control device over ethernet?


  • To display useful data to user (temperature, whatever…) you SSI tags
  • To control device (leds, PWM, whatever…), use CGI handlers


Let’s say, that you have website and when user access to your server, you want to display current temperature to him. You will have to assign new SSI tag and pass it into SetSSITags function, which will be described below.

Then, in your HTML code, you need to add SSI tag also, which will then be replaced by LwIP to useful data.

For example, you define SSI tag in your code, named “temperature“.

Then, in your HTML code, where you want to display it, you have to do this: <p><!–#temperature–></p>

Important is part in bold text. Other is just normal HTML which you wanna use.


  • SSI tags only works if your file name ends with .shtml, .shtm or .ssi
  • SSI tags can’t be unlimited long
  • SSI response text can’t be unlimited long

Now, you have tags defines and place into code. Next step is to set some data when this tag is found by LwIP in code. When SSI tag should be placed into code, my function for SSI will be called. This is fixed name function and is only one function for all SSI tags in your code.

In examples below, you will see how to use tags in practise.


CGI handlers are a simple way to control your STM device over ethernet. They are a way on how to handle GET method with url link this: /my_url.cgi?ledon=1&ledoff=3&ledtoggle=4

You can use more than just one CGI handler. CGI handler is called when you access to a URL which ends with .cgi. In our case we have “my_url.cgi” and let’s assign function which will be called on CGI call.

It will look something like that:

More about that will be clear when I show you an example


My library can also handle POST requests but I don’t suggest to use this. It is not 100% stable for now, and I will not describe how to use it yet.

Functions and enumerations

Here are described all functions and enumerations. It’s long part so they are hidden by default.

Example 1

  • STM configured as server mode on port 80.
  • For debug purpose is used PC6 (USART6) @ 115200baud where you will be able to see initialization settings.
  • How it works:
    • Data for user are stored in fsdata.c file,
    • There are SSI tags which are replaced with some settings
    • There is one CGI handlers which handles LEDs actions
    • DHCP is disabled, IP is used

Example 2

  • STM configured as server mode on port 80.
  • For debug purpose is used PC6 (USART6) @ 115200baud where you will be able to see initialization settings.
  • How it works:
    • Data for user are stored on SD card (how you will implement low layer is on you, but you can use my FatFs library as well)
    • There are SSI tags which are replaced with some settings
    • There is one CGI handlers which handles LEDs actions
    • DHCP is disabled, IP is used

Response on PC6 pin

Response on PC6 pin