W5500: incomplete MACRAW frames

In the project I’m working on I wrote support for w5500 MACRAW reading. Frames are passed to the TCP/IP stack (lwIP).
At low load, everything works OK, but if I start to send larger data packages (eg I want to update the uC firmware), there are some errors in the data.

The problem looks like this:

  1. I check if there are data in the RX buffer with the ‘getSn_RX_RSR ()’ function. The function returns the value 1900.
  2. OK, so I can read first 2 bytes from buffer - there should be the length of MACRAW, but this is where problem appears: after calculating length of the MAC frame I get value 22,000 bytes.

I started to dump all data received from SPI. First dump 1900 bytes. I noticed that at the beginning of buffer are some random bytes – this is why I get 22,000 MAC frame length.
Next MACRAW frame starts at byte number 800 and has a length of 1492 bytes. So there is missing 392 bytes (800 + 1492 – 1900).
But at the next reading (1000 B), I get the missing 392 bytes of previous frame + half of the next MACRAW frame, and so on.

I solved this problem temporarily by analyzing the readed data in my software and sending complete MAC frames to the TCP/IP stack, but this solution is very slow compared to just reading data over SPI.

To read data from w5500, I used this library https://github.com/d-a-v/W5500MacRaw with some small modifications. Here are 4 method used to get MACRAW frames.

The connection over SPI to w5500 looks like this:

bool Wiznet5500::begin(const uint8_t *mac_address)
    if (vspi == NULL)
	    memcpy(_mac_address, mac_address, 6);

	    gpio_set_direction(_cs, GPIO_MODE_INPUT_OUTPUT);

	    vspi = new SPIClass(VSPI);


	    // Use the full 16Kb of RAM for Socket 0

	    // Set our local MAC address

	    // Open Socket 0 in MACRaw mode
	    setSn_MR(Sn_MR_MACRAW | Sn_MR_MFEN);

	    uint8_t cfg = getPHYCFGR();
	    cfg |= PHYCFGR_OPMD;

    if (getSn_SR() != SOCK_MACRAW)
	    // Failed to put socket 0 into MACRaw mode
	    printf("[Wiznet5500] Failed to put socket 0 into MACRaw mode\n");
	    return false;

    // Success
    printf("[Wiznet5500] Ready\n");
    return true;

Checking if there is data to be read + checking the length of the MACRAW:

uint16_t Wiznet5500::readFrameSize()
    uint16_t tmpBufLen = getSn_RX_RSR();

    //no data to read
    if (tmpBufLen == 0)
	    return 0;

    uint8_t head[2];
    uint16_t data_len = 0;

    //get 2 data length bytes
    wizchip_recv_data(head, 2);
    while (getSn_CR())

    data_len = head[0];
    data_len = (data_len << 8) + head[1];

    if (data_len > 1)
	    data_len -= 2;
	    return 0;

    return data_len;

MACRAW reading:

Wiznet5500::readFrame + Wiznet5500::readFrameData
uint16_t Wiznet5500::readFrame(uint8_t *buffer, uint16_t bufsize)
    uint16_t data_len = readFrameSize();

    if (data_len == 0)
	    return 0;

    if (data_len > bufsize)
	    // Packet is bigger than buffer - drop the packet
	    printf("[Wiznet5500] Frame Discard %hu\n", data_len);
	    return 0;

    return readFrameData(buffer, data_len);

uint16_t Wiznet5500::readFrameData(uint8_t *buffer, uint16_t framesize)
    wizchip_recv_data(buffer, framesize);
    while (getSn_CR())

    // Had problems with W5500 MAC address filtering (the Sn_MR_MFEN option)
    // Do it in software instead:
    if ((buffer[0] & 0x01) || memcmp(&buffer[0], _mac_address, 6) == 0)
	    // Addressed to an Ethernet multicast address or our unicast address
	    return framesize;
	    printf("[w5500] MACRAW FRAME ERROR!!!\n");
	    // dumpFrame(buffer, framesize);
	    return 0;

And my questions:

  1. Why is the second half of the previously readed frame at the beginning of current data instead of 2 bytes MACRAW length?
  2. Do I make any mistake while reading data over SPI so this shift in the RX buffer appears?
  3. Is there any solution to this problem?


It would help if you share a SPI data dump and Wireshark log.

I suspect you wanted to allocate 16K for RX.

But if tmpBufLen is 1, you will get wrong value.

I did not use MACRAW mode, but I suspect that you should perform differently. Instead of taking frame size only and then performing RECV command, you must flush whole data size indicated by RSR into your working RAM buffer, perform RECV and then parse data in working RAM buffer afterwards.