WIZnet W5500 supports up to 80MHz SPI Clock so users with an MCU that provide a high-speed SPI communication can enjoy maximum ethernet throughput. In this post, I will show how STM32 MCU can achieve the best throughput with W5500.
When using Cortex M3/M4 line’s 32bit processors from STMicro, the ethernet throughput greatly varies upon which SPI communication mode is used. I will compare the difference of throughput between using SPI standard mode and using SPI DMA mode.
MCU board : Nucleo STM32F401RE
Ethernet controller : WIZnet WIZ550io(W5500 inside)
The pin connection between the MCU board and WIZnet WIZ550io is shown in the table below.
First, connect the Power line.
Second, connect SPI signals. But, connect SCS pin to GPIOA_Pin12 because I’m going to handle it in Software method.
Third, connect RSTn pin to GPIOA_Pin11 to reset WIZ550io.
Finally, connect RDY pin that signals WIZ550io initialization is complete to GPIOA_Pin1 .
It is not crucial that RSTn pin and RDY pin be connected but it’s best for stability.
How to implement SPI protocol
SPI protocol to control W5500 is the same in both SPI Standard mode and SPI DMA mode. However, the difference between two modes is whether there is idle time between data on SPI bus.
SPI protocol for W5500 is provided in W5500.c of WIZnet ioLibrary and has the below four functions.
- WIZCHIP_READ(uint32_t AddrSel)
- WIZCHIP_WRITE(uint32_t AddrSel, uint8_t wb)
- WIZCHIP_READ_BUF(uint32_t AddrSel, uint8_t* pBuf, uint16_t len)
- WIZCHIP_WRITE_BUF(uint32_t AddrSel, uint8_t* pBuf, uint16_t len)
When SPI DMA mode is not used, the inside of the function calls standard SPI read/write function like the below WIZCHIP_READ_BUF() function.
#if !defined (SPI_DMA)
WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16);
WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8);
WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0);
for(i = 0; i < len; i++) pBuf[i] = WIZCHIP.IF.SPI._read_byte();
When SPI DMA mode is used, it prepares commands data, which consists of address and opcode, and calls SPI_DMA_READ() function.
spi_data = (AddrSel & 0x00FF0000) >> 16;
spi_data = (AddrSel & 0x0000FF00) >> 8;
spi_data = (AddrSel & 0x000000FF) >> 0;
SPI_DMA_READ(spi_data, pBuf, len);
As explained on “How to implement the full duplex communication using the SPI DMA in STM32F2xx or STM32F4xx“, SPI_DMA_READ() and SPI_DMA_WRITE() are composed of the code to use SPI DMA mode.
Performance Comparison between Standard SPI mode & SPI DMA mode
The source code in the related data below is a sample code for loopback testing. It shows how much difference exists in performance between Standard SPI mode and SPI DMA mode.
Standard SPI mode
If you make “#define SPI_DMA” line as comment and compile it, then it will operate in standard SPI mode.
If you download the binary file which you got after compilation onto a Nucleo board and do loopback test with AX1.exe which WIZnet provides, then the transmission and reception will each achieve 1.6Mbps like the image below and we can know that the SPI full throughput is up to 3.2Mbps.
Here, SPI clock is 24MHz and you can clearly see the idle time between SPI data.
SPI DMA mode
Like above, make “#define SPI_DMA” line enabled from comment and compile it.
Next, if you download the binary file onto Nucleo, then you can see the throughput of SPI DMA mode. The loopback test performance of transmission and reception is each 4.3Mbps and SPI full throughput is over 8Mbps. If you use your own board that has a high speed external clock instead of Nucleo board, then you can get much faster throughput.