update w5500 w25q

This commit is contained in:
2026-02-03 12:01:38 +08:00
parent f56744ad7a
commit 270141591e
12 changed files with 6823 additions and 0 deletions
+247
View File
@@ -0,0 +1,247 @@
#include "bsp_DS1302.h"
#define bsp_DS1302_DELAY() do{ \
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
}while(0)
#define RST_CLR HAL_GPIO_WritePin(DS1302_RST_GPIO_Port, DS1302_RST_Pin, GPIO_PIN_RESET )
#define RST_SET HAL_GPIO_WritePin(DS1302_RST_GPIO_Port, DS1302_RST_Pin, GPIO_PIN_SET )
#define IO_CLR HAL_GPIO_WritePin(DS1302_DIO_GPIO_Port, DS1302_DIO_Pin, GPIO_PIN_RESET )
#define IO_SET HAL_GPIO_WritePin(DS1302_DIO_GPIO_Port, DS1302_DIO_Pin, GPIO_PIN_SET )
#define IO_READ HAL_GPIO_ReadPin (DS1302_DIO_GPIO_Port, DS1302_DIO_Pin )
#define SCK_CLR HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_RESET )
#define SCK_SET HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_SET )
static void bsp_DS1302Init(void);
static void bsp_DS1302_Task(void);
static u8 bsp_DS1302_Set(bsp_DS1302_Time_t *pTime);
bsp_DS1302_t DS1302 =
{
.Init = bsp_DS1302Init,
.Task = bsp_DS1302_Task,
.Set = bsp_DS1302_Set,
};
bsp_DS1302_t *pDS1302 = &DS1302;
static void bsp_DS1302DataInput(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体
GPIO_InitStruct.Pin = DS1302_DIO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DS1302_DIO_GPIO_Port, &GPIO_InitStruct);
}
static void bsp_DS1302DataOutput(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体
GPIO_InitStruct.Pin = DS1302_DIO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DS1302_DIO_GPIO_Port, &GPIO_InitStruct);
}
/*向bsp_DS1302写入一字节数据*/
static void bsp_DS1302_write_byte(u8 Addr, u8 Data)
{
u8 i;
RST_SET; /*启动bsp_DS1302总线*/
bsp_DS1302_DELAY();
/*写入目标地址:addr*/
Addr = Addr & 0xFE;/*最低位置零*/
for (i = 0; i < 8; i++)
{
if (Addr & 0x01)
{
IO_SET;
}
else
{
IO_CLR;
}
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
Addr = Addr >> 1;
}
/*写入数据:d*/
for (i = 0; i < 8; i++)
{
if (Data & 0x01)
{
IO_SET;
}
else
{
IO_CLR;
}
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
Data = Data >> 1;
}
RST_CLR; /*停止bsp_DS1302总线*/
bsp_DS1302_DELAY();
}
/*从bsp_DS1302读出一字节数据*/
static u8 bsp_DS1302_read_byte(u8 Addr)
{
u8 i;
u8 temp;
RST_SET; /*启动bsp_DS1302总线*/
bsp_DS1302_DELAY();
/*写入目标地址:addr*/
Addr = Addr | 0x01;/*最低位置高*/
for (i = 0; i < 8; i++)
{
if (Addr & 0x01)
{
IO_SET;
}
else
{
IO_CLR;
}
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
Addr = Addr >> 1;
}
bsp_DS1302DataInput();
/*输出数据:temp*/
for (i = 0; i < 8; i++)
{
temp = temp >> 1;
if (IO_READ)
{
temp |= 0x80;
}
else
{
temp &= 0x7F;
}
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
}
RST_CLR; /*停止bsp_DS1302总线*/
bsp_DS1302_DELAY();
bsp_DS1302DataOutput();
return temp;
}
static u8 HexToBCD(u8 code)
{
u8 temp;
temp = ((code / 10) << 4) + (code % 10);
return temp;
}
static u8 bsp_DS1302_Set(bsp_DS1302_Time_t *pTime)
{
if ((pDS1302->Time.Year > 99) || (pDS1302->Time.Month > 12) || (pDS1302->Time.Day > 31) ||
(pDS1302->Time.Hour > 23) || (pDS1302->Time.Minute > 59) || (pDS1302->Time.Second > 59))
{
return USR_FALSE;
}
else
{
bsp_DS1302_write_byte(BSP_DS1302_CONTROL_ADDR, 0x00); //关闭写保护
bsp_DS1302_write_byte(BSP_DS1302_SEC_ADDR, 0x80); //暂停
bsp_DS1302_write_byte(BSP_DS1302_YEAR_ADDR, HexToBCD(pTime->Year));
bsp_DS1302_write_byte(BSP_DS1302_MONTH_ADDR, HexToBCD(pTime->Month));
bsp_DS1302_write_byte(BSP_DS1302_DATA_ADDR, HexToBCD(pTime->Day));
bsp_DS1302_write_byte(BSP_DS1302_HOUR_ADDR, HexToBCD(pTime->Hour));
bsp_DS1302_write_byte(BSP_DS1302_MIN_ADDR, HexToBCD(pTime->Minute));
bsp_DS1302_write_byte(BSP_DS1302_SEC_ADDR, HexToBCD(pTime->Second));
bsp_DS1302_write_byte(BSP_DS1302_CONTROL_ADDR, 0x80); //打开写保护
return USR_TRUE;
}
}
static void bsp_DS1302_Task(void)
{
u8 RegData;
RegData = bsp_DS1302_read_byte(BSP_DS1302_YEAR_ADDR);
pDS1302->Time.Year = (RegData / 16) * 10 + RegData % 16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_MONTH_ADDR);
pDS1302->Time.Month = (RegData / 16) * 10 + RegData % 16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_DATA_ADDR);
pDS1302->Time.Day = (RegData / 16) * 10 + RegData % 16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_HOUR_ADDR);
pDS1302->Time.Hour = (RegData / 16) * 10 + RegData % 16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_MIN_ADDR);
pDS1302->Time.Minute = (RegData / 16) * 10 + RegData % 16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_SEC_ADDR);
pDS1302->Time.Second = (RegData / 16) * 10 + RegData % 16;
}
static void bsp_DS1302Init(void)
{
RST_SET;
SCK_CLR;
bsp_DS1302_Task();
if ((pDS1302->Time.Year > 99) || (pDS1302->Time.Month > 12) || (pDS1302->Time.Day > 31) ||
(pDS1302->Time.Hour > 23) || (pDS1302->Time.Minute > 59) || (pDS1302->Time.Second > 59))
{
pDS1302->Time.Year = 25;
pDS1302->Time.Month = 1;
pDS1302->Time.Day = 1;
pDS1302->Time.Hour = 0;
pDS1302->Time.Minute = 0;
pDS1302->Time.Second = 0;
bsp_DS1302_Set(&pDS1302->Time);
}
}
+206
View File
@@ -0,0 +1,206 @@
#include "bsp_DS1302.h"
#define bsp_DS1302_DELAY() do{ \
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
}while(0)
#define RST_CLR HAL_GPIO_WritePin(DS1302_RST_GPIO_Port, DS1302_RST_Pin, GPIO_PIN_RESET )
#define RST_SET HAL_GPIO_WritePin(DS1302_RST_GPIO_Port, DS1302_RST_Pin, GPIO_PIN_SET )
#define IO_CLR HAL_GPIO_WritePin(DS1302_DIO_GPIO_Port, DS1302_DIO_Pin, GPIO_PIN_RESET )
#define IO_SET HAL_GPIO_WritePin(DS1302_DIO_GPIO_Port, DS1302_DIO_Pin, GPIO_PIN_SET )
#define IO_READ HAL_GPIO_ReadPin (DS1302_DIO_GPIO_Port, DS1302_DIO_Pin )
#define SCK_CLR HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_RESET )
#define SCK_SET HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_SET )
static void bsp_DS1302Init(void);
static void bsp_DS1302_Task(void);
static void bsp_DS1302_Set(bsp_DS1302_Time_t *pTime);
bsp_DS1302_t DS1302 =
{
.Init = bsp_DS1302Init,
.Task = bsp_DS1302_Task,
.Set = bsp_DS1302_Set,
};
bsp_DS1302_t *pDS1302 = &DS1302;
static void bsp_DS1302DataInput(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体
GPIO_InitStruct.Pin = DS1302_DIO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DS1302_DIO_GPIO_Port, &GPIO_InitStruct);
}
static void bsp_DS1302DataOutput(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体
GPIO_InitStruct.Pin = DS1302_DIO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DS1302_DIO_GPIO_Port, &GPIO_InitStruct);
}
/*向bsp_DS1302写入一字节数据*/
static void bsp_DS1302_write_byte(u8 Addr, u8 Data)
{
u8 i;
RST_SET; /*启动bsp_DS1302总线*/
bsp_DS1302_DELAY();
/*写入目标地址:addr*/
Addr = Addr & 0xFE;/*最低位置零*/
for(i=0; i<8; i++){
if(Addr&0x01) IO_SET;
else IO_CLR;
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
Addr = Addr >> 1;
}
/*写入数据:d*/
for(i=0; i<8; i++){
if(Data&0x01) IO_SET;
else IO_CLR;
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
Data = Data >> 1;
}
RST_CLR; /*停止bsp_DS1302总线*/
bsp_DS1302_DELAY();
}
/*从bsp_DS1302读出一字节数据*/
static u8 bsp_DS1302_read_byte(u8 Addr)
{
u8 i;
u8 temp;
RST_SET; /*启动bsp_DS1302总线*/
bsp_DS1302_DELAY();
/*写入目标地址:addr*/
Addr = Addr | 0x01;/*最低位置高*/
for(i=0; i<8; i++)
{
if(Addr&0x01)
{
IO_SET;
}
else
{
IO_CLR;
}
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
Addr = Addr >> 1;
}
bsp_DS1302DataInput();
/*输出数据:temp*/
for(i=0; i<8; i++)
{
temp = temp>>1;
if(IO_READ) temp |= 0x80;
else temp&=0x7F;
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
}
RST_CLR; /*停止bsp_DS1302总线*/
bsp_DS1302_DELAY();
bsp_DS1302DataOutput();
return temp;
}
static u8 HexToBCD(u8 code)
{
u8 temp;
temp = ((code / 10)<<4)+(code % 10);
return temp;
}
static void bsp_DS1302_Set(bsp_DS1302_Time_t *pTime)
{
bsp_DS1302_write_byte(BSP_DS1302_CONTROL_ADDR,0x00); //关闭写保护
bsp_DS1302_write_byte(BSP_DS1302_SEC_ADDR,0x80); //暂停
bsp_DS1302_write_byte(BSP_DS1302_YEAR_ADDR, HexToBCD(pTime->Year));
bsp_DS1302_write_byte(BSP_DS1302_MONTH_ADDR, HexToBCD(pTime->Month));
bsp_DS1302_write_byte(BSP_DS1302_DATA_ADDR, HexToBCD(pTime->Day));
bsp_DS1302_write_byte(BSP_DS1302_HOUR_ADDR, HexToBCD(pTime->Hour));
bsp_DS1302_write_byte(BSP_DS1302_MIN_ADDR, HexToBCD(pTime->Minute));
bsp_DS1302_write_byte(BSP_DS1302_SEC_ADDR, HexToBCD(pTime->Second));
bsp_DS1302_write_byte(BSP_DS1302_CONTROL_ADDR,0x80); //打开写保护
}
static void bsp_DS1302_Task(void)
{
u8 RegData;
RegData = bsp_DS1302_read_byte(BSP_DS1302_YEAR_ADDR);
pDS1302->Time.Year = (RegData/16)*10 + RegData%16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_MONTH_ADDR);
pDS1302->Time.Month = (RegData/16)*10 + RegData%16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_DATA_ADDR);
pDS1302->Time.Day = (RegData/16)*10 + RegData%16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_HOUR_ADDR);
pDS1302->Time.Hour = (RegData/16)*10 + RegData%16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_MIN_ADDR);
pDS1302->Time.Minute = (RegData/16)*10 + RegData%16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_SEC_ADDR);
pDS1302->Time.Second = (RegData/16)*10 + RegData%16;
}
static void bsp_DS1302Init(void)
{
RST_SET;
SCK_CLR;
bsp_DS1302_Task();
if((pDS1302->Time.Year>99)||(pDS1302->Time.Month>12)||(pDS1302->Time.Day>31)||
(pDS1302->Time.Hour>23)||(pDS1302->Time.Minute>59)||(pDS1302->Time.Second>59))
{
pDS1302->Time.Year = 25;
pDS1302->Time.Month = 1;
pDS1302->Time.Day = 1;
pDS1302->Time.Hour = 0;
pDS1302->Time.Minute = 0;
pDS1302->Time.Second = 0;
bsp_DS1302_Set(&pDS1302->Time);
}
}
+38
View File
@@ -0,0 +1,38 @@
#ifndef __BSP_DS1302_H__
#define __BSP_DS1302_H__
#include "main.h"
#include "usr_config.h"
#define BSP_DS1302_SEC_ADDR 0x80 //秒数据地址
#define BSP_DS1302_MIN_ADDR 0x82 //分数据地址
#define BSP_DS1302_HOUR_ADDR 0x84 //时数据地址
#define BSP_DS1302_DATA_ADDR 0x86 //日数据地址
#define BSP_DS1302_MONTH_ADDR 0x88 //月数据地址
#define BSP_DS1302_DAY_ADDR 0x8a //星期数据地址
#define BSP_DS1302_YEAR_ADDR 0x8c //年数据地址
#define BSP_DS1302_CONTROL_ADDR 0x8e //控制数据地址
#define BSP_DS1302_CHARGER_ADDR 0x90
#define BSP_DS1302_CLKBURST_ADDR 0xbe
typedef struct
{
u16 Year;
u8 Month;
u8 Day;
u8 Hour;
u8 Minute;
u8 Second;
}bsp_DS1302_Time_t;
typedef struct
{
bsp_DS1302_Time_t Time;
void (*Init)(void);
u8 (*Set)(bsp_DS1302_Time_t *);
void (*Task)(void);
}bsp_DS1302_t;
extern bsp_DS1302_t DS1302;//系统时间
#endif
+808
View File
@@ -0,0 +1,808 @@
/**********************************************************************************
* 文件名 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);/*数据解析*/
}
}
}
}
+322
View File
@@ -0,0 +1,322 @@
#ifndef _W5500_H_
#define _W5500_H_
#include "main.h"
/***************** Common Register *****************/
#define MR 0x0000
#define RST 0x80
#define WOL 0x20
#define PB 0x10
#define PPP 0x08
#define FARP 0x02
#define GAR 0x0001
#define SUBR 0x0005
#define SHAR 0x0009
#define SIPR 0x000f
#define INTLEVEL 0x0013
#define IR 0x0015
#define CONFLICT 0x80
#define UNREACH 0x40
#define PPPOE 0x20
#define MP 0x10
#define IMR 0x0016
#define IM_IR7 0x80
#define IM_IR6 0x40
#define IM_IR5 0x20
#define IM_IR4 0x10
#define SIR 0x0017
#define S7_INT 0x80
#define S6_INT 0x40
#define S5_INT 0x20
#define S4_INT 0x10
#define S3_INT 0x08
#define S2_INT 0x04
#define S1_INT 0x02
#define S0_INT 0x01
#define SIMR 0x0018
#define S7_IMR 0x80
#define S6_IMR 0x40
#define S5_IMR 0x20
#define S4_IMR 0x10
#define S3_IMR 0x08
#define S2_IMR 0x04
#define S1_IMR 0x02
#define S0_IMR 0x01
#define RTR 0x0019
#define RCR 0x001b
#define PTIMER 0x001c
#define PMAGIC 0x001d
#define PHA 0x001e
#define PSID 0x0024
#define PMRU 0x0026
#define UIPR 0x0028
#define UPORT 0x002c
#define PHYCFGR 0x002e
#define RST_PHY 0x80
#define OPMODE 0x40
#define DPX 0x04
#define SPD 0x02
#define LINK 0x01
#define VERR 0x0039
/********************* Socket Register *******************/
#define Sn_MR 0x0000
#define MULTI_MFEN 0x80
#define BCASTB 0x40
#define ND_MC_MMB 0x20
#define UCASTB_MIP6B 0x10
#define MR_CLOSE 0x00
#define MR_TCP 0x01
#define MR_UDP 0x02
#define MR_MACRAW 0x04
#define Sn_CR 0x0001
#define OPEN 0x01
#define LISTEN 0x02
#define CONNECT 0x04
#define DISCON 0x08
#define CLOSE 0x10
#define SEND 0x20
#define SEND_MAC 0x21
#define SEND_KEEP 0x22
#define RECV 0x40
#define Sn_IR 0x0002
#define IR_SEND_OK 0x10
#define IR_TIMEOUT 0x08
#define IR_RECV 0x04
#define IR_DISCON 0x02
#define IR_CON 0x01
#define Sn_SR 0x0003
#define SOCK_CLOSED 0x00
#define SOCK_INIT 0x13
#define SOCK_LISTEN 0x14
#define SOCK_ESTABLISHED 0x17
#define SOCK_CLOSE_WAIT 0x1c
#define SOCK_UDP 0x22
#define SOCK_MACRAW 0x02
#define SOCK_SYNSEND 0x15
#define SOCK_SYNRECV 0x16
#define SOCK_FIN_WAI 0x18
#define SOCK_CLOSING 0x1a
#define SOCK_TIME_WAIT 0x1b
#define SOCK_LAST_ACK 0x1d
#define Sn_PORT 0x0004
#define Sn_DHAR 0x0006
#define Sn_DIPR 0x000c
#define Sn_DPORTR 0x0010
#define Sn_MSSR 0x0012
#define Sn_TOS 0x0015
#define Sn_TTL 0x0016
#define Sn_RXBUF_SIZE 0x001e
#define Sn_TXBUF_SIZE 0x001f
#define Sn_TX_FSR 0x0020
#define Sn_TX_RD 0x0022
#define Sn_TX_WR 0x0024
#define Sn_RX_RSR 0x0026
#define Sn_RX_RD 0x0028
#define Sn_RX_WR 0x002a
#define Sn_IMR 0x002c
#define IMR_SENDOK 0x10
#define IMR_TIMEOUT 0x08
#define IMR_RECV 0x04
#define IMR_DISCON 0x02
#define IMR_CON 0x01
#define Sn_FRAG 0x002d
#define Sn_KPALVTR 0x002f
/*******************************************************************/
/************************ SPI Control Byte *************************/
/*******************************************************************/
/* Operation mode bits */
#define VDM 0x00
#define FDM1 0x01
#define FDM2 0x02
#define FDM4 0x03
/* Read_Write control bit */
#define RWB_READ 0x00
#define RWB_WRITE 0x04
/* Block select bits */
#define COMMON_R 0x00
/* Socket 0 */
#define S0_REG 0x08
#define S0_TX_BUF 0x10
#define S0_RX_BUF 0x18
/* Socket 1 */
#define S1_REG 0x28
#define S1_TX_BUF 0x30
#define S1_RX_BUF 0x38
/* Socket 2 */
#define S2_REG 0x48
#define S2_TX_BUF 0x50
#define S2_RX_BUF 0x58
/* Socket 3 */
#define S3_REG 0x68
#define S3_TX_BUF 0x70
#define S3_RX_BUF 0x78
/* Socket 4 */
#define S4_REG 0x88
#define S4_TX_BUF 0x90
/* Socket 5 */
#define S5_REG 0xa8
#define S5_TX_BUF 0xb0
#define S5_RX_BUF 0xb8
/* Socket 6 */
#define S6_REG 0xc8
#define S6_TX_BUF 0xd0
#define S6_RX_BUF 0xd8
/* Socket 7 */
#define S7_REG 0xe8
#define S7_TX_BUF 0xf0
#define S7_RX_BUF 0xf8
#define TRUE 0xff
#define FALSE 0x00
#define S_RX_SIZE 2048 /*定义Socket接收缓冲区的大小,可以根据W5500_RMSR的设置修改 */
#define S_TX_SIZE 2048 /*定义Socket发送缓冲区的大小,可以根据W5500_TMSR的设置修改 */
/***************----- W5500 GPIO定义 -----***************/
#define W5500_SCS GPIO_PIN_0 // 定义W5500的CS引脚
#define W5500_SCS_PORT GPIOB
#define W5500_RST GPIO_PIN_4 // 定义W5500的RST引脚
#define W5500_RST_PORT GPIOA
#define W5500_INT GPIO_PIN_1 // 定义W5500的INT引脚
#define W5500_INT_PORT GPIOA
///***************----- 网络参数变量定义 -----***************/
//extern u8 Gateway_IP[4]; // 网关IP地址
//extern u8 Sub_Mask[4]; // 子网掩码
//extern u8 Phy_Addr[6]; // 物理地址(MAC)
//extern u8 IP_Addr[4]; // 本机IP地址
//extern u8 S0_Port[2]; // 端口0的端口号(5000)
//extern u8 S0_DIP[4]; // 端口0目的IP地址
//extern u8 S0_DPort[2]; // 端口0目的端口号(6000)
//extern u8 UDP_DIPR[4]; // UDP(广播)模式,目的主机IP地址
//extern u8 UDP_DPORT[2]; // UDP(广播)模式,目的主机端口号
///***************----- 端口的运行模式 -----***************/
//extern u8 S0_Mode; // 端口0的运行模式,0:TCP服务器模式,1:TCP客户端模式,2:UDP(广播)模式
//#define TCP_SERVER 0x00 // TCP服务器模式
//#define TCP_CLIENT 0x01 // TCP客户端模式
//#define UDP_MODE 0x02 // UDP(广播)模式
///***************----- 端口的运行状态 -----***************/
//extern u8 S0_State; // 端口0状态记录,1:端口完成初始化,2端口完成连接(可以正常传输数据)
//#define S_INIT 0x01 // 端口完成初始化
//#define S_CONN 0x02 // 端口完成连接,可以正常传输数据
///***************----- 端口收发数据的状态 -----***************/
//extern u8 S0_Data; // 端口0接收和发送数据的状态,1:端口接收到数据,2:端口发送数据完成
//#define S_RECEIVE 0x01 // 端口接收到一个数据包
//#define S_TRANSMITOK 0x02 // 端口发送一个数据包完成
///***************----- 端口数据缓冲区 -----***************/
//extern u8 Rx_Buffer[2048]; // 端口接收数据缓冲区
//extern u8 Tx_Buffer[2048]; // 端口发送数据缓冲区
//extern u8 W5500_Interrupt; // W5500中断标志(0:无中断,1:有中断)
typedef u8 SOCKET; // 自定义端口号数据类型
// extern void Delay(unsigned int d);//延时函数(ms)
//extern void W5500_GPIO_Configuration(void); // W5500 GPIO初始化配置
//extern void W5500_NVIC_Configuration(void); // W5500 接收引脚中断优先级设置
//extern void SPI_Configuration(void); // W5500 SPI初始化配置(STM32 SPI1)
//extern void W5500_Hardware_Reset(void); // 硬件复位W5500
//extern void W5500_Init(void); // 初始化W5500寄存器函数
//extern u8 Detect_Gateway(void); // 检查网关服务器
//extern void Socket_Init(SOCKET s); // 指定Socket(0~7)初始化
//extern u8 Socket_Connect(SOCKET s); // 设置指定Socket(0~7)为客户端与远程服务器连接
//extern u8 Socket_Listen(SOCKET s); // 设置指定Socket(0~7)作为服务器等待远程主机的连接
//extern u8 Socket_UDP(SOCKET s); // 设置指定Socket(0~7)为UDP模式
//extern u16 Read_SOCK_Data_Buffer(SOCKET s, u8 *dat_ptr); // 指定Socket(0~7)接收数据处理
//extern void Write_SOCK_Data_Buffer(SOCKET s, u8 *dat_ptr, u16 size); // 指定Socket(0~7)发送数据处理
//extern void W5500_Interrupt_Process(void); // W5500中断处理程序框架
#define BSP_W5500_PORT_NUM 1
#define BSP_W5500_DATA_LEN 2048
typedef struct bsp_W5500_Class_t bsp_W5500_Class_t;
struct bsp_W5500_Class_t
{
SOCKET SocketPort;
struct
{
/***************----- 网络参数变量定义 -----***************/
u8 Gateway_IP[4]; /*网关IP地址*/
u8 Sub_Mask[4]; /*子网掩码*/
u8 Phy_Addr[6]; /*物理地址(MAC)*/
u8 IP_Addr[4]; /*本机IP地址*/
u8 Port[2]; /*端口0的端口号(5000) */
u8 DIP[4]; /*端口0目的IP地址*/
u8 DPort[2]; /*端口0目的端口号(6000)*/
u8 UDP_DIPR[4]; /*UDP(广播)模式,目的主机IP地址*/
u8 UDP_DPORT[2]; /*UDP(广播)模式,目的主机端口号*/
}ConfigData;
/***************----- 端口的运行模式 -----***************/
u8 Run_Mode;
/***************----- 端口的运行状态 -----***************/
u8 Run_State;
/***************----- 端口收发数据的状态 -----***********/
u8 TR_Data_State;
/***************----- 端口数据缓冲区 -----***************/
u8 Rx_Buffer[BSP_W5500_DATA_LEN]; // 端口接收数据缓冲区
u8 Tx_Buffer[BSP_W5500_DATA_LEN]; // 端口发送数据缓冲区
u8 Interrupt; // W5500中断标志(0:无中断,1:有中断)
void (*Rx_DataAnalysis)(bsp_W5500_Class_t *,u8 *,u16 );
};
typedef struct
{
u8 Gateway_IP[4]; /*网关IP地址*/
u8 Sub_Mask[4]; /*子网掩码*/
u8 Phy_Addr[6]; /*物理地址(MAC)*/
u8 IP_Addr[4]; /*本机IP地址*/
bsp_W5500_Class_t W5500_Class[BSP_W5500_PORT_NUM]; /*端口成员*/
void (*Interrupt_Process)(void); /*处理进程*/
void (*Init)(void); /*初始化*/
void (*Task)(void); /*任务*/
void (*Socket_Send)(bsp_W5500_Class_t *, u8 *, u16 ); /*端口发送数据*/
}bsp_W5500_t;
extern bsp_W5500_t W5500;
#endif
+241
View File
@@ -0,0 +1,241 @@
#include "bsp_w25q.h"
#include "spi.h"
#include "main.h"
/* spi flash 片选引脚 - pb12 */
#define W25Q32_CS_LOW() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET)
#define W25Q32_CS_HIGH() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET)
/* spi 传输函数 */
static void w25q32_spi_transmit(uint8_t *data, uint16_t size) {
HAL_SPI_Transmit(&hspi2, data, size, HAL_MAX_DELAY);
}
static void w25q32_spi_receive(uint8_t *data, uint16_t size) {
HAL_SPI_Receive(&hspi2, data, size, HAL_MAX_DELAY);
}
static uint8_t w25q32_spi_transmit_receive(uint8_t data) {
uint8_t rx_data;
HAL_SPI_TransmitReceive(&hspi2, &data, &rx_data, 1, HAL_MAX_DELAY);
return rx_data;
}
/* 内部函数声明 */
static void w25q32_init(void);
static void w25q32_read(uint32_t addr, uint8_t *data, uint32_t len);
static void w25q32_write(uint32_t addr, uint8_t *data, uint32_t len);
static void w25q32_chip_erase(void);
static void w25q32_write_enable(void);
static void w25q32_write_disable(void);
static uint8_t w25q32_read_status_reg(void);
static void w25q32_wait_for_write_end(void);
static void w25q32_sector_erase(uint32_t sector_addr);
static void w25q32_block_erase(uint32_t block_addr);
static void w25q32_page_write(uint32_t addr, uint8_t *data, uint16_t len);
static uint8_t w25q32_read_id(void);
static void w25q32_power_down(void);
static void w25q32_wake_up(void);
/* w25q32 对象实例 */
w25q32_t w25q32 = {
.init = w25q32_init,
.read = w25q32_read,
.write = w25q32_write,
.chip_erase = w25q32_chip_erase,
};
/* 初始化函数 */
static void w25q32_init(void) {
W25Q32_CS_HIGH(); /* 初始时片选拉高 */
w25q32_wake_up(); /* 唤醒芯片 */
}
/* 读取芯片id */
static uint8_t w25q32_read_id(void) {
uint8_t id = 0;
uint8_t cmd = W25Q32_JEDEC_ID;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
w25q32_spi_receive(&id, 1); /* 忽略前两个字节 */
w25q32_spi_receive(&id, 1);
w25q32_spi_receive(&id, 1); /* 设备id在第三个字节 */
W25Q32_CS_HIGH();
return id;
}
/* 写使能 */
static void w25q32_write_enable(void) {
uint8_t cmd = W25Q32_WRITE_ENABLE;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
W25Q32_CS_HIGH();
}
/* 写禁止 */
static void w25q32_write_disable(void) {
uint8_t cmd = W25Q32_WRITE_DISABLE;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
W25Q32_CS_HIGH();
}
/* 读取状态寄存器 */
static uint8_t w25q32_read_status_reg(void) {
uint8_t status;
uint8_t cmd = W25Q32_READ_STATUS_REG1;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
status = w25q32_spi_transmit_receive(0x00);
W25Q32_CS_HIGH();
return status;
}
/* 等待写入完成 */
static void w25q32_wait_for_write_end(void) {
while (w25q32_read_status_reg() & W25Q32_STATUS_BUSY) {
/* 可添加延时或看门狗喂狗 */
}
}
/* 扇区擦除 (4kb) */
static void w25q32_sector_erase(uint32_t sector_addr) {
uint8_t cmd[4];
/* 确保地址是4k对齐 */
sector_addr &= ~(W25Q32_SECTOR_SIZE - 1);
w25q32_write_enable();
cmd[0] = W25Q32_SECTOR_ERASE;
cmd[1] = (sector_addr >> 16) & 0xFF;
cmd[2] = (sector_addr >> 8) & 0xFF;
cmd[3] = sector_addr & 0xFF;
W25Q32_CS_LOW();
w25q32_spi_transmit(cmd, 4);
W25Q32_CS_HIGH();
w25q32_wait_for_write_end();
}
/* 块擦除 (64kb) */
static void w25q32_block_erase(uint32_t block_addr) {
uint8_t cmd[4];
/* 确保地址是64k对齐 */
block_addr &= ~(W25Q32_BLOCK_SIZE - 1);
w25q32_write_enable();
cmd[0] = W25Q32_BLOCK_ERASE_64K;
cmd[1] = (block_addr >> 16) & 0xFF;
cmd[2] = (block_addr >> 8) & 0xFF;
cmd[3] = block_addr & 0xFF;
W25Q32_CS_LOW();
w25q32_spi_transmit(cmd, 4);
W25Q32_CS_HIGH();
w25q32_wait_for_write_end();
}
/* 整片擦除 */
static void w25q32_chip_erase(void) {
uint8_t cmd = W25Q32_CHIP_ERASE;
w25q32_write_enable();
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
W25Q32_CS_HIGH();
w25q32_wait_for_write_end();
}
/* 页写入 (最大256字节) */
static void w25q32_page_write(uint32_t addr, uint8_t *data, uint16_t len) {
uint8_t cmd[4];
if (len > W25Q32_PAGE_SIZE) {
len = W25Q32_PAGE_SIZE;
}
w25q32_write_enable();
cmd[0] = W25Q32_PAGE_PROGRAM;
cmd[1] = (addr >> 16) & 0xFF;
cmd[2] = (addr >> 8) & 0xFF;
cmd[3] = addr & 0xFF;
W25Q32_CS_LOW();
w25q32_spi_transmit(cmd, 4);
w25q32_spi_transmit(data, len);
W25Q32_CS_HIGH();
w25q32_wait_for_write_end();
}
/* 任意长度写入 */
static void w25q32_write(uint32_t addr, uint8_t *data, uint32_t len) {
uint32_t page_remaining;
uint32_t offset = 0;
while (len > 0) {
/* 计算当前页剩余字节数 */
page_remaining = W25Q32_PAGE_SIZE - (addr % W25Q32_PAGE_SIZE);
/* 本次写入的长度 */
uint32_t write_len = (len < page_remaining) ? len : page_remaining;
/* 写入一页数据 */
w25q32_page_write(addr, &data[offset], write_len);
/* 更新地址和偏移 */
addr += write_len;
offset += write_len;
len -= write_len;
}
}
/* 读取数据 */
static void w25q32_read(uint32_t addr, uint8_t *data, uint32_t len) {
uint8_t cmd[4];
cmd[0] = W25Q32_READ_DATA;
cmd[1] = (addr >> 16) & 0xFF;
cmd[2] = (addr >> 8) & 0xFF;
cmd[3] = addr & 0xFF;
W25Q32_CS_LOW();
w25q32_spi_transmit(cmd, 4);
w25q32_spi_receive(data, len);
W25Q32_CS_HIGH();
}
/* 进入掉电模式 */
static void w25q32_power_down(void) {
uint8_t cmd = W25Q32_POWER_DOWN;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
W25Q32_CS_HIGH();
}
/* 唤醒芯片 */
static void w25q32_wake_up(void) {
uint8_t cmd = W25Q32_RELEASE_POWER_DOWN;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
W25Q32_CS_HIGH();
HAL_Delay(5); /* 等待芯片唤醒 */
}
+57
View File
@@ -0,0 +1,57 @@
#ifndef __BSP_W25Q_H__
#define __BSP_W25Q_H__
#include "main.h"
#ifdef __cplusplus
extern "C" {
#endif
/* w25q32jvssiq 容量参数 */
#define W25Q32_FLASH_SIZE (0x400000UL) /* 4mb = 32mb */
#define W25Q32_PAGE_SIZE (256) /* 页大小 */
#define W25Q32_SECTOR_SIZE (4096) /* 扇区大小 */
#define W25Q32_BLOCK_SIZE (65536) /* 块大小 */
/* w25q32jvssiq 命令字 */
#define W25Q32_WRITE_ENABLE 0x06
#define W25Q32_WRITE_DISABLE 0x04
#define W25Q32_READ_STATUS_REG1 0x05
#define W25Q32_WRITE_STATUS_REG 0x01
#define W25Q32_READ_DATA 0x03
#define W25Q32_FAST_READ 0x0B
#define W25Q32_PAGE_PROGRAM 0x02
#define W25Q32_SECTOR_ERASE 0x20
#define W25Q32_BLOCK_ERASE_32K 0x52
#define W25Q32_BLOCK_ERASE_64K 0xD8
#define W25Q32_CHIP_ERASE 0xC7
#define W25Q32_POWER_DOWN 0xB9
#define W25Q32_RELEASE_POWER_DOWN 0xAB
#define W25Q32_DEVICE_ID 0xAB
#define W25Q32_MANUFACTURER_ID 0x90
#define W25Q32_JEDEC_ID 0x9F
/* 状态寄存器位 */
#define W25Q32_STATUS_BUSY (1 << 0)
#define W25Q32_STATUS_WRITE_EN (1 << 1)
/* flash 存储区域 */
#define W25Q32_USER_DATA_ADDR 0x000000 /* 用户数据存储起始地址 */
#define W25Q32_USER_DATA_SIZE 0x100000 /* 大约1mb空间用于用户数据 */
/* w25q32 对象结构体 */
typedef struct {
void (*init)(void);
void (*read)(uint32_t addr, uint8_t *data, uint32_t len);
void (*write)(uint32_t addr, uint8_t *data, uint32_t len);
void (*chip_erase)(void);
} w25q32_t;
/* 全局对象 */
extern w25q32_t w25q32;
#ifdef __cplusplus
}
#endif
#endif /* __BSP_W25Q_H__ */