Connecting W5300 to STM32F103 via FSMC interface

As W5300 supports only Parallel Bus Interface to Host MCU, connecting W5300 to STM32F103 MCU needs FSMC(Flexible Static Memory Controller) interface.

I’ll show you here how to configure FSMC interface for W5300 and how to set up a loopback application as an example of TCP/IP communication using W5300

Configure FSMC

In Pinout and Configuration Tab, select Connectivity->FSMC and.

In FSMC Mode block, click “NOR Flash/PSRAM/SRAM/ROM/LCD 3”, select “NE3” on Chip Select, “SRAM” on Memory type, “10 bits” on Address, and “16 bit” on Data.

In FSMC Configuration block, change Write operation to “Enable”, in NOR/PSRAM timing section, change “Data setup time in HCLK clock cycles” to 3 and other fields to 0.

Setting ioLibrary

WIZnet provides a driver and related libraries, named ioLibrary(internet offload Library), for their chips

We need to install ioLibrary into the previous project to use W5300.

There are two ways to install ioLibrary. One is using submodule command and the other is to download a .zip file from the github repository and uncompresses it in the top folder of the project folder.

The github repository of ioLibarys is https://github.com/Wiznet/ioLibrary_Driver.

Select W5300 Chip in ioLibrary

In wizchip_conf.h, set _WIZCHIP_ W5300 as below

in wizchip_conf.h
...
#ifndef _WIZCHIP_
#define _WIZCHIP_                                       W5300
#endif
...

Next, we need to define MCU Interface mode.

W5300 is connected to STM32F103 MCU via Parallel Bus Interface. We should set MCU Interface mode as Direct Bus Mode.

Related code is the same as below

in wizchip_conf.h
...
#elif ( _WIZCHIP_ == W5300)
    #define _WIZCHIP_ID_                         "W5300"

#ifndef _WIZCHIP_IO_MODE_
    #define _WIZCHIP_IO_MODE_          _WIZCHIP_IO_MODE_BUS_DIR_
#endif

And please set Data Bus Width to 16bit.

in wizchip_conf.h
...
#ifndef _WIZCHIP_IO_BUS_WIDTH_
#define _WIZCHIP_IO_BUS_WIDTH_                16
#endif

And finally, we need to set the base address of W5300 because STM32F103 treats W5300 as an external memory on WIZ145SR.

On WIZ145SR, W5300 is connected to FSMC Bank1 of STM32F103 and /CS of W5300 is tied to NE3 pin of STM32103. It means that W5300 is being addressed as FSMC Bank1 and Subbank3.

As below, the base address of FSMC Bank1 and Subbank3 is 6800 0000h.

So, set _WIZCHIP_IO_BASE_ as below.

in wizchip_conf.h
...
#if _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_BUS_
	#define _WIZCHIP_IO_BASE_				0x68000000	// for W5300
#elif _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_SPI_
	#define _WIZCHIP_IO_BASE_				0x00000000	// for 5100S SPI
#endif

Setting PATH

After hardware configuration, now we need to set up the build environment.

First, set the location of header files on ioLibrary in STM32CubeIDE.

Add three paths after select C/C++Build->Setting->Tool Settings->MCU GCC Compiler->Include paths as below.

Next, set Source Location as below, to find source files having implementation codes.

Writing Basic Code

Now, it is ready to make a TCP/IP application.

As a basic application, we’ll reset W5300 and access W5300 registers.

If we can read from and write to W5300 registers properly, we can make any TCP/IP communication application using libraries in ioLibrary.

For a basic application using ioLibrary, we should register callback functions for read and write operation and W5300 reset function.

First make a W5300BasicFunctions.h and W5300BasicFunctions.c

And write codes in W5300BasicFunctions.h as below.

#ifndef INC_W5300BASICFUNCTIONS_H_
#define INC_W5300BASICFUNCTIONS_H_

#include "wizchip_conf.h"

void Reset_W5300(void);
void W5300_write(uint32_t addr, iodata_t wd);
iodata_t W5300_read(uint32_t addr);


#endif /* INC_W5300BASICFUNCTIONS_H_ */

Then write codes in W5300BasicFunctions.c as below.

#include "main.h"
#include "W5300BasicFunctions.h"

void Reset_W5300()
{
	HAL_GPIO_WritePin(RESET_W5300_GPIO_Port, RESET_W5300_Pin, GPIO_PIN_RESET);
	HAL_Delay(10);
	HAL_GPIO_WritePin(RESET_W5300_GPIO_Port, RESET_W5300_Pin, GPIO_PIN_SET);
	HAL_Delay(100);
}

void W5300_write(uint32_t addr, iodata_t wd)
{
	*((uint16_t*)(addr << 1)) = wd;
}

iodata_t W5300_read(uint32_t addr)
{
	return *((uint16_t*)(addr << 1));
}

Next, add some codes to call functions we added in Main.c

...
Reset_W5300();
reg_wizchip_bus_cbfunc(W5300_read, W5300_write);
...

Now, we can access W5300 registers.

Add below codes to check whether we can read from and write to some registers on W5300.

...
  Reset_W5300();
  reg_wizchip_bus_cbfunc(W5300_read, W5300_write);

  printf("getMR() = %04Xrn", getMR());

  getSHAR(tmpaddr);
  printf("SHAR=%02X:%02X:%02X:%02X:%02X:%02Xrn", tmpaddr[0], tmpaddr[1], tmpaddr[2], tmpaddr[3], tmpaddr[4], tmpaddr[5]);
  getSIPR(tmpaddr);
  printf("SIPR=%d.%d.%d.%drn", tmpaddr[0], tmpaddr[1], tmpaddr[2], tmpaddr[3]);
  getGAR(tmpaddr);
  printf("SIPR=%d.%d.%d.%drn", tmpaddr[0], tmpaddr[1], tmpaddr[2], tmpaddr[3]);
  getSUBR(tmpaddr);
  printf("SUBR=%d.%d.%d.%drn", tmpaddr[0], tmpaddr[1], tmpaddr[2], tmpaddr[3]);

  setSHAR(gWIZNETINFO.mac);
  setSIPR(gWIZNETINFO.ip);
  setGAR(gWIZNETINFO.gw);
  setSUBR(gWIZNETINFO.sn);

  getSHAR(tmpaddr);
  printf("SHAR=%02X:%02X:%02X:%02X:%02X:%02Xrn", tmpaddr[0], tmpaddr[1], tmpaddr[2], tmpaddr[3], tmpaddr[4], tmpaddr[5]);
  getSIPR(tmpaddr);
  printf("SIPR=%d.%d.%d.%drn", tmpaddr[0], tmpaddr[1], tmpaddr[2], tmpaddr[3]);
  getGAR(tmpaddr);
  printf("SIPR=%d.%d.%d.%drn", tmpaddr[0], tmpaddr[1], tmpaddr[2], tmpaddr[3]);
  getSUBR(tmpaddr);
  printf("SUBR=%d.%d.%d.%drn", tmpaddr[0], tmpaddr[1], tmpaddr[2], tmpaddr[3]);

Build and Download

Next build a binary code and download it to WIZ145SR using STM32CubeProgrammer

Loopback Example

Now, we will make a TCP/IP communication application.

In this application, we will create a socket and listen to a connection request on the created socket. After a connection is established, all data received on the socket echoes back to the sender. For this, WIZnet provides a example, called loopback_tcps() on ioLibrary. So, we’ll use this function.

For TCP/IP communication, we need network information like IP address, Gateway address, Subnet mask and so on.

wiz_Netinfo is data structure for this and we define local network information with this structure like below.

We should change below information according to the real network environment.

in main.c
...
/* USER CODE BEGIN PV */
wiz_NetInfo gWIZNETINFO = {
		.mac = {0x00, 0x08, 0xdc, 0xff, 0xff, 0xff},
		.ip = {192, 168, 0, 60},
		.sn = {255, 255, 255, 0},
		.gw = {192, 168, 0, 1},
		.dns = {168, 126, 63, 1},
		.dhcp = NETINFO_DHCP
};
/* USER CODE END PV */
...

Next, we need to configure tx buffer size and rx buffer size for each socket of W5300. W5300 has 8 sockets and each socket has tx buffer and rx buffer respectively. We can configure buffer size differently socket by socket. Default buffer size is 8Kbytes each.

Declare two dimensional array for tx and rx buffer size.

Regarding buffer size constraints, please refer to W5300 Datasheet.

in main.c
...
uint8_t W5300_memsize[2][8] = {{8,8,8,8,8,8,8,8}, {8,8,8,8,8,8,8,8}};
...

If we call W5300Initialize() function with the array we declared, related registers will be set. After it, we can read related registers whether buffer sizes are set properly.

in main.c
...
uint8_t W5300_memsize[2][8] = {{8,8,8,8,8,8,8,8}, {8,8,8,8,8,8,8,8}};
...
W5300Initialize(W5300_memsize); 

printf("GetTMS01R()%04Xrn", getTMS01R());
printf("GetTMS23R()%04Xrn", getTMS23R());
printf("GetTMS45R()%04Xrn", getTMS45R());
printf("GetTMS67R()%04Xrn", getTMS67R());
printf("GetRMS01R()%04Xrn", getRMS01R());
printf("GetRMS23R()%04Xrn", getRMS23R());
printf("GetRMS45R()%04Xrn", getRMS45R());
printf("GetRMS67R()%04Xrn", getRMS67R());

W5300Initialize calls ctlwizchip() function which ioLibrary provides.

in W5300BasicFunctions.c
...
void W5300Initialize(unsigned char * mem_size)
{
	if (ctlwizchip(CW_INIT_WIZCHIP, (void*)mem_size) == -1)
	{
		printf("W5300 memory initialization failedrn");
	}
}

Next, we should write the network information to the related register. For this, just call ctlnetwork() function with the network information we prepared before.

print_network_information() is a function to display in a human readable format.

Please check whether everything is the same as what you wrote. If not, it means that your code or hardware configuration has something wrong. You need to verify what you did step by step.

in main.c
...  
  ctlnetwork(CN_SET_NETINFO, (void *)&gWIZNETINFO);
  print_network_information();
...

Adding loopback server function

To call loopback_tcps, we need three parameters, socket number, data buffer and port number to listen.

loopback_tcps(socket_num, buffer, port_num);

socket_num is integer value from 0 to 7, buffer is the pointer of the buffer to store received data, and port_num is the port number of the listening socket.

In the below example, we open socket 0 and listen to port number 5000, and store data to ethBuf0 when the socket received.

in main.c
...
#define ETH_MAX_BUF_SIZE		2048
uint8_t ethBuf0[ETH_MAX_BUF_SIZE];
...
while(1)
{
   ...
	  loopback_tcps(0, ethBuf0, 5000);   
}

If you succeeded so far, the STM32CubeIDE project you made works well.

Next time, we will raise UART baud rate with UART DMA as an intermediate project.

For the project code, please refer to the below link.

https://github.com/javakys/WIZ14xSR_Proj/releases/tag/Ver0.5

3 Comments

  1. kirant400 says:

    I tried the program.
    I am receiving
    Mac address: 00:00:00:00:00:00
    IP address : 0.0.0.0
    SM Mask : 0.0.0.0
    Gate way : 0.0.0.0
    DNS Server : 168.126.63.1
    Not able to communicate.

  2. kirant400 says:

    Working now. Modified to
    #define _WIZCHIP_IO_BASE_ 0x34000000 // for W5300
    From
    #define _WIZCHIP_IO_BASE_ 0x68000000

Leave a Comment