STM Lesson 91. LAN. W5500. HTTP Server. Part 2
STM Lesson 91. LAN. W5500. HTTP Server. Part 2
0
Project description
Part 2
LAN. W5500. HTTP server
B previous part we got acquainted with the W5500 module, studied the organization of memory and data exchange of the W5500 chip, created and configured the project.
Initialization begins with a reboot of the module. I took this from an example written for an assessment fee and posted on an official website, I did not find this in the technical documentation.
So let's start writing the initialization function in the file w5500.c
//-----------------------------------------------
void w5500_ini(void)
{
uint8_t dtt=0;
uint8_t opcode=0;
//Hard Reset
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_Delay(70);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
HAL_Delay(70);
}
//-----------------------------------------------
We will write a prototype for this function and connect our module in a file net.h
#include <stdint.h>
#include "w5500.h"
In the net.c file in the corresponding function, call our initialization function
void net_ini(void)
{
w5500_ini();
}
After a hardware reboot using the RESET leg, we will restart the software.
To do this, first write some macros in the file w5500.h
#define MAC_ADDR {0x00,0x15,0x42,0xBF,0xF0,0x51}
//--------------------------------------------------
#define BSB_COMMON 0x00
#define BSB_S0 0x01
#define BSB_S0_TX 0x02
#define BSB_S0_RX 0x03
//--------------------------------------------------
#define RWB_WRITE 1
#define RWB_READ 0
//--------------------------------------------------
#define OM_FDM0 0x00//режим передачи данных переменной длины
#define OM_FDM1 0x01//режим передачи данных по одному байту
#define OM_FDM2 0x02//режим передачи данных по два байта
#define OM_FDM3 0x03//режим передачи данных по четыре байта
//--------------------------------------------------
#define MR 0x0000//Mode Register
//--------------------------------------------------
Above the initialization function in the w5500.c file we write the function of writing the byte in the register
//-----------------------------------------------
void w5500_writeReg(uint8_t op, uint16_t addres, uint8_t data)
{
uint8_t buf[] = {addres >> 8, addres, op|(RWB_WRITE<<2), data};
SS_SELECT();
HAL_SPI_Transmit(&hspi1, buf, 4, 0xFFFFFFFF);
SS_DESELECT();
}
//-----------------------------------------------
We sequentially write to the 4-byte buffer the address of the register ( memory cells ), then the operation code with the one attached to it using the operation OR a bit of recording and a actually byte of data. Then we lower the selection leg, pass these 4 bytes using the corresponding function of the HAL library, and then lift the device selection leg.
Now write the code for the software reboot of the module into the initialization function
HAL_Delay(70);
//Soft Reset
opcode = (BSB_COMMON<<3)|OM_FDM1;
w5500_writeReg(opcode, MR, 0x80);
HAL_Delay(100);
Register we use a common Mr, and the mode of fixed transmission of one byte

We only take the 7th bit in it. After that, you need to wait in theory when this bit drops. Thus, we find out that the reboot has occurred. But it’s enough just to wait a few milliseconds, not often we initialize the chip.
Next, we configure all the addresses for our chip, entering them also in certain registers. Before that, we will add macros to the header file for this w5500.h
#define MR 0x0000//Mode Register
//--------------------------------------------------
#define SHAR0 0x0009//Source Hardware Address Register MSB
#define SHAR1 0x000A
#define SHAR2 0x000B
#define SHAR3 0x000C
#define SHAR4 0x000D
#define SHAR5 0x000E// LSB
#define GWR0 0x0001//Gateway IP Address Register MSB
#define GWR1 0x0002
#define GWR2 0x0003
#define GWR3 0x0004// LSB
#define SUBR0 0x0005//Subnet Mask Register MSB
#define SUBR1 0x0006
#define SUBR2 0x0007
#define SUBR3 0x0008// LSB
#define SIPR0 0x000F//Source IP Address Register MSB
#define SIPR1 0x0010
#define SIPR2 0x0011
#define SIPR3 0x0012// LSB
//--------------------------------------------------
Which register is responsible for what is visible from the comments on it.
Let's move to the initialization function to a file w5500.c and configure register data
HAL_Delay(100);
//Configute Net
w5500_writeReg(opcode, SHAR0,macaddr[0]);
w5500_writeReg(opcode, SHAR1,macaddr[1]);
w5500_writeReg(opcode, SHAR2,macaddr[2]);
w5500_writeReg(opcode, SHAR3,macaddr[3]);
w5500_writeReg(opcode, SHAR4,macaddr[4]);
w5500_writeReg(opcode, SHAR5,macaddr[5]);
w5500_writeReg(opcode, GWR0,ipgate[0]);
w5500_writeReg(opcode, GWR1,ipgate[1]);
w5500_writeReg(opcode, GWR2,ipgate[2]);
w5500_writeReg(opcode, GWR3,ipgate[3]);
w5500_writeReg(opcode, SUBR0,ipmask[0]);
w5500_writeReg(opcode, SUBR1,ipmask[1]);
w5500_writeReg(opcode, SUBR2,ipmask[2]);
w5500_writeReg(opcode, SUBR3,ipmask[3]);
w5500_writeReg(opcode, SIPR0,ipaddr[0]);
w5500_writeReg(opcode, SIPR1,ipaddr[1]);
w5500_writeReg(opcode, SIPR2,ipaddr[2]);
w5500_writeReg(opcode, SIPR3,ipaddr[3]);
Since data registers are also common, the opcode does not change.
Now set up a port for socket 0.
To do this, add registers for port numbers to a file w5500.h
#define SIPR3 0x0012// LSB
//--------------------------------------------------
#define Sn_PORT0 0x0004 // Socket 0 Source Port Register MSB
#define Sn_PORT1 0x0005 // Socket 0 Source Port Register LSB
//--------------------------------------------------
Now in the initialization function in the file w5500.h enter the data of our port in the registers
w5500_writeReg(opcode, SIPR3,ipaddr[3]);
//Настраиваем сокет 0
opcode = (BSB_S0<<3)|OM_FDM1;
w5500_writeReg(opcode, Sn_PORT0,local_port>>8);
w5500_writeReg(opcode, Sn_PORT1,local_port);
Here, the type of register is already changing, so we will initialize the opcode again.
In principle, at this step we can already collect the code and pass the controller.
And we will already have our module to ping. That is, ICMP and ARP will work.
Let's do it.
Before stitching the controller, let's see our ( scheme, click on the image to enlarge the image )
We will open the controller and check the availability of our module

Everything is working! You can continue further.
In file w5500.h add a structure for the properties of the connection
#define be16toword(a) ((((a)>>8)&0xff)|(((a)<<8)&0xff00))
//--------------------------------------------------
typedef struct tcp_prop {
volatile uint8_t cur_sock;//активный сокет
} tcp_prop_ptr;
//--------------------------------------------------
Add a global variable of the type of our structure in the file w5500.c
extern char str1[60];
tcp_prop_ptr tcpprop;
In the initialization pound, we initialize the active ( current ) socket
w5500_writeReg(opcode, Sn_PORT1,local_port);
//инициализируем активный сокет
tcpprop.cur_sock = 0;
After the register write function, add the function of reading data from the register
//-----------------------------------------------
uint8_t w5500_readReg(uint8_t op, uint16_t addres)
{
uint8_t data;
uint8_t wbuf[] = {addres >> 8, addres, op, 0x0};
uint8_t rbuf[4];
SS_SELECT();
HAL_SPI_TransmitReceive(&hspi1, wbuf, rbuf, 4, 0xFFFFFFFF);
SS_DESELECT();
data = rbuf[3];
return data;
}
//-----------------------------------------------
Here we work somewhat differently. We type the same thing into the buffer, only we don’t include the bit of the record, and you can use any data by writing to buffer 0. Then we organize another buffer and call up the function of ring data exchange on the SPI bus, which will return to us in the last element of the array the byte we need from the register.
In the w5500.h file, we will add a few more macros with register addresses and some parameters and conditions that we will meet later
#define Sn_PORT1 0x0005 // Socket 1 Source Port Register 1 LSB
//--------------------------------------------------
#define Sn_MR 0x0000 // Socket 0 Mode Register
#define Sn_CR 0x0001 // Socket 0 Command Register
#define Sn_SR 0x0003 // Socket 0 Status Register
//--------------------------------------------------
//Socket mode
#define Mode_CLOSED 0x00
#define Mode_TCP 0x01
#define Mode_UDP 0x02
#define Mode_MACRAV 0x04
//--------------------------------------------------
//Socket states
#define SOCK_CLOSED 0x00
#define SOCK_INIT 0x13
#define SOCK_LISTEN 0x14
#define SOCK_ESTABLISHED 0x17
//-------------------------------------------
#define Sn_MSSR0 0x0012
#define Sn_MSSR1 0x0013
#define Sn_TX_FSR0 0x0020
#define Sn_TX_FSR1 0x0021
#define Sn_TX_RD0 0x0022
#define Sn_TX_RD1 0x0023
#define Sn_TX_WR0 0x0024
#define Sn_TX_WR1 0x0025
#define Sn_RX_RSR0 0x0026
#define Sn_RX_RSR1 0x0027
#define Sn_RX_RD0 0x0028
#define Sn_RX_RD1 0x0029
//--------------------------------------------------
Let's go to the file w5500.c and add two more functions to initialize and wait for the end of socket initialization
//-----------------------------------------------
void OpenSocket(uint8_t sock_num, uint16_t mode)
{
uint8_t opcode=0;
opcode = (((sock_num<<2)|BSB_S0)<<3)|OM_FDM1;
w5500_writeReg(opcode, Sn_MR, mode);
w5500_writeReg(opcode, Sn_CR, 0x01);
}
//-----------------------------------------------
void SocketInitWait(uint8_t sock_num)
{
uint8_t opcode=0;
opcode = (((sock_num<<2)|BSB_S0)<<3)|OM_FDM1;
while(1)
{
if(w5500_readReg(opcode, Sn_SR)==SOCK_INIT)
{
break;
}
}
}
//-----------------------------------------------
Add prototypes for these functions.
In the first function, we enter the type of operating mode in the socket mode register corresponding to the socket with the number that came in the incoming parameter, which will also come in the incoming parameter. Then we install a bit in the control register of the socket corresponding to the socket opening command. This sign will immediately tell us about all this and tell us

And in the second function, we interrogate the register of the state of the socket, and wait there for a value of 0x13 corresponding to the state of "INIT"

Call function data in initialization function
tcpprop.cur_sock = 0;
//Открываем сокет 0
OpenSocket(0,Mode_TCP);
SocketInitWait(0);
Now we will have to serve this socket, that is, monitor when some TCP packet from the client comes to us. To do this, we will also write two functions
//-----------------------------------------------
void ListenSocket(uint8_t sock_num)
{
uint8_t opcode=0;
opcode = (((sock_num<<2)|BSB_S0)<<3)|OM_FDM1;
w5500_writeReg(opcode, Sn_CR, 0x02); //LISTEN SOCKET
}
//-----------------------------------------------
void SocketListenWait(uint8_t sock_num)
{
uint8_t opcode=0;
opcode = (((sock_num<<2)|BSB_S0)<<3)|OM_FDM1;
while(1)
{
if(w5500_readReg(opcode, Sn_SR)==SOCK_LISTEN)
{
break;
}
}
}
//-----------------------------------------------
We also add prototypes in the title file for these functions.
Here we have a similar situation. In the first function, we transfer the command 0x02, which transfers the socket to the state "Listen"

And the second function waits for this state to be established by reading the status register byte

Call function data in initialization function
SocketInitWait(0);
//Начинаем слушать сокет
ListenSocket(0);
SocketListenWait(0);
Just in case, we’ll wait a bit and see the state of the ( chip, although this is not necessary ). I heard about cases that the programma still waited for the desired state in the function, and then this state was reset by itself. This is what we will control
SocketListenWait(0);
HAL_Delay(500);
//Посмотрим статусы
opcode = (BSB_S0<<3)|OM_FDM1;
dtt = w5500_readReg(opcode, Sn_SR);
sprintf(str1,"First Status Sn0: 0x%02X\r\n",dtt);
HAL_UART_Transmit(&huart2,(uint8_t*)str1,strlen(str1),0x1000);
}
//-----------------------------------------------
We collect the code, send the controller and see the output in the terminal program
![]()
On this, initialization can be considered completed.
Now we will need to try to accept some package from the network.
Below the initialization function, create a package acceptance function
//-----------------------------------------------
void w5500_packetReceive(void)
{
uint16_t point;
uint16_t len;
}
//-----------------------------------------------
We create a prototype for this function in the header file and call it in the corresponding function in the file net.c
void packet_receive(void)
{
w5500_packetReceive();
}
In file w5500.c over the initialization function, add the function for determining the current state of the socket
//-----------------------------------------------
uint8_t GetSocketStatus(uint8_t sock_num)
{
uint8_t dt;
uint8_t opcode=0;
opcode = (((sock_num<<2)|BSB_S0)<<3)|OM_FDM1;
dt = w5500_readReg(opcode, Sn_SR);
return dt;
}
//-----------------------------------------------
To find out the state of the socket, we interrogate the register of the state of the socket, the number of which we pass in the incoming argument.
Now we create a condition for the state of the current socket in the function of receiving the package. It must be in the status of "United"
uint16_t len;
if(GetSocketStatus(tcpprop.cur_sock)==SOCK_ESTABLISHED)
{
}
B next part lesson we explore the HTTP request that came from the client and begin to form an answer to it.
