1 year, 2 months ago.

MAC address on STM32F7 can't be changed?

Hello there,

I'm currently working on a project where we use a RMII/WiFi Bridge to connect a STM32F7 MCU to a wireless module for network connectivity. The exact MCU is a STM32F769NI Discovery Board.

The Situation

Since the WiFi modules we use come shipped with 4 individual MAC addresses for our usage (whereas Mbed generates them from the STMs UID, as can be seen in
mbed-os\features\netsocket\emac-drivers\TARGET_STM_EMAC\stm32xx_emac.cpp:mbed_mac_address())

we decided to implement the WEAK mbed_otp_mac_address() to overwrite this default MAC with one provided by the wireless module. Now I have found all of these various posts ( #1, #2, #3, #4 ) spead across the Internet, that's why we looked into mbed_otp_mac_address() in the first place.

Our solution

Here is our code:

Overwrite mbeds default MAC address

#define UBLOX_SERIAL_TX PC_12
#define UBLOX_SERIAL_RX PD_2
#define UBLOX_BAUDRATE 115200

UARTSerial uart_ublox(UBLOX_SERIAL_TX, UBLOX_SERIAL_RX, UBLOX_BAUDRATE);
ATCmdParser* at_parser_ublox = new ATCmdParser(&uart_ublox, "\r", 256, 4000, false);

/**
 * @brief Return the MAC address in mbed.
 *
 * The address is read from the Flash register in the STM.
 *
 * @param mac  Char array to write the MAC address into
 * @return 1 if successful.
 */
uint8_t mbed_otp_mac_address(char *mac) {
    /* Reads the MAC address from an attached ublox NINA module. */
    /* This is the attached wireless module */
    at_parser_ublox->send("AT+UMLA=2");
    if (at_parser_ublox->recv("+UMLA:%2X%2X%2X%2X%2X%2X\r\nOK",
        &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5])) {
            printf("MAC set\n");

            return 1;
    } else {
    /* Return some fake MAC address.
     * The default for STM32F769NI is:  00:80:e1:1b:00:24
     */
        mac[0] = 0x00;
        mac[1] = 0x80;
        mac[2] = 0xe1;
        mac[3] = 0x1b;
        mac[4] = 0x00;
        mac[5] = 0x28;

        printf("Set default MAC\n");
        return 1;
    }
};

The Diagnosis

I have confirmed that the MAC address from the wireless module is read correctly and also returned properly.
I have also made sure that the function is called upon creating an Ethernet Interface.

Furthermore I have verified that the MAC address entered above is the exact same that EthernetInterface::get_mac_address() returns to me.
Additionally, as seen in the reference manual, Rev. 4, page 1849, the MAC address of the STM32F7 MCU is saved in a register (ETH_MACA0xx) and compared to the MAC address of incoming packets.

This bit of code shows me that the MAC address is indeed written into the register (After an Ethernet Interface has been initialized and EthernetInterface::connect() has been called!!):

Read the MAC address from STM32H7 flash memory

void print_mac_reg() {
#if defined (TARGET_DISCO_F769NI)
        uint32_t ETH_MAC_ADDR_REG_OFFSET = 0x40UL;   /* RM0410, Rev.4, p. 1849 */
#else
#error "Cannot determine position of the MAC address register!"
#endif

    uint32_t *ETH_MAC_ADDR_REG_POS = (uint32_t *)(ETH_MAC_BASE + ETH_MAC_ADDR_REG_OFFSET);
    printf("[DEBUG ]: At 0x%08X : %08X\n", (ETH_MAC_ADDR_REG_POS + 0), *(ETH_MAC_ADDR_REG_POS + 0));
    printf("[DEBUG ]: At 0x%08X : %08X\n", (ETH_MAC_ADDR_REG_POS + 1), *(ETH_MAC_ADDR_REG_POS + 1));
}

All of this leads me to assume that changing the MAC address on the STM32F7 has worked.

The Problem

However, the STM32F7 now doesn't recognize packets adressed to it anymore (it seems to me).

If I leave the STM with it's default MAC address (00:80:e1:1b:00:24), it answers ICMP (ping) requests.
As soon as I change the MAC address (to 00:80:e1:1b:00:28 for example, or even something entirely different), it seemingly doesn't receive packets anymore. Calling ping now results in silence, the STM doesn't even answer ARP requests.

Calling nping (after changing the MAC address) with the --dest-mac option set to either the default value or the overridden value set by myself results in silence as well. If I make the STM send UDP packets to my host PC I can see in Wireshark that:

  • The STM sends an ARP request
  • My host PC answers this ARP request correctly
  • No UDP packet is ever sent
  • The STM sends more ARP packets indefinitely, which
  • My host PC keeps answering, indefinitely...

Note, however, that Wireshark reports the correct Ethernet Frame address (the one returned to me by mbed, too).

This leads me to assume that the underlying hardware or low-level drivers somehow haven't been notified of the change in the MAC address.

Does anybody have an idea what might be wrong with this? Is somebody else having this problem or can someone else reproduce it? So far I could reproduce this issue across multiple F7-DISCO Boards.

More information

  • IDE: VSCode, Version 1.37.1
  • OS: Windows 10 Enterprise, Version 1803, OS-build: 17134.950
  • Toolchain: GCC_ARM, Version 6, Release 2017 Q2
  • Board (Target): STM32F769NI Discovery
  • mbed-cli: Version 1.8.3
  • mbed-os: checked out at Commit #1bf6b20df9d3cd5f29f001ffc6f0d0fcbbb96118

The full sample code

main.cpp

#include "mbed-os/mbed.h"
#include "Ethernet.h"
#include "EthernetInterface.h"


#define UBLOX_SERIAL_TX PC_12
#define UBLOX_SERIAL_RX PD_2
#define UBLOX_BAUDRATE 115200

UARTSerial uart_ublox(UBLOX_SERIAL_TX, UBLOX_SERIAL_RX, UBLOX_BAUDRATE);
ATCmdParser* at_parser_ublox = new ATCmdParser(&uart_ublox, "\r", 256, 4000, false);

/**
 * @brief Return the MAC address in mbed.
 *
 * The address is read from the Flash register in the STM.
 *
 * @param mac  Char array to write the MAC address into
 * @return 1 if successful.
 */
uint8_t mbed_otp_mac_address(char *mac) {
    /* Reads the MAC address from an attached NINA module. */
    at_parser_ublox->send("AT+UMLA=2");
    if (at_parser_ublox->recv("+UMLA:%2X%2X%2X%2X%2X%2X\r\nOK",
        &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5])) {
            printf("MAC set\n");

            return 1;
    } else {
    /* Return some fake MAC address.
     * The default for STM32F769NI is:  00:80:e1:1b:00:24
     */
        mac[0] = 0x00;
        mac[1] = 0x80;
        mac[2] = 0xe1;
        mac[3] = 0x1b;
        mac[4] = 0x00;
        mac[5] = 0x28;

        printf("Set default MAC\n");
        return 1;
    }
};

void print_mac_reg() {
#if defined (TARGET_DISCO_F769NI)
        uint32_t ETH_MAC_ADDR_REG_OFFSET = 0x40UL;   /* RM0410, Rev.4, p. 1849 */
#else
#error "Cannot determine position of the MAC address register!"
#endif

    uint32_t *ETH_MAC_ADDR_REG_POS = (uint32_t *)(ETH_MAC_BASE + ETH_MAC_ADDR_REG_OFFSET);
    printf("[DEBUG ]: At 0x%08X : %08X\n", (ETH_MAC_ADDR_REG_POS + 0), *(ETH_MAC_ADDR_REG_POS + 0));
    printf("[DEBUG ]: At 0x%08X : %08X\n", (ETH_MAC_ADDR_REG_POS + 1), *(ETH_MAC_ADDR_REG_POS + 1));
}



int main() {
    EthernetInterface eth;
    bool success = false;

    /* In my test scenario the host PC is the gateway in it's own private network
     * 192.168.0.0/24, whereas the STM is a client with the IP 192.168.0.11 
     */
    success = eth.set_network("192.168.0.11", "255.255.255.0", "192.168.0.1");
    if (success == NSAPI_ERROR_OK) {
        debug("Address set!\n");
    }

    success = eth.connect();
    if (success == NSAPI_ERROR_OK) {
        debug("Interface is connected!\n");
    }

    printf("Interface MAC address is %s\n", eth.get_mac_address());
    printf("The interface IP address is '%s'\n", eth.get_ip_address());

    /* Setup UDP so we can send out packets and check wireshark for the MAC */
    UDPSocket sock;
    UDPSocket *client_sock;
    SocketAddress remote("192.168.0.1", 10234);
    char *message = "Hello World!";

    sock.open(&eth);
    sock.connect(remote);
    sock.bind(10234);

    client_sock = &sock;

    while(1) {
        printf("[ INFO ]: Interface MAC address is %s\n", eth.get_mac_address());
        print_mac_reg();
        client_sock->send(message, strlen(message));
        wait(1);
    }
}

1 Answer

1 year, 2 months ago.

Hello, regarding the MAC address change, I have the same issue and no solution yet. regarding the fact you do no receive any UDP message: udp is not connected, I don't think you need connect and if you don't need a server (receive) you can omit bind. To send udp messages, you should use sendto(<destAddr>, <dest-port>, <msg>, <msgLen>), in you case sock.sendto("192.168.0.1", 10234, message, strlen(message));

hope this helps.

About UDP:

You are right, UDP is a connectionless protocol. But looking in the docs you will find that the call to "bind" and "connect" will filter incoming/outgoing packets. I used this approach since i took this snippet from another code I wrote that used TCP/UDP/TLS interchangeably - thus the "un-UDP-ish" approach. :-)

About the MAC addresses:

So far I could confirm that the STM will happily answer ANY incoming packet as long as the Destination MAC address is a multicast Ethernet address (but not singlecast...). Could you please confirm this behaviour as well?
For testing purposes I wrote a "random MAC generator" that spits out random addresses after every reset. The code looks like this:

Random MAC address generator

uint8_t mbed_otp_mac_address(char *mac) {
    srand(time(NULL));
    int i;
    for (i = 3; i < 6; ++i) {
        mac[i] = (char)(rand() % 256);
    }

    return 1;
}

I tested about 25 different MAC addresses, so this does not seem to be random behaviour to me.

posted by Andreas Hartmann 29 Aug 2019

I'm unable to change MAC address on the STM, the address il always the same.

I did the following test on the board : my MAC is 00:80:E1:4A:00:2F if I'm correct this a singlecast MAC. I have a receiving thread and it receives messages from my PC in UDP.

void udpSrvThread()
{
    int i=0;
    char buf[100];
    SocketAddress adr;
    
    while (i>=0)
    {
        i = sock.recvfrom(&adr, buf, 100);
        if (i>=0) 
            buf[i]=0;
        else 
            buf[0]=0;
        printf("\n\nudpSrvThread: received %d data[%s] bytes from %s:%d\n\n", i, buf, adr.get_ip_address(), adr.get_port() );
    }
}
posted by serge Bernard 30 Aug 2019

Can't change the MAC, huh? That's weird. I could at least change the MAC, but nevermind that: Your address is indeed a singlecast address. And furthermore I assume it is the Mbed OS generated default address, right?

I'm asking because if I leave the MAC at it's default value in Mbed I can send/receive packets on my STM as well. So that's fine. But as soon as I change the MAC to any other value the STM becomes deaf.

Furthermore I could already determine that deep within the STM-specific LwIP Code there is a setting that controls the reception/filtering on incoming Multicast Packets. So this seems to be turned "On" in Mbed by default, meaning that ALL Multicast packets are received. Guess that as soon as I turn this off my STM will become deaf completely, but couldn't test this yet. Definitely put it on my TODO list.

Would you mind looking into changing your STMs MAC address again and tell me what happens when you do manage to change the MAC address? I'm especially interested in answering the question whether or not the STM sends/receives packets anymore once the MAC is changed to some unicast MAC address that isn't Mbeds default.

Unfortunately I need to work on another issue first, but will report back once I know more!

posted by Andreas Hartmann 02 Sep 2019