Hi i have following Wiznet W5100 board
and i am interfacing it following STM32 Board using UDP
I am trying to make an Echo server. Whatever data is sent to my chip via W5500 , data is returned back to the PC.
I have a C# program written by myself to send and receive data using UDP socket. I am Monitoring communication by
Wireshark. UDP send from PC is working ok. i can see the data sent in wireshark and data is received without any problem in
my C program. But when i send the data back to the PC, Function SendData is stuck inside while(1) loop
such that Sok_0_INTR_Value is always 0x04. I neither get timeout or send_ok.
Physically there is a direct connection by patch cable between W5500 and my laptop.
and w5500 gateway defined as laptop IP
Thank You
#include<stm32f10x.h>
#include<stm32f10x_gpio.h>
#define BSB_Common_Reg 0b00000 // Block Selection Bits - Common Reg
#define BSB_Sok_0_Reg 0b00001
#define Wiz_CS GPIO_Pin_3 // Port A
#define Wiz_RST GPIO_Pin_2 // Port A
unsigned volatile char DataRecieved = 0 ; // To be changed by Socket Interrupt = Volatile
int main(void)
{
SPI1_setup();
Wiz_Setup_A_INIT();
Wiz_Setup_B_OPEN();
unsigned short RecvCount = 0 ;
unsigned short Count = 0 ;
unsigned char Data[64];
unsigned char SCADAInfo[8];
while(1)
{
GPIO_SetBits(GPIOC, GPIO_Pin_8 | GPIO_Pin_9 );
Delay(1,500); // 500 Mili Sec
GPIO_ResetBits(GPIOC, GPIO_Pin_8 | GPIO_Pin_9 );
Delay(1,500); // 500 Mili Sec
RecvCount = DataRecievedCheck();
if( RecvCount )
{
GetData(Data , &Count ,SCADAInfo); // Recieve Data = Closes Soket in the end
SendData(Data ,Count ); // Send Data = Closes Soket in the end
__disable_irq();
RecvCount = 0 ; // Atomic
__enable_irq();
Wiz_Setup_B_OPEN(); // Wiz UDP = Open-Close Socket every Time. But NOT in Wiz TCP
}
}
return 1 ;
}
void Wiz_Setup_A_INIT(void)
{
unsigned short GAR = 0x0001 ; // Gateway 4 Bytes
unsigned short SUBR = 0x0005 ; // Subnet 4 Bytes
unsigned short SAR = 0x0009 ; // Source Hardware Address MAC - 6 Bytes
unsigned short SIPR = 0x000F ; // IP Address 4 Bytes
unsigned short RCR = 0x001B ; // Retry Count, Retry Attempts = RCR + 1, Set RCR = 2 so Attempts = 3
unsigned short SIMR = 0x0016 ; // Socket Interrupt Mask , Only enable for the Intterupts u would use , SIR = 0X00 = CLEARED BY STM32
// Reset
Delay(1,200); // 200 Mili Sec
GPIO_ResetBits(GPIOA, Wiz_RST);
Delay(1,5); // Reset Time = 1.5 Mili Sec
GPIO_SetBits(GPIOA, Wiz_RST);
Delay(1,2); // 2 mili sec
// Auto Negotionaion = 2 Chips decide their Speed ( 10 / 100 MBPs ) and Duplex ( Sigle / double)
// Link = Up => Auto Negotiation is success
// unsigned short PHYCFGR = 0x002E ;
// unsigned char PHYCFGRValue = 0x00 ; // If PHYCFGRValue && 0x01 = 1 => Link UP
// while( ( PHYCFGRValue & 0x01) != 0 ) // 0Th bit of PHYCFGR Reg = 1
// Wiz_Read_Multi( PHYCFGR , BSB_Common_Reg , &PHYCFGRValue , 1);
// Mode Reg = 0x00 after Reset = ok
unsigned char mac[] = {0x00,0x16,0x36,0xDE,0x58,0xF6};
unsigned char ip[] = {192,168,1,12}; // 0xC0 , 0xA8 , 0x01 , 0x0C
unsigned char subnet[] = {255,255,255,0}; // 255 = 0xFF
unsigned char gate[] = {192,168,1,1};
// Direct connection by patch cable between W5500 and laptop. gateway defined as laptop IP
Wiz_Write_Multi(SAR , BSB_Common_Reg , mac , sizeof(mac));
Wiz_Write_Multi(SIPR , BSB_Common_Reg , ip, sizeof(ip));
Wiz_Write_Multi(SUBR , BSB_Common_Reg , subnet , sizeof(subnet));
Wiz_Write_Multi(GAR , BSB_Common_Reg , gate , sizeof(gate));
unsigned char RCRValue = 0x02 ; // Retry Count = 0x02 + 1 = 3
Wiz_Write_Multi(RCR , BSB_Common_Reg , &RCRValue , sizeof(RCRValue));
// Default RTR Retry Time At Reset = 2000 = 2000 x 0.1 = 200 MiLi Sec = OK
// Default IMR Interrupt Mask Reg = 0x00 = All Desabled = OK
unsigned char SIMRValue = 0x01 ; // Socket Interrupt Mask keep Socket Interrupts Active AS PER PROJECT Needs
Wiz_Write_Multi(SIMR , BSB_Common_Reg , &SIMRValue , sizeof(SIMRValue)); // Only Socket 0 Interrupt = Enable
}
void Wiz_Setup_B_OPEN(void)
{
unsigned short Sok_0_Mod_Reg = 0x0000 ; // Mode Offet Address
unsigned char Sok_0_Mod_Value = 0x02 ; // Sock 0 Mode = 0x22 = UDP
unsigned short Sok_0_Port_Reg = 0x0004 ; // 2 Bytes - Sock 0 Port Offset Address
unsigned char port[] = {0x13,0x88}; // 0x1388 = 5000
unsigned short Sok_0_Comand_Reg = 0x0001 ; //
unsigned char Comand_OPEN = 0x01 ; // Command Reg = 0x01 => Socket OPEN
unsigned char Comand_CLOSE = 0x10 ; // Command Reg = 0x10 => Socket CLOSE
unsigned short Sok_0_Status_Reg = 0x0003 ;
unsigned char Status_Socket = 0x00 ; // => 0x02 = UDP
START: // Label
Wiz_Write_Multi(Sok_0_Mod_Reg , BSB_Sok_0_Reg , &Sok_0_Mod_Value , 1); // Mode = 0x22 = UDP
Wiz_Write_Multi(Sok_0_Port_Reg , BSB_Sok_0_Reg , port , 2 ); // Port = 5000
Wiz_Write_Multi(Sok_0_Comand_Reg , BSB_Sok_0_Reg , &Comand_OPEN , 1 ); // Open Socket
Wiz_Read_Multi(Sok_0_Status_Reg , BSB_Sok_0_Reg , &Status_Socket , 1 ); // Get Socket Status
if(Status_Socket != 0x22 ) // Status Reg = 0x22 => Socket = UDP
{
Wiz_Write_Multi(Sok_0_Comand_Reg , BSB_Sok_0_Reg , &Comand_CLOSE , 1 ); // Close Socket
goto START ;
}
// else socket is opened , Keep looping till Socket is opened
}
unsigned short DataRecievedCheck(void) // Socket Recieve Size Register RSR != 0x0000 .
{
unsigned short Sok_0_RSR_reg = 0x0026 ; // 2 Bytes - Recieved Size
unsigned char RSRValue[] = {0x00,0x00};
Wiz_Read_Multi(Sok_0_RSR_reg , BSB_Sok_0_Reg , RSRValue , 2 );
unsigned short RCVCount = ( RSRValue[0] << 8 ) | RSRValue[1];
return RCVCount ;
}
unsigned char SendData(unsigned char* data , unsigned short count )
{
// UDP MTU = 1472 Deafult
unsigned char BSB_Sok_0_Tx_Buffer = 0b00010;
unsigned short Sok_0_Tx_FreeSize_Reg = 0x0020 ; // 2 bytes
unsigned char Sok_0_Tx_FreeSize_Value[] = {0x00 , 0x00};
unsigned short Sok_0_RemoteIP_Reg = 0x000C ; // 4 bytes
unsigned char Sok_0_RemoteIP_Value[] = {192, 168 , 1 , 8}; // SCADA PC IP
unsigned short Sok_0_RemotePort_Reg = 0x0010 ; // 2 bytes
unsigned char Sok_0_RemotePort_Value[] = {0x13 , 0x89}; // SCADA PC Listening Port 5001 = 0x1389
unsigned short Sok_0_Tx_WritePT_Reg = 0x0024 ; // 2 bytes
unsigned char Sok_0_Tx_WritePT_value[] = {0x00 , 0x00};
unsigned short Sok_0_Comand_Reg = 0x0001 ;
unsigned char Comand_SEND = 0x20 ; // 0x20 => Socket SEND
unsigned char Comand_CLOSE = 0x10 ;
unsigned short Sok_0_INTR_Reg = 0x0002 ;
unsigned char Sok_0_INTR_Value = 0x00 ; // Check which Interrupt occured, Reset by Writing 1
// unsigned short IR_Reg = 0x0015 ; // Chip Level Interrupt Register
// unsigned char IR_Value = 0x00 ;
unsigned short FreeSize = 0 ;
FREESIZE : // Label
Wiz_Read_Multi(Sok_0_Tx_FreeSize_Reg , BSB_Sok_0_Reg , Sok_0_Tx_FreeSize_Value , 2 );
FreeSize = ( Sok_0_Tx_FreeSize_Value[0] << 8 ) | Sok_0_Tx_FreeSize_Value[1];
if( FreeSize < count)
goto FREESIZE ;
Wiz_Write_Multi(Sok_0_RemoteIP_Reg , BSB_Sok_0_Reg , Sok_0_RemoteIP_Value , 4 ); // SCADA IP
Wiz_Write_Multi(Sok_0_RemotePort_Reg , BSB_Sok_0_Reg , Sok_0_RemotePort_Value , 2 ); // SCADA Listening Port
unsigned short dist_ptr = 0 ;
Wiz_Read_Multi(Sok_0_Tx_WritePT_Reg , BSB_Sok_0_Reg , Sok_0_Tx_WritePT_value , 2 );
dist_ptr = ( Sok_0_Tx_WritePT_value[0] << 8 ) | Sok_0_Tx_WritePT_value[1];
Wiz_Write_Multi(dist_ptr , BSB_Sok_0_Tx_Buffer , data , count ); // write Data to Wiz Tx Buffer
dist_ptr += count;
Sok_0_Tx_WritePT_value[0] = dist_ptr >> 8 ; // 0 = MS Byte
Sok_0_Tx_WritePT_value[1] = dist_ptr & 0x00FF ; // 1 = LS Byte
Wiz_Write_Multi(Sok_0_Tx_WritePT_Reg , BSB_Sok_0_Reg , Sok_0_Tx_WritePT_value , 2 );
Wiz_Write_Multi(Sok_0_Comand_Reg , BSB_Sok_0_Reg , &Comand_SEND , 1 ); // SEND
unsigned char success = 0 ;
while(1)
{
Wiz_Read_Multi(Sok_0_INTR_Reg , BSB_Sok_0_Reg , &Sok_0_INTR_Value , 1 ); // read Interrupt Reg
if( (Sok_0_INTR_Value & ( 1 << 4)) != 0 ) // Send Ok
{
success = 1 ; // Break out of While Loop
break;
}
if( (Sok_0_INTR_Value & ( 1 << 3)) != 0 ) // Send Time Out
{
success = 0 ;
break; // Break out of While Loop
}
}
Sok_0_INTR_Value = 0xFF;// IR_n = 1 To Reset INTR
Wiz_Write_Multi(Sok_0_INTR_Reg , BSB_Sok_0_Reg , &Sok_0_INTR_Value , 1 ); // Reset S0_IR = Write 1
Wiz_Write_Multi(Sok_0_Comand_Reg , BSB_Sok_0_Reg , &Comand_CLOSE , 1 ); // CLOSE
return success ;
}
void GetData(unsigned char* data , unsigned short* count , unsigned char* UDPInfoPack) // Socket Recieve Size Register RSR != 0x0000 .
{
unsigned short Sok_0_RD_Point_Reg = 0x0028 ; // 2 bytes
unsigned char Sok_0_RD_Point_value[] = {0x00 , 0x00};
Wiz_Read_Multi(Sok_0_RD_Point_Reg , BSB_Sok_0_Reg , Sok_0_RD_Point_value , 2 );
unsigned short src_ptr = ( Sok_0_RD_Point_value[0] << 8 ) | Sok_0_RD_Point_value[1];
unsigned char BSB_Sok_0_Rx_Buffer = 0b00011;
Wiz_Read_Multi(src_ptr , BSB_Sok_0_Rx_Buffer , UDPInfoPack , 8 );
*count = (*(UDPInfoPack + 6) << 8 ) | (*(UDPInfoPack + 7)) ;
src_ptr += 8;
Wiz_Read_Multi(src_ptr, BSB_Sok_0_Rx_Buffer , data , *count );
// Set Read-pointer of Socket_0
src_ptr += *count ;
src_ptr -= 8 ;
Sok_0_RD_Point_value[0] = src_ptr >> 8 ; // MS Byte
Sok_0_RD_Point_value[1] = src_ptr & 0x00FF ; // LS Byte
Wiz_Write_Multi(Sok_0_RD_Point_Reg , BSB_Sok_0_Reg , Sok_0_RD_Point_value , 2 );
// Set Command Recieve
unsigned short Sok_0_Comand_Reg = 0x0001 ;
unsigned char Comand_RECV = 0x04 ; // Command Reg = 0x01 => Socket RECV
Wiz_Write_Multi(Sok_0_Comand_Reg , BSB_Sok_0_Reg , &Comand_RECV , 1 ); // Command = RECV
// Reset Interrupts - Clearing S0_IR (writing 1) also clears SIR_0
// unsigned short Sok_0_IR_Reg = 0x0002 ; // Sock 0 Interrupt Reg
// unsigned char Sok_0_IR_Value = 0x1F ; // Write 1 to Clear Interupt
// Wiz_Write_Multi(Sok_0_IR_Reg , BSB_Sok_0_Reg , &Sok_0_IR_Value , 1);
// Close Socket, it Rsets Rx buffer pointer
unsigned char Comand_CLOSE = 0x10 ; // Command Reg = 0x10 => Socket CLOSE
Wiz_Write_Multi(Sok_0_Comand_Reg , BSB_Sok_0_Reg , &Comand_CLOSE , 1 ); // Close Socket
}
void Wiz_Write_Multi( unsigned short address , unsigned char BSB , unsigned char* bytes , unsigned short count )
{
unsigned char control = ( BSB << 3 ) | 0x04 ; // BSB_RW_OM
// BSB 5 Bits, R/W bit W = 1 R = 0, OM 2 Bits = 00 = VDM = Chip Slect is NOT ground
unsigned short x = 0 ;
GPIO_ResetBits(GPIOA, Wiz_CS);
Delay(0,15);
SPI_SendBye(address >> 8); // Offset Address High Byte
SPI_SendBye(address & 0x00FF); // Offset Address Low Byte
SPI_SendBye(control); // VDM
for( x = 0 ; x < count ; x++ ) // Send Data
SPI_SendBye(*bytes++); // * has precedence over ++
Delay(0,15);
GPIO_SetBits(GPIOA, Wiz_CS);
Delay(0,15);
}
void Wiz_Read_Multi( unsigned short address , unsigned char BSB , unsigned char* data , unsigned short count)
{
unsigned char control = BSB << 3 ; // BSB_RW_OM => R/W = 0 , OM = 00
// BSB 5 Bits, R/W bit W = 1 R = 0, OM 2 Bits = 00 = VDM = Chip Slect is NOT ground
unsigned short x = 0 ;
GPIO_ResetBits(GPIOA, Wiz_CS);
Delay(0,15);
SPI_SendBye(address >> 8); // Offset Address High Byte
SPI_SendBye(address & 0x00FF); // Offset Address Low Byte
SPI_SendBye(control); // VDM - Read
for( x = 0 ; x < count ; x++ ) // Read Data
*data++ = SPI_ReadByte(); // * has precedence over ++
Delay(0,15);
GPIO_SetBits(GPIOA, Wiz_CS);
Delay(0,15);
// In C Array cant be returned , so pass an array by REFERENCE and fill it
}
void SPI_SendBye(unsigned char byte)
{
while ( SPI_I2S_GetFlagStatus(SPI1 , SPI_I2S_FLAG_TXE) == RESET ); // sending data Wait
SPI_I2S_SendData(SPI1 , byte);
while ( SPI_I2S_GetFlagStatus(SPI1 , SPI_I2S_FLAG_RXNE) == RESET ); // Wait for data
byte = SPI_I2S_ReceiveData(SPI1); // Dummy read to generate clock
}
unsigned char SPI_ReadByte(void)
{
while ( SPI_I2S_GetFlagStatus(SPI1 , SPI_I2S_FLAG_TXE) == RESET );
SPI_I2S_SendData(SPI1 , 0xff); // Dummy write to generate clock
while ( SPI_I2S_GetFlagStatus(SPI1 , SPI_I2S_FLAG_RXNE) == RESET );
return (unsigned char)SPI_I2S_ReceiveData(SPI1);
}
void SPI1_setup(void)
{
// Enable clock for SPI1 AFIO GPIOA GPIOB
RCC->APB2ENR |= ( 1<<12 ) | ( 1<<0 ) | ( 1<<2 ) | ( 1<<3 );
// PA 3 = CS PA 2 = RST
GPIO_InitTypeDef GpioPin;
GpioPin.GPIO_Pin = Wiz_CS | Wiz_RST ;
GpioPin.GPIO_Speed = GPIO_Speed_2MHz;
GpioPin.GPIO_Mode = GPIO_Mode_Out_PP ; // CS = DO = Out Push Pull
GPIO_Init(GPIOA, &GpioPin);
GPIO_SetBits(GPIOA, Wiz_CS | Wiz_RST ); // CS + RST = High
// SCK = PA5 = Alternate Push Pull 10 MHz
// MISO = PA6 = Input pull up
// MOSI = PA7 = Alternate Push Pull 10 MHz
GpioPin.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7 ; // Clock + MOSI
GpioPin.GPIO_Speed = GPIO_Speed_10MHz;
GpioPin.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GpioPin);
// Few example say MOSI is Alternate Push Pull
GpioPin.GPIO_Pin = GPIO_Pin_6 ;
GpioPin.GPIO_Mode = GPIO_Mode_IPU; // Input Pull Up
GPIO_Init(GPIOA, &GpioPin); // Clock + MOSI
SPI_InitTypeDef MySPI;
MySPI.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
MySPI.SPI_Mode = SPI_Mode_Master;
MySPI.SPI_DataSize = SPI_DataSize_8b;
MySPI.SPI_CPOL = SPI_CPOL_Low; // Mode 0
MySPI.SPI_CPHA = SPI_CPHA_1Edge; // Mode 0
MySPI.SPI_NSS = SPI_NSS_Soft; // CS handles by Software
MySPI.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2 ; // 24 / 2 = 12 MHz < 33.3 MHz
MySPI.SPI_CRCPolynomial = 7;
SPI_Init(SPI1 , &MySPI);
SPI_Cmd(SPI1 , ENABLE);
}