W5500 UDP Recieve Working but SEND not working

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);
    }

This situation may happen in the following circumstances:

  • you do not give SEND command to the W5500;
  • you have data size set to 0 (so there’s nothing to send);
  • W5500 does not know where (or how) to send. To be able to send it must know DHAR of the remote device, there should be valid port set. Does W5500 get responses (from laptop) for its ARP request packets?
1 Like

Thanks for quick repply, i managed to solve the issue
I get PING reply from W5500. i was making 3 mistakes

(1) i was sending data on a UDP socket which was not open , and after this Polling methd recieve and transmit started to work as expected

    GetData(Data , &Count ,SCADAInfo);  
    Wiz_Setup_B_OPEN();  // This Line was missing
    SendData(Data ,Count );            
    Wiz_Setup_B_OPEN();  

later i wanted to use interrupt which was not working but i found out following error
(2) correected SIMR = 0x0018. it was previously set to 0x0016

Now Interrupt would keep firing Endlessly. Send would fire Send_Ok interrupt which would set my volatile DataRecieved = 1 so SendData function was executed endlessly
To fix this , i disabled all interrupts at start of SendData function and enabled only Socket_0 interrupt in the end
(3)

        unsigned short SIMR = 0x0018;
    	unsigned char SIMRValueDisable = 0x00 ;  // Disable All Wiz Interrupt
    	unsigned char SIMRValueEnable0 = 0x01 ;  // Enable Interrupt 0 Wiz Interrupt
    	Wiz_Write_Multi(SIMR  , BSB_Common_Reg , &SIMRValueDisable , 1); // Disable Interrupt

Now things are working as expected
Thanks for your reply
Here is the complete UDP working code both by polling and interrupt on stm32F100RB and Wiznet W5500

    #include<stm32f10x.h>
    #include<stm32f10x_gpio.h>
    #include<stm32f10x_rcc.h>
    #include<stm32f10x_usart.h>
    #include<stm32f10x_tim.h>
    #include<stm32f10x_spi.h>
    #include<stm32f10x_exti.h>
    #include<misc.h>

    void Wiz_Write_Multi( unsigned short , unsigned char , unsigned char * , unsigned short ) ; // , , Pointer , Array Count
    void Wiz_Read_Multi( unsigned short , unsigned char , unsigned char *, unsigned short ) ;   // , , Pointer , Array Count
    void LEDSetup(void);
    void SPI1_setup(void);
    void SPI_SendBye(unsigned char);
    unsigned char SPI_ReadByte();
    void Tim2_init(unsigned char);
    void Delay( unsigned char , unsigned short); // 0 = Micro , 1 = Mili
    void Wiz_Setup_A_INIT(void);
    void Wiz_Setup_B_OPEN(void);
    void ExtInterruptLineConfig(void) ;
    void GetData(unsigned char* , unsigned short* , unsigned char*);
    unsigned char SendData(unsigned char* , unsigned short);
    unsigned short DataRecievedCheck(void);

    #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
    //			__disable_irq();RecvCount = 0 ;  // Atomic  __enable_irq();
    unsigned volatile char DataRecieved = 0 ; // To be changed by Socket Interrupt = Volatile
    int main(void)
    {
    	LEDSetup();
    	SPI1_setup();
    	ExtInterruptLineConfig();
    	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);
    		GPIO_ResetBits(GPIOC, GPIO_Pin_8 | GPIO_Pin_9 );
    		Delay(1,500);
    		// RecvCount = DataRecievedCheck();  // if( RecvCount ) Polling
    		if( DataRecieved ) // Interrupt
    		{
    			DataRecieved = 0 ;
    			GetData(Data , &Count ,SCADAInfo);  // Recieve Data = Closes Soket in the end
    			Wiz_Setup_B_OPEN();
    			SendData(Data ,Count );             // Send Data = Closes Soket in the end
    			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 = 0x0018 ;  // Socket Interrupt Mask , Only enable for the Intterupts u would use , SIR = 0X00 = CLEARED BY STM32

    	// Reset
    	Delay(1,200);
    	GPIO_ResetBits(GPIOA, Wiz_RST);
    	Delay(1,5); // Reset Time = 1.5 Mili Sec
    	GPIO_SetBits(GPIOA, Wiz_RST);
    	Delay(1,2);

    	// 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,8}; // My Own laptop
    	// 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 )
    {
    	// Disable Interrupt during send, else Sending data will fire Send_OK or Time Out Interrupt
    	// which will make volatile DataRecieved = 1 so senddata will run again........making it Infinite Loop
    	// After send is complete , SIMR = 0x01 = Data Recieved interrupt will fire
    	unsigned short SIMR = 0x0018;
    	unsigned char SIMRValueDisable = 0x00 ;  // Disable All Wiz Interrupt
    	unsigned char SIMRValueEnable0 = 0x01 ;  // Enable Interrupt 0 Wiz Interrupt
    	Wiz_Write_Multi(SIMR  , BSB_Common_Reg , &SIMRValueDisable , 1); // Disable Interrupt


    	// 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 = 0x1F;// 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

    	// Enable only All Interrupt
    	Wiz_Write_Multi(SIMR  , BSB_Common_Reg , &SIMRValueEnable0 , 1); // Disable Interrupt
    	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);
    }

    // Tim 2 = General Purpose , CNT ARR PSC = 16 Bit in STM32F100RB.
    void Tim2_init(unsigned char base) // base = 0 = Micro , base = 1 Mili
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    	TIM_TimeBaseInitTypeDef TIM;
    	TIM_TimeBaseStructInit(&TIM);
    	if(base)
    		TIM.TIM_Prescaler = (SystemCoreClock/1000)-1;    // 10 CNT = 1 Mili Sec
    	else
    		TIM.TIM_Prescaler = (SystemCoreClock/1000000)-1; // 1 CNT = 1 Micro Sec
    	TIM.TIM_Period = 0xFFFF - 1 ; // ARR 32 Bits
    	TIM.TIM_ClockDivision = 0;
    	TIM.TIM_CounterMode = TIM_CounterMode_Up;
    	TIM_TimeBaseInit(TIM2,&TIM);
    	TIM2->CNT = 0 ; // Reset
    	TIM_Cmd(TIM2,ENABLE); // Timer Start
    	// STM32F100RB Tim CLK = SystemCoreClock
    	// STM32F4 Tim CLK = SystemCoreClock / 2
    }

    void Delay( unsigned char base , unsigned short Ticks) // 0 = Micro , 1 = Mili
    {
    	Tim2_init(base); // Reset during Init
    	volatile unsigned short start = TIM2->CNT;
    	while((TIM2->CNT - start) <= Ticks);
    	// Stop timer
    	TIM_Cmd(TIM2,DISABLE);
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,DISABLE); // Power Save
    }

    void LEDSetup(void)
    {
    	RCC->APB2ENR |= ( 1 << 4 );
    	GPIO_InitTypeDef GpioPin;
    	GpioPin.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 ;
    	GpioPin.GPIO_Speed = GPIO_Speed_10MHz;
    	GpioPin.GPIO_Mode = GPIO_Mode_Out_PP ;
    	GPIO_Init(GPIOC, &GpioPin);
    }

    void ExtInterruptLineConfig(void)
    {
    	RCC->APB2ENR |= (1<<4) | (1<<0) ; // AFIO is must for EXTI
    	GPIO_InitTypeDef GPIO_InitStruct;
    	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 ;
    	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
    	GPIO_Init(GPIOC, &GPIO_InitStruct);

    	EXTI_InitTypeDef EXTI_InitStruct;
    	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource0); // Port Source = GPIOC
    	EXTI_InitStruct.EXTI_Line = EXTI_Line0 ;  // EXTI_Line0 = PA0 PB0 PC0 PD0 ....
    	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; // So EXTI_Line0 = PC0
    	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; // Falling Edge
    	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
    	EXTI_Init(&EXTI_InitStruct);

    	NVIC_InitTypeDef NVIC_InitStruct;
    	NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; // EXTI0_IRQn = EXTI_Line0
    	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x0F; // lowest priority
    	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x0F; // lowest subpriority
    	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    	NVIC_Init(&NVIC_InitStruct);
    	// NVIC_EnableIRQ(EXTI0_IRQn);
    }
    void EXTI0_IRQHandler(void)  // Data Recieved
    {
    	if(EXTI_GetITStatus(EXTI_Line0) != RESET)
    		DataRecieved = 1 ;
    	EXTI_ClearITPendingBit(EXTI_Line0); // Must
    }
2 Likes