W5300是一款带有硬件协议栈的网络芯片,内部拥有128K的缓存,最大支持8路socket通信,与MCU之间通过16位数据总线通信,通信速度远超W5500之类以SPI作为通信接口的网络芯片,特别适合对高速网络传输有需求的应用。
本次使用STM32F205ZET6作为主控MCU,通过FSMC接口与W5300连接,主机在完成配置后,就可以像访问SRAM一样轻松操作W5300。以下为W5300引脚介绍及参考电路
除FSMC接口外,还需要额外的芯片复位脚和中断脚。芯片上电复位不太可靠,因此一般需要通过操作复位引脚来进行可靠复位,这个特性在W5500上也有,需要注意。中断脚的话不是必须的,也可以通过查询方式来获取中断信息,但这里我们还是使用了。
除此以外,硬件上还有一些配置,可以对照上面的电路图
硬件连接没有问题后就开始软件编程了,首先是初始化。初始化这部分分两块,一个是对于FSMC的引脚初始化,另一部分是对于芯片的初始化。
FSMC初始化(在这里不包括复位和中断脚的初始化,这两个脚可以使用普通IO,而FSMC的引脚是固定的),根据接线不同,FSMC_NORSRAMInitStructure.FSMC_Bank和FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth参数也不同,具体的可以查看STM32的手册。
void Config_FSMC(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
FSMC_NORSRAMTimingInitTypeDef p;
FSMC_NORSRAMDeInit(FSMC_Bank1_NORSRAM1);
/* AHB3 Peripheral Clock configuration -------------------------------------*/
/* FSMC clock enable */
RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC , ENABLE);
/* Enable GPIOs clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOF |
RCC_AHB1Periph_GPIOG, ENABLE);
/*-- GPIOs Configuration -----------------------------------------------------*/
/*
+-------------------+--------------------+------------------+------------------+
| PD0 <-> FSMC_D2 | PE0 <-> FSMC_NBL0 | PF0 <-> FSMC_A0 | PG0 <-> FSMC_A10 |
| PD1 <-> FSMC_D3 | PE1 <-> FSMC_NBL1 | PF1 <-> FSMC_A1 | PG1 <-> FSMC_A11 |
| PD4 <-> FSMC_NOE | PE2 <-> FSMC_A23 | PF2 <-> FSMC_A2 | PG2 <-> FSMC_A12 |
| PD5 <-> FSMC_NWE | PE3 <-> FSMC_A19 | PF3 <-> FSMC_A3 | PG3 <-> FSMC_A13 |
| PD8 <-> FSMC_D13 | PE4 <-> FSMC_A20 | PF4 <-> FSMC_A4 | PG4 <-> FSMC_A14 |
| PD9 <-> FSMC_D14 | PE5 <-> FSMC_A21 | PF5 <-> FSMC_A5 | PG5 <-> FSMC_A15 |
| PD10 <-> FSMC_D15 | PE6 <-> FSMC_A22 | PF12 <-> FSMC_A6 | PG9 <-> FSMC_NE2 |
| PD11 <-> FSMC_A16 | PE7 <-> FSMC_D4 | PF13 <-> FSMC_A7 |------------------+
| PD12 <-> FSMC_A17 | PE8 <-> FSMC_D5 | PF14 <-> FSMC_A8 |
| PD13 <-> FSMC_A18 | PE9 <-> FSMC_D6 | PF15 <-> FSMC_A9 |
| PD14 <-> FSMC_D0 | PE10 <-> FSMC_D7 |------------------+
| PD15 <-> FSMC_D1 | PE11 <-> FSMC_D8 |
+-------------------| PE12 <-> FSMC_D9 |
| PE13 <-> FSMC_D10 |
| PE14 <-> FSMC_D11 |
| PE15 <-> FSMC_D12 |
+--------------------+
*/
/* GPIOD configuration */
GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_FSMC);
//GPIO_PinAFConfig(GPIOD, GPIO_PinSource11, GPIO_AF_FSMC);
//GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_FSMC);
//GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_FSMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 |
GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14 |
GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD, &GPIO_InitStructure);
/* GPIOE configuration */
//GPIO_PinAFConfig(GPIOE, GPIO_PinSource0 , GPIO_AF_FSMC);
//GPIO_PinAFConfig(GPIOE, GPIO_PinSource1 , GPIO_AF_FSMC);
//GPIO_PinAFConfig(GPIOE, GPIO_PinSource2 , GPIO_AF_FSMC);
//GPIO_PinAFConfig(GPIOE, GPIO_PinSource3 , GPIO_AF_FSMC);
//GPIO_PinAFConfig(GPIOE, GPIO_PinSource4 , GPIO_AF_FSMC);
//GPIO_PinAFConfig(GPIOE, GPIO_PinSource5 , GPIO_AF_FSMC);
//GPIO_PinAFConfig(GPIOE, GPIO_PinSource6 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource7 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource8 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource9 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource10 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource11 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource12 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource13 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource14 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource15 , GPIO_AF_FSMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 |
GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 |
GPIO_Pin_15;
GPIO_Init(GPIOE, &GPIO_InitStructure);
/* GPIOF configuration */
GPIO_PinAFConfig(GPIOF, GPIO_PinSource0 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource1 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource2 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource3 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource4 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource5 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource12 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource13 , GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource14 , GPIO_AF_FSMC);
//GPIO_PinAFConfig(GPIOF, GPIO_PinSource15 , GPIO_AF_FSMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 |
GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_12 | GPIO_Pin_13 |
GPIO_Pin_14 ;
GPIO_Init(GPIOF, &GPIO_InitStructure);
//-- FSMC Configuration ------------------------------------------------------
p.FSMC_AddressSetupTime = 0;
p.FSMC_AddressHoldTime = 0;
p.FSMC_DataSetupTime = 5; //2
p.FSMC_BusTurnAroundDuration = 1; //0
p.FSMC_CLKDivision = 0;
p.FSMC_DataLatency = 0;
p.FSMC_AccessMode = FSMC_AccessMode_A;
FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM1;
FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM;
FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
//FSMC_NORSRAMInitStructure.FSMC_AsyncWait = FSMC_AsyncWait_Disable; //
FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;
FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;
FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;
FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);
/* Enable FSMC Bank1_SRAM Bank */
FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE);
}
接下来就是对于芯片的初始化,前面说过对于芯片的访问如同SRAM一样,具体到W5300上,就是寄存器地址好比SRAM存储地址,操作寄存器就是往不同的地址写数据。W5300的寄存器地址都是厂商给定的相对地址,而基地址则跟FSMC接线有关。
W5300的寄存器分为模式寄存器,间接模式寄存器,通用寄存器和SOCKET寄存器。不同的寄存器分管不同的功能,具体的可以查阅官方手册,这里不作列举了。
W5300的初始化分为3个步骤
- 设置主机接口(数据总线宽度,接口模式,时序)
- 设置网络信息(MAC,本地IP,网关,子网掩码,重发间隔次数等)
- 分配SOCKET内部TX/RX存储空间
示例代码如下
u8 W5300_Init(void)
{
u16 i;
u16 Tsum=0,Rsum=0;
u16 val;
u8 rMac[6];
vdTimeDelay(0x00800000);
// 设置主机接口:8位/直接访问
_SetMR(MR_RST);
vdTimeDelay(0x02000000);
//setMR(getMR()|MR_FS);
// 设置主机中断:IP冲突 | 目标端口无法到达 // | Socket0~3
_SetIMR(IR_IPCF | IR_DPUR | 0x03);//
// 设置网络参数
_SetSHAR((u8 *)&(SysInfo.bMAC[0]));
_SetGAR((u8 *)&(SysInfo.bGW[0]));
_SetSUBR((u8 *)&(SysInfo.bSUB[0]));
_SetSIPR((u8 *)&(SysInfo.bIP[0]));
_GetSHAR((u8 *)rMac);
for(i = 0;i<6;i++)
{
if(SysInfo.bMAC[i] != rMac[i]) break;
}
if(i < 6) return 0;
// 配置重复发送超时周期的值,RTR的标准单位是 100us
_SetRTR(2000);
// 配置重复发送的次数。当重复发送的次数达到 RCR+1时,将产生超时中断(Sn_IR 的TIMEOUT?位置1)
_SetRCR(7);
// 分配Socket内存
for(i=0; i < MAX_SOCKET_NUM; i++)
{
if(TxMemSize[i] > 64) return 0;
if(RxMemSize[i] > 64) return 0;
Tsum += (u16)TxMemSize[i];
Rsum += (u16)RxMemSize[i];
dwTMSsum[i] = ((u32)TxMemSize[i]) << 10;
dwRMSsum[i] = ((u32)RxMemSize[i]) << 10;
}
if( (Tsum % 8) || ((Tsum + Rsum) != 128)) return 0;
for(i = 0;i<8;i++)
{
_SetTMSR(i,TxMemSize[i]);
_SetRMSR(i,RxMemSize[i]);
}
val = 0;
for(i=0; i < Tsum/8; i++)
{
val <<= 1;
val |= 1;
}
_SetMTYPER(val);
return 1;
}
之后就可以根据实际应用进行socket编程了,根据配置选择TCP或UDP通信等,每个socket可以独立配置互不影响。
当网络接收到数据时,触发中断,通过读取IR寄存器获知中断类型,然后进相应的处理函数去处理。
void ISR_W5300(void)
{
u16 wPendInt;
// Close Global Interrupt
wPendInt = _GetIR();
// IP地址冲突
if(wPendInt & IR_IPCF) // check the IP conflict interrupt
{
_SetIR(IR_IPCF);
}
// 目标IP无法到达
if(wPendInt & IR_DPUR) // check the unreachable destination interrupt
{
_SetIR(IR_DPUR);
}
if (wPendInt & 0x0001) ISR_Socket0();
if (wPendInt & 0x0002) ISR_Socket1();
if (wPendInt & 0x0004) ISR_Socket2();
// Open Global Interrupt
}
如果要进行发送,则操作相应的SOCKET寄存器即可
void _WrSxBuffer(u8 Sx,u8* buf,u32 len)
{
u32 z,tLen;
pSOCKET Sn;
Sn = (pSOCKET)(SOCKET0_BASE + SOCKET_REG_SIZE * Sx);
tLen = len + (len & 0x01);
for(z = 0; z < tLen; z += 2)
{
Sn->TX_FIFOR = (u16)(*(buf + z)<< 8) | (u16)(*(buf+z+1));
}
}
代码太多不便展示,具体可参考
https://download.csdn.net/download/u011436603/88902967?spm=1001.2014.3001.5503