Peripheral Driver Library Development
Peripheral Driver Library Development
0
Project description
1.?Function overview
W5500 is a single-chip full-hardware TCP/IP protocol stack developed by WIZnet, which can easily implement network connection applications.1.1?、Hardware description
As a full hardware TCP/IP embedded Ethernet controller, W5500 provides a simpler Internet connection solution for embedded systems.?W5500 integrates TCP/IP protocol stack, 10/100M Ethernet data link layer (MAC) and physical layer (PHY), enabling users to expand network connectivity in their applications using a single chip.?The pin layout and subassembly are as follows:
W5500 full hardware TCP/IP protocol stack supports TCP, UDP, IPv4, ICMP, ARP, IGMP and PPPoE protocols.?The W5500 embeds 32K bytes of on-chip cache for Ethernet packet processing.?Using the W5500, Ethernet applications can be implemented with only some simple Socket programming.?Users can use 8 hardware sockets for independent communication at the same time.
The W5500 provides SPI (Peripheral Serial Interface) for easier integration with peripheral MCUs.?Moreover, W5500 uses a new high-efficiency SPI protocol to support 80MHz rate, which can better realize high-speed network communication.?In order to reduce system power consumption, W5500 provides Wake-on-LAN (WOL) and power-down modes for customers to choose from.
1.2?、 Communication interface
W5500 provides SPI (Serial External Interface) as the peripheral host interface, there are 4 signals of SCSn, SCLK, MOSI, MISO, and it works as an SPI slave.?The connection between W5500 and MCU is shown in the figure below.?According to whether SCSn is controlled by the host, its working mode is divided into variable data length mode and fixed data length mode.?In variable data length mode, W5500 can share the SPI interface with other SPI devices.?In fixed data length mode, SPI will be assigned to W5500 and cannot be shared with other SPI devices.
The SPI protocol defines four operating modes (mode 0, 1, 2, 3).?The difference between each mode is defined according to the polarity and phase of SCLK.?The only difference between Mode 0 and Mode 3 of the SPI is the polarity of the SCLK signal in the inactive state.?In SPI modes 0 and 3, data is latched on the rising edge of SCLK and output on the falling edge.?W5500 supports SPI mode 0 and mode 3.?MOSI and MISO signals, whether received or transmitted, follow a transmission sequence from the most significant bit (MSB) to the least significant bit (LSB).
1.3?、Internal register
The SPI data frame of W5500 includes the offset address of the 16-bit address segment, the 8-bit control segment and the N-byte data segment.?As shown in the figure below:
The address field specifies a 16-bit offset address for the W5500's registers or TX/RX buffers.?The value of this 16-bit offset address comes from the sequential transfer from the highest flag bit to the lowest flag bit.
The control segment specifies the ownership of the offset area set by the address segment, the read/write access mode and the SPI working mode.?The 8-bit control segment can be redefined by modifying the region selection bits (BSB[4:0]), the read/write access mode bits (RWB), and the SPI operating mode bits (OM[1:0]).?The region select bits select the region that belongs to the offset address.
The data segment of the SPI data frame is automatically incremented by the offset address (the offset address increases by 1 for every 1 byte transferred), supporting continuous data read/write.
W5500 has 1 general-purpose register, 8 Socket register areas, and send and receive buffer areas corresponding to each Socket.?Each region is selected by the region selection bits (BSB[4:0]) of the SPI data frame.?The sending buffer area of ??each Socket is in a 16KB physical sending memory, and the initial allocation is 2KB.?The receive buffer area of ??each Socket is in a 16KB physical receive memory, which is initially allocated as 2KB.?Regardless of how much receive/transmit buffer is allocated to each Socket, it must be within the 16-bit offset address range (from 0x0000 to 0xFFFF).
The general register area is configured with basic information such as the IP address and MAC address of the W5500.?This area can be selected by the area selection bits (BSB[4:0]) of the SPI data frame.
W5500 supports 8 Sockets as communication channels.?Each Socket is controlled by the Socket n register area (0≤n≤7).?The Socket n register can select the corresponding register n through the area selection register (BSB[4:0]) in the SPI data frame.
2.?Drive design and implementation
We have already had a more detailed understanding of the pin package, interface method, protocol stack operation process and basic operation library of the W5500 Ethernet controller.?Next we will design and implement the driver for the W5500 Ethernet controller.2.1?、Object definition
Before using an object we need to obtain an object.?Similarly, if we want the W5500 Ethernet controller, we need to define the object of the W5500 Ethernet controller first.2.1.1?、Object abstraction
To get the W5500 Ethernet controller object, we need to analyze its basic characteristics first.?Generally speaking, an object contains at least two characteristics: attributes and operations.?Next, let's think about the objects of the W5500 Ethernet controller from these two aspects. Consider properties first, as properties are definitely something that identifies or records characteristics of an object.?Let's consider the W5500 Ethernet Controller object properties.?As an Ethernet controller, the W5500 object obviously needs to have network configuration parameters as its attributes, including IP address and MAC address, etc.?So we define the network parameters as properties of the object.?Here we define network parameters in the form of structures. Then we also need to consider the operation of the W5500 Ethernet Controller object.?In fact, our operation of the W5500 is the operation of the SPI interface. Here, because we use the basic library of the manufacturer, we pass the operation function in the way of function registration callback function.?We no longer need to operate on the SPI ports as objects, but pass them in the initialization function as function pointers.?Then our operation on the object is the operation of reading and writing information, and the specific data processing always depends on the specific application, so we regard it as the operation of the object. According to our analysis of the W5500 Ethernet controller above, we can define the object types of the W5500 Ethernet controller as follows:1 /* Define the W5500 object type */ 2 typedef struct W5500Object { 3 wiz_NetInfo gWIZNETINFO; 4 uint16_t (*DataParsing)(uint8_t *rxBuffer,uint16_t rxSize,uint8_t *txBuffer); // Receive message parsing and return message generation, the return value is The byte length of the returned message is 5 uint16_t (*RequestData)(uint8_t *rqBuffer); // Get the request command, which is generally used by the client to initiate access 6 }W5500ObjectType;
2.1.2?、Object initialization
We know that an object cannot be used only by declaring it, we need to initialize it first, so here we consider the initialization function of the W5500 Ethernet controller object.?Generally speaking, the initialization function needs to deal with several aspects.?The first is to check whether the input parameters are reasonable; the second is to assign initial values ??to the properties of the object; the third is to make the necessary initialization configuration for the object.?Accordingly, we design the initialization function of the W5500 Ethernet controller object as follows:1 /* W5500 object initialization */ 2 void W5500Initialization(W5500ObjectType * w5500, 3 uint8_t mac[ 6 ], // local Mac address 4 uint8_t ip[ 4 ], // local IP address 5 uint8_t sn[ 4 ], // sub Netmask 6 uint8_t gw[ 4 ], // Gateway address 7 uint8_t dns[ 4 ], // DNS server address 8 DHCP dhcp_mode, // the DHCP type . 9 W5500CSCrisType cris_en, 10 W5500CSCrisType cris_ex, . 11 W5500CSCrisType cs_sel, 12 is W5500CSCrisType cs_desel, 13 is W5500SPIReadByteTYpe spi_rb, 14 W5500SPIWriteByteTYpe spi_wb, 15 W5500DataParsingType dataParse, 16 W5500RequestDataType requst . 17 ) 18 is { . 19 IF((w5500==NULL)||(cris_en==NULL)||(cris_ex==NULL)||(cs_sel==NULL)||(cs_desel==NULL)||(spi_rb==NULL)||( spi_wb== NULL)) 20 { 21 return ; 22 } 23 24 for ( int i= 0 ;i< 6 ;i++ ) 25 { 26 w5500->gWIZNETINFO.mac[i]= mac[i]; 27 } 28 29 for ( int i= 0 ; i< 4 ; i++ ) 30 { 31 w5500->gWIZNETINFO.ip[i]= ip[i]; 32 w5500->gWIZNETINFO.sn[i]= sn[i]; 33 w5500->gWIZNETINFO.gw[i]= gw[i]; 34 w5500->gWIZNETINFO.dns[i]= dns[i]; 35 } 36 37 w5500->gWIZNETINFO.dhcp= dhcp; 38 39 /* Register the callback functions related to TCP communication */ 40 RegisterFunction(cris_en,cris_ex,cs_sel,cs_desel,spi_rb,spi_wb); 41 42 /* Initialize chip parameters */ 43 ChipParametersConfiguration (); 44 45 /* Initialize network communication parameters */ 46 NetworkParameterConfiguration(w5500-> gWIZNETINFO); 47 48 if (dataParse!= NULL) 49 { 50 w5500->DataParsing= dataParse; 51 } 52 else 53 { 54 w5500->DataParsing= LoopBackDataHandle; 55 } 56 57 if (requst!= NULL) 58 { 59 w5500->RequestData = requst; 60 } 61 else 62 { 63 w5500->RequestData= DefaultRequest; 64 } 65 }
2.2?, object operation
We have completed the definition of the W5500 Ethernet controller object type and the design of the object initialization function.?But our main goal is to get the information of the object, and then we have to implement various operations for the W5500 Ethernet controller. What are the operations of the W5500 Ethernet controller??As a communication interface, the most important thing is to send and receive data.?Of course, we can implement these functions, but these functions are already provided in the basic library provided by the manufacturer, we just need to use them directly, so we will not list them here.3?, the use of the driver
We have designed the driver for the W5500 Ethernet controller, let's design a simple application to verify this driver.3.1?, declare and initialize the object
To use object-based operations, we need to get this object first, so we first declare a W5500 Ethernet controller object variable using the W5500 Ethernet controller object type defined earlier. The specific operation format is as follows: W5500ObjectType w5500; Declaring this object variable cannot be used immediately, we also need to use the initialization function defined in the driver to initialize this variable.?The input parameters required by this initialization function are as follows: W5500ObjectType *w5500, uint8_t mac[6], //local Mac address uint8_t ip[4], //local IP address uint8_t sn[4], //subnet mask uint8_t gw[4], //gateway address uint8_t dns[4], //DNS server address dhcp_mode dhcp, //DHCP type W5500CSCrisTypecris_en, W5500CSCrisTypecris_ex, W5500CSCrisType cs_sel, W5500CSCrisType cs_desel, W5500SPIReadByteTYpe spi_rb, W5500SPIWriteByteTYpe spi_wb, W5500DataParsingType dataParse, W5500RequestDataType request For these parameters, the object variables we have defined.?And the parameters of IP address, we only need to input it when we fall asleep.?The main thing is that we need to define several functions with function pointers as parameters.?The types of these functions are as follows:1 /* Parse the received data */ 2 typedef uint16_t (*W5500DataParsingType)(uint8_t *rxBuffer,uint16_t rxSize,uint8_t * txBuffer); 3 4 /* Get the request command, which is generally used by the client to initiate access */ 5 typedef uint16_t (*W5500RequestDataType)(uint8_t * rqBuffer); 6 7 /* Define chip select and critical section operation function type */ 8 typedef void (*W5500CSCrisType)( void ); 9 10 /* Define SPI read one byte function type */ 11 typedef uint8_t (*W5500SPIReadByteTYpe)( void ); 12 13 /*Define SPI to write a byte function type */ 14 typedef void (*W5500SPIWriteByteTYpe)(uint8_t wb);
1 /* Write 1 byte of data to the SPI bus */ 2 static void SPI_WriteByte(uint8_t TxData) 3 { 4 HAL_SPI_Transmit(&w5500hspi,&TxData, 1 , 1000 ); 5 } 6 7 /* Read 1 byte of data from the SPI bus */ 8 static uint8_t SPI_ReadByte( void ) 9 { 10 uint8_t rxData; 11 HAL_SPI_Receive(&w5500hspi,&rxData, 1 , 1000 ); 12 return rxData; // return the received data 13 } 14 15 /* Enter critical section */ 16 static void SPI_CrisEnter( void ) 17 { 18 __set_PRIMASK( 1 ); 19 } 20 21 /* Exit critical section */ 22 static void SPI_CrisExit( void ) 23 { 24 __set_PRIMASK( 0 ) ; 25 } 26 27 /* chip select signal output low level */ 28 static void SPI_CS_Select( void ) 29 { 30 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); 31 } 32 33 /* chip select signal output high level */ 34 static void SPI_CS_Deselect( void ) 35 { 36 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); 37 } 38 39 /* Data loopback processing */ 40 static uint16_t LoopBackDataHandle(uint8_t *rxBuffer,uint16_t rxSize,uint8_t * txBuffer) 41 { 42 uint16_t txSize = 0 ; 43 44 txSize= (uint16_t)rxSize; 45 46 for ( int i= 0 ;i<txSize;i++ ) 47 { 48 txBuffer[i]= rxBuffer[i]; 49 } 50 51 return txSize; 52 } 53 54 /* default test request */ 55 static uint16_t DefaultRequest(uint8_t * rqBuffer) 56 { 57 uint16_t rSize= 0 ; 58 59 char requstString[]= "This is a new client connection.rn " ; 60 61 rSize= strlen(requstString); 62 63 for ( int i= 0 ;i<rSize;i++ ) 64 { 65 rqBuffer[i]= requstString[i]; 66 } 67 68 return rSize; 69 }
1 /* W5500 initialization configuration */ 2 void W5500Configuration( void ) 3 { 4 uint8_t mac[ 6 ]= { 0x01 , 0x08 , 0xdc , 0x00 , 0xab , 0xcd }; // Local Mac address 5 uint8_t ip[ 4 ]= { 192 , 168 , 1 , 190 }; // local IP address 6 uint8_t sn[ 4 ]= { 255 ,255 , 255 , 0 }; // Subnet mask 7 uint8_t gw[ 4 ]= { 192 , 168 , 1 , 1 }; // Gateway address 8 uint8_t dns[ 4 ]= { 0 , 0 , 0 , 0 } ; // DNS server address 9 10 W5500_SPI_Configuration(); 11 W5500Initialization(&w5500,mac,ip,sn,gw,dns,NETINFO_STATIC,SPI_CrisEnter,SPI_CrisExit,SPI_CS_Select,SPI_CS_Deselect,SPI_ReadByte,SPI_WriteByte,NULL,NULL); 12 }
3.2?. Object-based operations
We define the object variable and initialize it using the initialization function.?Then we will consider manipulating this object to get the data we want.?We have already acquired the data and converted it into the scale value of the converted value in the driver, and then we use this driver to develop our application example.?We implement a TCP loopback server.?The specific call is as follows: W5500TCPServer(&w5500,Socket0,502); The TCP server is designed as follows:1 /* TCP server data communication */ 2 int32_t W5500TCPServer(W5500ObjectType * w5500,W5500SocketType sn,uint16_t lPort) 3 { 4 int32_t ret; 5 6 switch (getSn_SR(sn)) 7 { 8 case SOCK_ESTABLISHED: 9 { 10 if (getSn_IR (sn) & Sn_IR_CON) 11 { 12 setSn_IR(sn,Sn_IR_CON); 13 } 14 uint16_t size= 0 ; 15 if ((size = getSn_RX_RSR(sn)) > 0) 16 { 17 if (size > DATA_BUFFER_SIZE) 18 { 19 size = DATA_BUFFER_SIZE; 20 } 21 22 uint8_t rxBuffer[DATA_BUFFER_SIZE]; 23 ret = recv(sn,rxBuffer,size); 24 if (ret <= 0 ) 25 { 26 return ret; 27 } 28 29 // Add data parsing and response functions 30 uint8_t txBuffer[DATA_BUFFER_SIZE]; 31 uint16_t length=w5500-> DataParsing(rxBuffer,ret,txBuffer); 32 33 uint16_t sentsize= 0 ; 34 while (length != sentsize) 35 { 36 ret = send(sn,txBuffer+sentsize,length- sentsize); 37 if (ret < 0 ) 38 { 39 close(sn); 40 return ret; 41 } 42 sentsize += ret; // don't care about SOCKERR_BUSY because it's zero. 43 } 44 } 45 break ; 46 } 47 case SOCK_CLOSE_WAIT: 48 { 49 if ((ret=disconnect(sn)) != SOCK_OK) 50 { 51 return ret; 52 } 53 break ; 54 } 55 case SOCK_INIT: 56 { 57 if ( (ret = listen(sn)) != SOCK_OK) 58 { 59 return ret; 60 } 61 break ; 62 } 63 case SOCK_CLOSED: 64 { 65 if ((ret=socket(sn,Sn_MR_TCP,lPort, 0x00 )) != sn) 66 { 67 return ret; 68 } 69 break ; 70 } 71 default : 72 { 73 break ; 74 } 75 } 76 return 1 ; 77 }

