809 lines
32 KiB
C
809 lines
32 KiB
C
/**********************************************************************************
|
||
* 文件名 :W5500.c
|
||
* 描述 :W5500 驱动函数库
|
||
* 库版本 :ST_v3.5
|
||
* 作者 :泥人通信模块开发团队
|
||
* 博客 :http://nirenelec.blog.163.com
|
||
* 淘宝 :http://nirenelec.taobao.com
|
||
**********************************************************************************/
|
||
|
||
//#include "stm32f1xx.h"
|
||
//#include "stm32f1xx_hal_spi.h"
|
||
#include "main.h"
|
||
|
||
#include "bsp_W5500.h"
|
||
#include "usart.h"
|
||
#include "stdio.h"
|
||
#include "spi.h"
|
||
//#include "bsp_print.h"
|
||
|
||
|
||
#define BSP_W5500_SPI_CS_LOW
|
||
|
||
|
||
/*Run_Mode 端口的运行模式*/
|
||
#define BSP_W5500_PORT_RUN_MODE_TCP_SERVER 0x00 /*TCP服务器模式*/
|
||
#define BSP_W5500_PORT_RUN_MODE_TCP_CLIENT 0x01 /*TCP客户端模式*/
|
||
#define BSP_W5500_PORT_RUN_MODE_UDP 0x02 /*UDP(广播)模式*/
|
||
|
||
/*Run_State 端口的运行状态 BIT位*/
|
||
#define BSP_W5500_PORT_RUN_STATE_INIT 0x01 /*端口完成初始化*/
|
||
#define BSP_W5500_PORT_RUN_STATE_CONN 0x02 /*端口完成连接,可以正常传输数据*/
|
||
|
||
/*TR_Data_State 端口的收发数据状态*/
|
||
#define BSP_W5500_PORT_DATA_RECEIVE 0x01 /*端口接收到一个数据包*/
|
||
#define BSP_W5500_PORT_DATA_TRANSMITOK 0x02 /*端口发送一个数据包完成*/
|
||
|
||
static void bsp_W5500_Interrupt_Process(void);
|
||
static void bsp_W5500_Init(void);
|
||
static void bsp_W5500_Task(void);
|
||
static void Write_SOCK_Data_Buffer(bsp_W5500_Class_t *pW5500_Class, u8 *dat_ptr, u16 size);
|
||
|
||
bsp_W5500_t W5500 =
|
||
{
|
||
.Gateway_IP = {192,168,1,1},
|
||
.Sub_Mask = {255,255,255,0},
|
||
.Phy_Addr = {0x0c,0x29,0xab,0x7c,0x00,0x01},
|
||
|
||
//.IP_Addr = {169,254,107,101},
|
||
.IP_Addr = {192,168,1,101},
|
||
|
||
.Interrupt_Process = bsp_W5500_Interrupt_Process,
|
||
|
||
.Init = bsp_W5500_Init,
|
||
.Task = bsp_W5500_Task,
|
||
.Socket_Send = Write_SOCK_Data_Buffer,
|
||
|
||
.W5500_Class[0] =
|
||
{
|
||
.SocketPort = 0, /*使用端口0*/
|
||
.ConfigData.Gateway_IP = {192,168,1,1},
|
||
.ConfigData.Sub_Mask = {255,255,255,0},
|
||
.ConfigData.Phy_Addr = {0x0c,0x29,0xab,0x7c,0x00,0x01},
|
||
|
||
.ConfigData.IP_Addr = {192,168,1,101},
|
||
.ConfigData.Port = {0x13,0x88},
|
||
|
||
// .ConfigData.DIP = {192,168,1,32},
|
||
// .ConfigData.DPort = {0x03,0x09},
|
||
|
||
.Run_Mode = BSP_W5500_PORT_RUN_MODE_TCP_SERVER,
|
||
// .Rx_DataAnalysis = proto_HSMS_Rx_DataAnalysis,
|
||
},
|
||
};
|
||
|
||
bsp_W5500_t *pW5500 = &W5500;
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : SPI1_Send_Byte
|
||
* 描述 : SPI1发送1个字节数据
|
||
* 输入 : dat:待发送的数据
|
||
* 输出 : 无
|
||
* 返回值 : 无
|
||
* 说明 : 无
|
||
*******************************************************************************/
|
||
void SPI1_Send_Byte(u8 dat)
|
||
{
|
||
// hspi1.Instance->DR=dat;
|
||
HAL_SPI_Transmit(&hspi1, &dat, 1, 0xff);
|
||
// while(__HAL_SPI_GET_FLAG(&hspi1,SPI_FLAG_TXE)==RESET);
|
||
// SPI_I2S_SendData(SPI1,dat);//写1个字节数据
|
||
// while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);//等待数据寄存器空
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : SPI1_Send_Short
|
||
* 描述 : SPI1发送2个字节数据(16位)
|
||
* 输入 : dat:待发送的16位数据
|
||
* 输出 : 无
|
||
* 返回值 : 无
|
||
* 说明 : 无
|
||
*******************************************************************************/
|
||
void SPI1_Send_Short(u16 dat)
|
||
{
|
||
SPI1_Send_Byte(dat >> 8); // 写数据高位
|
||
SPI1_Send_Byte(dat); // 写数据低位
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : Write_W5500_1Byte
|
||
* 描述 : 通过SPI1向指定地址寄存器写1个字节数据
|
||
* 输入 : reg:16位寄存器地址,dat:待写入的数据
|
||
* 输出 : 无
|
||
* 返回值 : 无
|
||
* 说明 : 无
|
||
*******************************************************************************/
|
||
void Write_W5500_1Byte(u16 reg, u8 dat)
|
||
{
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||
|
||
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
|
||
SPI1_Send_Byte(FDM1 | RWB_WRITE | COMMON_R); // 通过SPI1写控制字节,1个字节数据长度,写数据,选择通用寄存器
|
||
SPI1_Send_Byte(dat); // 写1个字节数据
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : Write_W5500_2Byte
|
||
* 描述 : 通过SPI1向指定地址寄存器写2个字节数据
|
||
* 输入 : reg:16位寄存器地址,dat:16位待写入的数据(2个字节)
|
||
* 输出 : 无
|
||
* 返回值 : 无
|
||
* 说明 : 无
|
||
*******************************************************************************/
|
||
void Write_W5500_2Byte(u16 reg, u16 dat)
|
||
{
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||
|
||
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
|
||
SPI1_Send_Byte(FDM2 | RWB_WRITE | COMMON_R); // 通过SPI1写控制字节,2个字节数据长度,写数据,选择通用寄存器
|
||
SPI1_Send_Short(dat); // 写16位数据
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : Write_W5500_nByte
|
||
* 描述 : 通过SPI1向指定地址寄存器写n个字节数据
|
||
* 输入 : reg:16位寄存器地址,*dat_ptr:待写入数据缓冲区指针,size:待写入的数据长度
|
||
* 输出 : 无
|
||
* 返回值 : 无
|
||
* 说明 : 无
|
||
*******************************************************************************/
|
||
void Write_W5500_nByte(u16 reg, u8 *dat_ptr, u16 size)
|
||
{
|
||
u16 i;
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||
|
||
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
|
||
SPI1_Send_Byte(VDM | RWB_WRITE | COMMON_R); // 通过SPI1写控制字节,N个字节数据长度,写数据,选择通用寄存器
|
||
|
||
for (i = 0; i < size; i++) // 循环将缓冲区的size个字节数据写入W5500
|
||
{
|
||
SPI1_Send_Byte(*dat_ptr++); // 写一个字节数据
|
||
}
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : Write_W5500_SOCK_1Byte
|
||
* 描述 : 通过SPI1向指定端口寄存器写1个字节数据
|
||
* 输入 : s:端口号,reg:16位寄存器地址,dat:待写入的数据
|
||
* 输出 : 无
|
||
* 返回值 : 无
|
||
* 说明 : 无
|
||
*******************************************************************************/
|
||
void Write_W5500_SOCK_1Byte(SOCKET s, u16 reg, u8 dat)
|
||
{
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||
|
||
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
|
||
SPI1_Send_Byte(FDM1 | RWB_WRITE | (s * 0x20 + 0x08)); // 通过SPI1写控制字节,1个字节数据长度,写数据,选择端口s的寄存器
|
||
SPI1_Send_Byte(dat); // 写1个字节数据
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : Write_W5500_SOCK_2Byte
|
||
* 描述 : 通过SPI1向指定端口寄存器写2个字节数据
|
||
* 输入 : s:端口号,reg:16位寄存器地址,dat:16位待写入的数据(2个字节)
|
||
* 输出 : 无
|
||
* 返回值 : 无
|
||
* 说明 : 无
|
||
*******************************************************************************/
|
||
void Write_W5500_SOCK_2Byte(SOCKET s, u16 reg, u16 dat)
|
||
{
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||
|
||
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
|
||
SPI1_Send_Byte(FDM2 | RWB_WRITE | (s * 0x20 + 0x08)); // 通过SPI1写控制字节,2个字节数据长度,写数据,选择端口s的寄存器
|
||
SPI1_Send_Short(dat); // 写16位数据
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : Write_W5500_SOCK_4Byte
|
||
* 描述 : 通过SPI1向指定端口寄存器写4个字节数据
|
||
* 输入 : s:端口号,reg:16位寄存器地址,*dat_ptr:待写入的4个字节缓冲区指针
|
||
* 输出 : 无
|
||
* 返回值 : 无
|
||
* 说明 : 无
|
||
*******************************************************************************/
|
||
void Write_W5500_SOCK_4Byte(SOCKET s, u16 reg, u8 *dat_ptr)
|
||
{
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||
|
||
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
|
||
SPI1_Send_Byte(FDM4 | RWB_WRITE | (s * 0x20 + 0x08)); // 通过SPI1写控制字节,4个字节数据长度,写数据,选择端口s的寄存器
|
||
|
||
SPI1_Send_Byte(*dat_ptr++); // 写第1个字节数据
|
||
SPI1_Send_Byte(*dat_ptr++); // 写第2个字节数据
|
||
SPI1_Send_Byte(*dat_ptr++); // 写第3个字节数据
|
||
SPI1_Send_Byte(*dat_ptr++); // 写第4个字节数据
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : Read_W5500_1Byte
|
||
* 描述 : 读W5500指定地址寄存器的1个字节数据
|
||
* 输入 : reg:16位寄存器地址
|
||
* 输出 : 无
|
||
* 返回值 : 读取到寄存器的1个字节数据
|
||
* 说明 : 无
|
||
*******************************************************************************/
|
||
u8 Read_W5500_1Byte(u16 reg)
|
||
{
|
||
u8 i;
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||
|
||
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
|
||
SPI1_Send_Byte(FDM1 | RWB_READ | COMMON_R); // 通过SPI1写控制字节,1个字节数据长度,读数据,选择通用寄存器
|
||
i = hspi1.Instance->DR;
|
||
// HAL_SPI_Receive(&hspi1,&i,1,0xf);
|
||
// i=SPI_I2S_ReceiveData(SPI1);
|
||
SPI1_Send_Byte(0x00); // 发送一个哑数据
|
||
|
||
i = hspi1.Instance->DR;
|
||
// HAL_SPI_Receive(&hspi1,&i,1,0xf);
|
||
|
||
// i=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||
return i; // 返回读取到的寄存器数据
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : Read_W5500_SOCK_1Byte
|
||
* 描述 : 读W5500指定端口寄存器的1个字节数据
|
||
* 输入 : s:端口号,reg:16位寄存器地址
|
||
* 输出 : 无
|
||
* 返回值 : 读取到寄存器的1个字节数据
|
||
* 说明 : 无
|
||
*******************************************************************************/
|
||
u8 Read_W5500_SOCK_1Byte(SOCKET s, u16 reg)
|
||
{
|
||
u8 i;
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||
|
||
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
|
||
SPI1_Send_Byte(FDM1 | RWB_READ | (s * 0x20 + 0x08)); // 通过SPI1写控制字节,1个字节数据长度,读数据,选择端口s的寄存器
|
||
|
||
i = hspi1.Instance->DR;
|
||
// i=SPI_I2S_ReceiveData(SPI1);
|
||
SPI1_Send_Byte(0x00); // 发送一个哑数据
|
||
i = hspi1.Instance->DR;
|
||
// i=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||
return i; // 返回读取到的寄存器数据
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : Read_W5500_SOCK_2Byte
|
||
* 描述 : 读W5500指定端口寄存器的2个字节数据
|
||
* 输入 : s:端口号,reg:16位寄存器地址
|
||
* 输出 : 无
|
||
* 返回值 : 读取到寄存器的2个字节数据(16位)
|
||
* 说明 : 无
|
||
*******************************************************************************/
|
||
u16 Read_W5500_SOCK_2Byte(SOCKET s, u16 reg)
|
||
{
|
||
u16 i;
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||
|
||
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
|
||
SPI1_Send_Byte(FDM2 | RWB_READ | (s * 0x20 + 0x08)); // 通过SPI1写控制字节,2个字节数据长度,读数据,选择端口s的寄存器
|
||
|
||
i = hspi1.Instance->DR;
|
||
// i=SPI_I2S_ReceiveData(SPI1);
|
||
SPI1_Send_Byte(0x00); // 发送一个哑数据
|
||
i = hspi1.Instance->DR;
|
||
// i=SPI_I2S_ReceiveData(SPI1);//读取高位数据
|
||
SPI1_Send_Byte(0x00); // 发送一个哑数据
|
||
i *= 256;
|
||
i += hspi1.Instance->DR;
|
||
// i+=SPI_I2S_ReceiveData(SPI1);//读取低位数据
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||
return i; // 返回读取到的寄存器数据
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : Read_SOCK_Data_Buffer
|
||
* 描述 : 从W5500接收数据缓冲区中读取数据
|
||
* 输入 : s:端口号,*dat_ptr:数据保存缓冲区指针
|
||
* 输出 : 无
|
||
* 返回值 : 读取到的数据长度,rx_size个字节
|
||
* 说明 : 无
|
||
*******************************************************************************/
|
||
u16 Read_SOCK_Data_Buffer(SOCKET s, u8 *dat_ptr)
|
||
{
|
||
u16 rx_size;
|
||
u16 offset, offset1;
|
||
u16 i;
|
||
u8 j;
|
||
|
||
rx_size = Read_W5500_SOCK_2Byte(s, Sn_RX_RSR);
|
||
if (rx_size == 0)
|
||
return 0; // 没接收到数据则返回
|
||
if (rx_size > 1460)
|
||
rx_size = 1460;
|
||
|
||
offset = Read_W5500_SOCK_2Byte(s, Sn_RX_RD);
|
||
offset1 = offset;
|
||
offset &= (S_RX_SIZE - 1); // 计算实际的物理地址
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||
|
||
SPI1_Send_Short(offset); // 写16位地址
|
||
SPI1_Send_Byte(VDM | RWB_READ | (s * 0x20 + 0x18)); // 写控制字节,N个字节数据长度,读数据,选择端口s的寄存器
|
||
j = hspi1.Instance->DR;
|
||
// j=SPI_I2S_ReceiveData(SPI1);
|
||
|
||
if ((offset + rx_size) < S_RX_SIZE) // 如果最大地址未超过W5500接收缓冲区寄存器的最大地址
|
||
{
|
||
for (i = 0; i < rx_size; i++) // 循环读取rx_size个字节数据
|
||
{
|
||
SPI1_Send_Byte(0x00); // 发送一个哑数据
|
||
j = hspi1.Instance->DR;
|
||
// j=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据
|
||
*dat_ptr = j; // 将读取到的数据保存到数据保存缓冲区
|
||
dat_ptr++; // 数据保存缓冲区指针地址自增1
|
||
}
|
||
}
|
||
else // 如果最大地址超过W5500接收缓冲区寄存器的最大地址
|
||
{
|
||
offset = S_RX_SIZE - offset;
|
||
for (i = 0; i < offset; i++) // 循环读取出前offset个字节数据
|
||
{
|
||
SPI1_Send_Byte(0x00); // 发送一个哑数据
|
||
j = hspi1.Instance->DR;
|
||
// j=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据
|
||
*dat_ptr = j; // 将读取到的数据保存到数据保存缓冲区
|
||
dat_ptr++; // 数据保存缓冲区指针地址自增1
|
||
}
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||
|
||
SPI1_Send_Short(0x00); // 写16位地址
|
||
SPI1_Send_Byte(VDM | RWB_READ | (s * 0x20 + 0x18)); // 写控制字节,N个字节数据长度,读数据,选择端口s的寄存器
|
||
j = hspi1.Instance->DR;
|
||
// j=SPI_I2S_ReceiveData(SPI1);
|
||
|
||
for (; i < rx_size; i++) // 循环读取后rx_size-offset个字节数据
|
||
{
|
||
SPI1_Send_Byte(0x00); // 发送一个哑数据
|
||
j = hspi1.Instance->DR;
|
||
// j=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据
|
||
*dat_ptr = j; // 将读取到的数据保存到数据保存缓冲区
|
||
dat_ptr++; // 数据保存缓冲区指针地址自增1
|
||
}
|
||
}
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||
offset1 += rx_size; // 更新实际物理地址,即下次读取接收到的数据的起始地址
|
||
Write_W5500_SOCK_2Byte(s, Sn_RX_RD, offset1);
|
||
Write_W5500_SOCK_1Byte(s, Sn_CR, RECV); // 发送启动接收命令
|
||
return rx_size; // 返回接收到数据的长度
|
||
}
|
||
/*******************************************************************************
|
||
* 函数名 : Write_SOCK_Data_Buffer
|
||
* 描述 : 将数据写入W5500的数据发送缓冲区
|
||
* 输入 : s:端口号,*dat_ptr:数据保存缓冲区指针,size:待写入数据的长度
|
||
* 输出 : 无
|
||
* 返回值 : 无
|
||
* 说明 : 无
|
||
*******************************************************************************/
|
||
static void Write_SOCK_Data_Buffer(bsp_W5500_Class_t *pW5500_Class, u8 *dat_ptr, u16 size)
|
||
{
|
||
u16 offset, offset1;
|
||
u16 i;
|
||
// 如果是UDP模式,可以在此设置目的主机的IP和端口号
|
||
if ((Read_W5500_SOCK_1Byte(pW5500_Class->SocketPort, Sn_MR) & 0x0f) != SOCK_UDP) // 如果Socket打开失败
|
||
{
|
||
Write_W5500_SOCK_4Byte(pW5500_Class->SocketPort, Sn_DIPR, pW5500_Class->ConfigData.UDP_DIPR); // 设置目的主机IP
|
||
Write_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_DPORTR, pW5500_Class->ConfigData.UDP_DPORT[0]<<8 | pW5500_Class->ConfigData.UDP_DPORT[1]); // 设置目的主机端口号
|
||
}
|
||
|
||
offset = Read_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_TX_WR);
|
||
offset1 = offset;
|
||
offset &= (S_TX_SIZE - 1); // 计算实际的物理地址
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||
|
||
SPI1_Send_Short(offset); // 写16位地址
|
||
SPI1_Send_Byte(VDM | RWB_WRITE | (pW5500_Class->SocketPort * 0x20 + 0x10)); // 写控制字节,N个字节数据长度,写数据,选择端口s的寄存器
|
||
|
||
if ((offset + size) < S_TX_SIZE) // 如果最大地址未超过W5500发送缓冲区寄存器的最大地址
|
||
{
|
||
for (i = 0; i < size; i++) // 循环写入size个字节数据
|
||
{
|
||
SPI1_Send_Byte(*dat_ptr++); // 写入一个字节的数据
|
||
}
|
||
}
|
||
else // 如果最大地址超过W5500发送缓冲区寄存器的最大地址
|
||
{
|
||
offset = S_TX_SIZE - offset;
|
||
for (i = 0; i < offset; i++) // 循环写入前offset个字节数据
|
||
{
|
||
SPI1_Send_Byte(*dat_ptr++); // 写入一个字节的数据
|
||
}
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||
|
||
SPI1_Send_Short(0x00); // 写16位地址
|
||
SPI1_Send_Byte(VDM | RWB_WRITE | (pW5500_Class->SocketPort * 0x20 + 0x10)); // 写控制字节,N个字节数据长度,写数据,选择端口s的寄存器
|
||
|
||
for (; i < size; i++) // 循环写入size-offset个字节数据
|
||
{
|
||
SPI1_Send_Byte(*dat_ptr++); // 写入一个字节的数据
|
||
}
|
||
}
|
||
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||
|
||
offset1 += size; // 更新实际物理地址,即下次写待发送数据到发送数据缓冲区的起始地址
|
||
Write_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_TX_WR, offset1);
|
||
Write_W5500_SOCK_1Byte(pW5500_Class->SocketPort, Sn_CR, SEND); // 发送启动发送命令
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : W5500_Hardware_Reset
|
||
* 描述 : 硬件复位W5500
|
||
* 输入 : 无
|
||
* 输出 : 无
|
||
* 返回值 : 无
|
||
* 说明 : W5500的复位引脚保持低电平至少500us以上,才能重围W5500
|
||
*******************************************************************************/
|
||
void W5500_Hardware_Reset(void)
|
||
{
|
||
HAL_GPIO_WritePin(W5500_RST_PORT, W5500_RST, GPIO_PIN_RESET); // 复位引脚拉低
|
||
HAL_Delay(50);
|
||
HAL_GPIO_WritePin(W5500_RST_PORT, W5500_RST, GPIO_PIN_SET); // 复位引脚拉高
|
||
HAL_Delay(100);
|
||
|
||
// while((Read_W5500_1Byte(PHYCFGR)&LINK)==0);//等待以太网连接完成
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : W5500_Init
|
||
* 描述 : 初始化W5500寄存器函数
|
||
* 输入 : 无
|
||
* 输出 : 无
|
||
* 返回值 : 无
|
||
* 说明 : 在使用W5500之前,先对W5500初始化
|
||
*******************************************************************************/
|
||
void W5500_Init(void)
|
||
{
|
||
u16 i = 0;
|
||
|
||
Write_W5500_1Byte(MR, RST); // 软件复位W5500,置1有效,复位后自动清0
|
||
|
||
HAL_Delay(10); // 延时10ms,自己定义该函数
|
||
|
||
// 设置网关(Gateway)的IP地址,Gateway_IP为4字节u8数组,自己定义
|
||
// 使用网关可以使通信突破子网的局限,通过网关可以访问到其它子网或进入Internet
|
||
Write_W5500_nByte(GAR, pW5500->Gateway_IP, 4);
|
||
|
||
// 设置子网掩码(MASK)值,SUB_MASK为4字节u8数组,自己定义
|
||
// 子网掩码用于子网运算
|
||
Write_W5500_nByte(SUBR, pW5500->Sub_Mask, 4);
|
||
|
||
// 设置物理地址,PHY_ADDR为6字节u8数组,自己定义,用于唯一标识网络设备的物理地址值
|
||
// 该地址值需要到IEEE申请,按照OUI的规定,前3个字节为厂商代码,后三个字节为产品序号
|
||
// 如果自己定义物理地址,注意第一个字节必须为偶数
|
||
Write_W5500_nByte(SHAR, pW5500->Phy_Addr, 6);
|
||
|
||
// 设置本机的IP地址,IP_ADDR为4字节u8数组,自己定义
|
||
// 注意,网关IP必须与本机IP属于同一个子网,否则本机将无法找到网关
|
||
Write_W5500_nByte(SIPR, pW5500->IP_Addr, 4);
|
||
|
||
// 设置发送缓冲区和接收缓冲区的大小,参考W5500数据手册
|
||
for (i = 0; i < 8; i++)
|
||
{
|
||
Write_W5500_SOCK_1Byte(i, Sn_RXBUF_SIZE, 0x02); // Socket Rx memory size=2k
|
||
Write_W5500_SOCK_1Byte(i, Sn_TXBUF_SIZE, 0x02); // Socket Tx mempry size=2k
|
||
}
|
||
|
||
// 设置重试时间,默认为2000(200ms)
|
||
// 每一单位数值为100微秒,初始化时值设为2000(0x07D0),等于200毫秒
|
||
Write_W5500_2Byte(RTR, 0x07d0);
|
||
|
||
// 设置重试次数,默认为8次
|
||
// 如果重发的次数超过设定值,则产生超时中断(相关的端口中断寄存器中的Sn_IR 超时位(TIMEOUT)置“1”)
|
||
Write_W5500_1Byte(RCR, 8);
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : Detect_Gateway
|
||
* 描述 : 检查网关服务器
|
||
* 输入 : 无
|
||
* 输出 : 无
|
||
* 返回值 : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
|
||
* 说明 : 无
|
||
*******************************************************************************/
|
||
u8 Detect_Gateway(void)
|
||
{
|
||
u8 ip_adde[4];
|
||
ip_adde[0] = pW5500->IP_Addr[0] + 1;
|
||
ip_adde[1] = pW5500->IP_Addr[1] + 1;
|
||
ip_adde[2] = pW5500->IP_Addr[2] + 1;
|
||
ip_adde[3] = pW5500->IP_Addr[3] + 1;
|
||
|
||
// 检查网关及获取网关的物理地址
|
||
Write_W5500_SOCK_4Byte(0, Sn_DIPR, ip_adde); // 向目的地址寄存器写入与本机IP不同的IP值
|
||
Write_W5500_SOCK_1Byte(0, Sn_MR, MR_TCP); // 设置socket为TCP模式
|
||
Write_W5500_SOCK_1Byte(0, Sn_CR, OPEN); // 打开Socket
|
||
HAL_Delay(5); // 延时5ms
|
||
|
||
if (Read_W5500_SOCK_1Byte(0, Sn_SR) != SOCK_INIT) // 如果socket打开失败
|
||
{
|
||
Write_W5500_SOCK_1Byte(0, Sn_CR, CLOSE); // 打开不成功,关闭Socket
|
||
return FALSE; // 返回FALSE(0x00)
|
||
}
|
||
|
||
Write_W5500_SOCK_1Byte(0, Sn_CR, CONNECT); // 设置Socket为Connect模式
|
||
|
||
do
|
||
{
|
||
u16 j = 0;
|
||
j = Read_W5500_SOCK_1Byte(0, Sn_IR); // 读取Socket0中断标志寄存器
|
||
if (j != 0)
|
||
Write_W5500_SOCK_1Byte(0, Sn_IR, j);
|
||
HAL_Delay(5); // 延时5ms
|
||
if ((j & IR_TIMEOUT) == IR_TIMEOUT)
|
||
{
|
||
return FALSE;
|
||
}
|
||
else if (Read_W5500_SOCK_1Byte(0, Sn_DHAR) != 0xff)
|
||
{
|
||
Write_W5500_SOCK_1Byte(0, Sn_CR, CLOSE); // 关闭Socket
|
||
return TRUE;
|
||
}
|
||
} while (1);
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : Socket_Init
|
||
* 描述 : 指定Socket(0~7)初始化
|
||
* 输入 : s:待初始化的端口
|
||
* 输出 : 无
|
||
* 返回值 : 无
|
||
* 说明 : 无
|
||
*******************************************************************************/
|
||
static void bsp_W5500_Socket_Init(bsp_W5500_Class_t *pW5500_Class)
|
||
{
|
||
Write_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_MSSR, 1460); // 最大分片字节数=1460(0x5b4)
|
||
Write_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_PORT, pW5500_Class->ConfigData.Port[0]<<8 | pW5500_Class->ConfigData.Port[1]);
|
||
// 设置端口0目的(远程)端口号
|
||
Write_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_DPORTR, pW5500_Class->ConfigData.DPort[0]<<8 | pW5500_Class->ConfigData.DPort[1]);
|
||
// 设置端口0目的(远程)IP地址
|
||
Write_W5500_SOCK_4Byte(pW5500_Class->SocketPort, Sn_DIPR, pW5500_Class->ConfigData.DIP);
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : Socket_Connect
|
||
* 描述 : 设置指定Socket(0~7)为客户端与远程服务器连接
|
||
* 输入 : s:待设定的端口
|
||
* 输出 : 无
|
||
* 返回值 : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
|
||
* 说明 : 当本机Socket工作在客户端模式时,引用该程序,与远程服务器建立连接
|
||
* 如果启动连接后出现超时中断,则与服务器连接失败,需要重新调用该程序连接
|
||
* 该程序每调用一次,就与服务器产生一次连接
|
||
*******************************************************************************/
|
||
u8 Socket_Connect(SOCKET s)
|
||
{
|
||
Write_W5500_SOCK_1Byte(s, Sn_MR, MR_TCP); // 设置socket为TCP模式
|
||
Write_W5500_SOCK_1Byte(s, Sn_CR, OPEN); // 打开Socket
|
||
HAL_Delay(5); // 延时5ms
|
||
if (Read_W5500_SOCK_1Byte(s, Sn_SR) != SOCK_INIT) // 如果socket打开失败
|
||
{
|
||
Write_W5500_SOCK_1Byte(s, Sn_CR, CLOSE); // 打开不成功,关闭Socket
|
||
return FALSE; // 返回FALSE(0x00)
|
||
}
|
||
Write_W5500_SOCK_1Byte(s, Sn_CR, CONNECT); // 设置Socket为Connect模式
|
||
return TRUE; // 返回TRUE,设置成功
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : Socket_Listen
|
||
* 描述 : 设置指定Socket(0~7)作为服务器等待远程主机的连接
|
||
* 输入 : s:待设定的端口
|
||
* 输出 : 无
|
||
* 返回值 : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
|
||
* 说明 : 当本机Socket工作在服务器模式时,引用该程序,等等远程主机的连接
|
||
* 该程序只调用一次,就使W5500设置为服务器模式
|
||
*******************************************************************************/
|
||
u8 Socket_Listen(SOCKET s)
|
||
{
|
||
Write_W5500_SOCK_1Byte(s, Sn_MR, MR_TCP); // 设置socket为TCP模式
|
||
Write_W5500_SOCK_1Byte(s, Sn_CR, OPEN); // 打开Socket
|
||
HAL_Delay(5); // 延时5ms
|
||
if (Read_W5500_SOCK_1Byte(s, Sn_SR) != SOCK_INIT) // 如果socket打开失败
|
||
{
|
||
Write_W5500_SOCK_1Byte(s, Sn_CR, CLOSE); // 打开不成功,关闭Socket
|
||
return FALSE; // 返回FALSE(0x00)
|
||
}
|
||
Write_W5500_SOCK_1Byte(s, Sn_CR, LISTEN); // 设置Socket为侦听模式
|
||
HAL_Delay(5); // 延时5ms
|
||
if (Read_W5500_SOCK_1Byte(s, Sn_SR) != SOCK_LISTEN) // 如果socket设置失败
|
||
{
|
||
Write_W5500_SOCK_1Byte(s, Sn_CR, CLOSE); // 设置不成功,关闭Socket
|
||
return FALSE; // 返回FALSE(0x00)
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
// 至此完成了Socket的打开和设置侦听工作,至于远程客户端是否与它建立连接,则需要等待Socket中断,
|
||
// 以判断Socket的连接是否成功。参考W5500数据手册的Socket中断状态
|
||
// 在服务器侦听模式不需要设置目的IP和目的端口号
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : Socket_UDP
|
||
* 描述 : 设置指定Socket(0~7)为UDP模式
|
||
* 输入 : s:待设定的端口
|
||
* 输出 : 无
|
||
* 返回值 : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
|
||
* 说明 : 如果Socket工作在UDP模式,引用该程序,在UDP模式下,Socket通信不需要建立连接
|
||
* 该程序只调用一次,就使W5500设置为UDP模式
|
||
*******************************************************************************/
|
||
u8 Socket_UDP(SOCKET s)
|
||
{
|
||
Write_W5500_SOCK_1Byte(s, Sn_MR, MR_UDP); // 设置Socket为UDP模式*/
|
||
Write_W5500_SOCK_1Byte(s, Sn_CR, OPEN); // 打开Socket*/
|
||
HAL_Delay(5); // 延时5ms
|
||
if (Read_W5500_SOCK_1Byte(s, Sn_SR) != SOCK_UDP) // 如果Socket打开失败
|
||
{
|
||
Write_W5500_SOCK_1Byte(s, Sn_CR, CLOSE); // 打开不成功,关闭Socket
|
||
return FALSE; // 返回FALSE(0x00)
|
||
}
|
||
else
|
||
return TRUE;
|
||
|
||
// 至此完成了Socket的打开和UDP模式设置,在这种模式下它不需要与远程主机建立连接
|
||
// 因为Socket不需要建立连接,所以在发送数据前都可以设置目的主机IP和目的Socket的端口号
|
||
// 如果目的主机IP和目的Socket的端口号是固定的,在运行过程中没有改变,那么也可以在这里设置
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* 函数名 : W5500_Interrupt_Process
|
||
* 描述 : W5500中断处理程序框架
|
||
* 输入 : 无
|
||
* 输出 : 无
|
||
* 返回值 : 无
|
||
* 说明 : 无
|
||
*******************************************************************************/
|
||
static void bsp_W5500_Interrupt_Process(void)
|
||
{
|
||
u8 i, j;
|
||
u8 Int_Flag,Socket_Flag;
|
||
|
||
IntDispose:
|
||
|
||
Int_Flag = Read_W5500_1Byte(SIR); // 读取端口中断标志寄存器
|
||
HAL_Delay(10);
|
||
for(i=0;i<BSP_W5500_PORT_NUM;i++)
|
||
{
|
||
if(Int_Flag & (0x01 << i))
|
||
{
|
||
Socket_Flag = Read_W5500_SOCK_1Byte(pW5500->W5500_Class[i].SocketPort, Sn_IR); // 读取Socket0中断标志寄存器
|
||
Write_W5500_SOCK_1Byte(pW5500->W5500_Class[i].SocketPort, Sn_IR, Socket_Flag);
|
||
if (Socket_Flag & IR_CON) // 在TCP模式下,Socket0成功连接
|
||
{
|
||
pW5500->W5500_Class[i].Run_State |= BSP_W5500_PORT_RUN_STATE_CONN; // 网络连接状态0x02,端口完成连接,可以正常传输数据
|
||
}
|
||
if (Socket_Flag & IR_DISCON) // 在TCP模式下Socket断开连接处理
|
||
{
|
||
Write_W5500_SOCK_1Byte(pW5500->W5500_Class[i].SocketPort, Sn_CR, CLOSE); // 关闭端口,等待重新打开连接
|
||
bsp_W5500_Socket_Init(&pW5500->W5500_Class[i]); // 指定Socket(0~7)初始化,初始化端口0
|
||
pW5500->W5500_Class[i].Run_State = 0; // 网络连接状态0x00,端口连接失败
|
||
}
|
||
if (Socket_Flag & IR_SEND_OK) // Socket0数据发送完成,可以再次启动S_tx_process()函数发送数据
|
||
{
|
||
pW5500->W5500_Class[i].TR_Data_State |= BSP_W5500_PORT_DATA_TRANSMITOK; // 端口发送一个数据包完成
|
||
}
|
||
if (Socket_Flag & IR_RECV) // Socket接收到数据,可以启动S_rx_process()函数
|
||
{
|
||
pW5500->W5500_Class[i].TR_Data_State |= BSP_W5500_PORT_DATA_RECEIVE; // 端口接收到一个数据包
|
||
}
|
||
if (Socket_Flag & IR_TIMEOUT) // Socket连接或数据传输超时处理
|
||
{
|
||
Write_W5500_SOCK_1Byte(pW5500->W5500_Class[i].SocketPort, Sn_CR, CLOSE); // 关闭端口,等待重新打开连接
|
||
pW5500->W5500_Class[i].TR_Data_State = 0; // 网络连接状态0x00,端口连接失败
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
if (Read_W5500_1Byte(SIR) != 0)
|
||
goto IntDispose;
|
||
}
|
||
|
||
|
||
void bsp_W5500_Socket_Set(bsp_W5500_Class_t *pW5500_Class)
|
||
{
|
||
if (0 == pW5500_Class->Run_State)
|
||
{
|
||
switch(pW5500_Class->Run_Mode)
|
||
{
|
||
/*TCP服务器模式*/
|
||
case BSP_W5500_PORT_RUN_MODE_TCP_SERVER:
|
||
{
|
||
if (Socket_Listen(pW5500_Class->SocketPort) == TRUE)
|
||
pW5500_Class->Run_State = BSP_W5500_PORT_RUN_STATE_INIT;
|
||
else
|
||
pW5500_Class->Run_State = 0;
|
||
}break;
|
||
/*TCP客户端模式*/
|
||
case BSP_W5500_PORT_RUN_MODE_TCP_CLIENT:
|
||
{
|
||
if(Socket_Connect(pW5500_Class->SocketPort)==TRUE)
|
||
pW5500_Class->Run_State = BSP_W5500_PORT_RUN_STATE_INIT;
|
||
else
|
||
pW5500_Class->Run_State = 0;
|
||
}break;
|
||
/*UDP模式*/
|
||
case BSP_W5500_PORT_RUN_MODE_UDP:
|
||
{
|
||
if(Socket_UDP(pW5500_Class->SocketPort)==TRUE)
|
||
pW5500_Class->Run_State = BSP_W5500_PORT_RUN_STATE_INIT | BSP_W5500_PORT_RUN_STATE_CONN;
|
||
else
|
||
pW5500_Class->Run_State = 0;
|
||
}break;
|
||
default:break;
|
||
}
|
||
}
|
||
}
|
||
|
||
static void bsp_W5500_Init()
|
||
{
|
||
u8 i;
|
||
W5500_Hardware_Reset(); /*硬件复位W5500*/
|
||
W5500_Init(); /*初始化W5500寄存器函数*/
|
||
Detect_Gateway(); /*检查网关服务器*/
|
||
|
||
for(i=0;i<BSP_W5500_PORT_NUM;i++)
|
||
{
|
||
bsp_W5500_Socket_Init(&pW5500->W5500_Class[i]);
|
||
pW5500->W5500_Class[i].Run_State = 0; /*复位状态*/
|
||
//bsp_W5500_Socket_Set(&pW5500->W5500_Class[i]); /*W5500端口初始化配置*/
|
||
}
|
||
}
|
||
|
||
static void bsp_W5500_Task(void)
|
||
{
|
||
u8 i;
|
||
for(i=0;i<BSP_W5500_PORT_NUM;i++)
|
||
{
|
||
bsp_W5500_Socket_Set(&pW5500->W5500_Class[i]); /*W5500端口初始化配置*/
|
||
}
|
||
bsp_W5500_Interrupt_Process(); // W5500中断处理程序框架
|
||
|
||
for(i=0;i<BSP_W5500_PORT_NUM;i++)
|
||
{
|
||
if ((pW5500->W5500_Class[i].TR_Data_State & BSP_W5500_PORT_DATA_RECEIVE) == BSP_W5500_PORT_DATA_RECEIVE) // 如果Socket0接收到数据
|
||
{
|
||
pW5500->W5500_Class[i].TR_Data_State &= ~BSP_W5500_PORT_DATA_RECEIVE;
|
||
u16 Len = Read_SOCK_Data_Buffer(0, pW5500->W5500_Class[i].Rx_Buffer);
|
||
// Write_SOCK_Data_Buffer(&pW5500->W5500_Class[i], pW5500->W5500_Class[i].Rx_Buffer, Len);
|
||
// printf("RX");
|
||
// Debug_UartSend(pW5500->W5500_Class[i].Rx_Buffer, Len);
|
||
if(pW5500->W5500_Class[i].Rx_DataAnalysis != NULL)
|
||
{
|
||
pW5500->W5500_Class[i].Rx_DataAnalysis(&pW5500->W5500_Class[i],pW5500->W5500_Class[i].Rx_Buffer,Len);/*数据解析*/
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|