SNTP issue when NTP server is temporarily unavailable


I have a small problem with SNTP and I could not find any trace of the source of that problem.
I use W5500 with ATmega128p and I use the Windows time service as the NTP server to test my code.

I have been able to initialize the SNTP and update time periodically from the local server with no problems as examples show. Now, I want to test a case as if the NTP server is unavailable temporarily. So, I stop the windows service to simulate this for a while, and when start it back W5500 can not communicate with the server even if it is available.

If I reset the MCU , it reads NTP correctly, but when stop/restart the service it can not communicate with server again.

By looking at Wireshark:

  • When the NTP server is running, I see packets for NTP protocol (as expected)
  • When the NTP server is stopped, I see captured packet for ICMP error -port unreachable (as expected)
  • But when the NTP server is available again, the server does not receive any request from W5500 at all, despite the SNTP_run() is running and returns 0.
  • If I reset the MCU and W5500 , SNTP works again as expected.

It seems that there is variable updated when the server is unavailable but not updated back when the server is available.
I tried to go through sntp.c for the past two days but frankly I was lost. Can any one assist in identifying the problem?

Thank you

We need your code under consideration and link to libraries you use.

Here I am attaching the code. I use the original files in ioLibrary_Driver.

Also, I am attaching snapshots for the two scenarios (When server run 1-continously and When 2-Run/Stop/Run)

 * W5500-HTML-Again.c
 * Created: 16/9/2022 1:47:41 AM
 * Author : Zedan

/*********************** Include Files ************************/
#include <avr/io.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define  F_CPU 16000000UL
#include <util/delay.h>
#include <avr/interrupt.h>
#include "m1284p/USART.h"
#include "m1284p/SPI.h"
#include "m1284p/I2C_Master.h"
#include "Ethernet\W5500\w5500.h"
//#include "Ethernet\socket.h"
#include "Internet/DNS/dns.h"
#include "Internet/SNTP/sntp.h"

static FILE mystdout = FDEV_SETUP_STREAM(UART_SendChar_io, NULL, _FDEV_SETUP_WRITE);  //To be used for redirecting printf to UART

uint32_t SysUpTime=0;
uint8_t MinuteFlag=0;
volatile uint8_t CntOF=0; 
uint8_t i=0;

// define default static IP address (when DHCP selected & failed)
wiz_NetInfo netInfo = {
	.mac  = {0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}, // Mac address- we will read it from external EEPROM
	.ip   = {10, 0, 0, 100}, // Default IP address
	.sn   = {255, 0, 0, 0}, // Default Subnet mask
	.dns =  {10, 0, 0, 102},		// Default DNS address
	.gw   = {10, 0, 0, 102},       // Default Gateway address
};    //Dynamic IP configuration

uint8_t DNS_2nd[4] = {0, 0, 0, 0}; // Default Secondary DNS server IP.

uint8_t bufSize[] = {2, 2, 2, 2};  // Tx/RX buffer sizes for w5500
#define SOCK_DHCP    0   //Specify the socket used for DHCP communication
#define DATA_BUF_SIZE_DHCP   550

//****  DNS Variables
#define SOCK_DNS	6
#define ETH_MAX_BUF_SIZE	2048

uint8_t Domain_name[] = "ntp.home";;
uint8_t Domain_IP[4]  = {0, };  // Translated IP address by DNS Server
int8_t DNSret;

//****  SNTP Variables
#define SOCK_SNTP       7
const uint8_t SNTP_TIMEZONE = 26;  // (26) UTC+02:00 - Egypt (look at sntp.c)
datetime time;

void print_network_information(void);
void cs_sel() {W5500_Select();}    //to register SPI chip select function
void cs_desel() {W5500_DeSelect();}  //to register SPI chip de-select function

uint8_t spi_rb(void) {return SPI_SndByte(0);}  //to register SPI reading one byte
void spi_wb(uint8_t b) {SPI_SndByte(b);}  //to register SPI sending one byte

int main(void)
	stdout = &mystdout;  //To Enable redirect printf to UART
	//****** HW initialization
	sei();  //Enable global interrupt bit
	DDRD=(1<<PIND7)|(1<<PIND6)|(1<<PIND5)|(1<<PIND4);  //PINs output direction (for relays)
	DDRC&=~(1<<PINC0); //Input Pin for Internal Temperature Sensor DS18B20
	SPI_MasterInit();  //SPI Initialization (Master)
	_delay_ms(10000);  //To avoid problem of W5500 with UART.  Connect UART (physically) after few seconds of power-on
	UART_Init(19200);  //UART Initialization
	I2C_Master_Init();	//Initialize I2C as master
	TCCR0A&= ~(1<<WGM00); TCCR0A&=~(1<<WGM01); TCCR0A&=~(1<<WGM02);  //Counter0 Normal Mode (overflow) - default value
	TCCR0B= (1<<CS00)|(1<<CS02); TCCR0B &=~(1<<CS01);  //Counter0 Prescaler 1024
	TIMSK0|=(1<<TOIE0); //Counter0 Overflow Interrupt Enable
	TCNT0=0;  //Preload the counter (see my notes page 73)

	//wizphy_reset();  //Reset PHY
	//setMR(MR_RST);  //Reset W5500
	//wizchip_sw_reset();  //Reset W5500, retain basic network info
	reg_wizchip_cs_cbfunc(cs_sel, cs_desel);  //Register SPI ChipSelect function for W5500
	reg_wizchip_spi_cbfunc(spi_rb, spi_wb);  //Register SPI Read/Write functions for W5500
	wizchip_init(bufSize, bufSize);  //Initialize W5500 and set buffer sizes
	//setSHAR(netInfo.mac);   //Or use wizchip_setnetinfo(&netInfo); to write all network values
	wizchip_setnetinfo(&netInfo); //Set network information to W5500
	DNS_init(SOCK_DNS, gDATABUF_DNS);   // DNS client Initialization

	/* DNS processing */
	if ((DNSret = DNS_run(netInfo.dns, Domain_name, Domain_IP))==1)  //Trying 1st DNS server
		printf("\n\r> DNS1 for %s return= %d", Domain_name, DNSret);
		printf("\n\r> Translated %s to [%d.%d.%d.%d]\r\n\r\n",Domain_name,Domain_IP[0],Domain_IP[1],Domain_IP[2],Domain_IP[3]);
	else if ((DNSret = DNS_run(DNS_2nd, Domain_name, Domain_IP))==1) //Trying 2st DNS server
		printf("\n\r> 1st DNS Failed, trying DNS2");
		printf("\n\r> DNS2 for %s return= %d", Domain_name, DNSret);
		printf("\n\r> Translated %s to [%d.%d.%d.%d]\r\n\r\n",Domain_name,Domain_IP[0],Domain_IP[1],Domain_IP[2],Domain_IP[3]);
	else {printf("\n\r> Error resolving %s - DNS Failed !!\n\r\n\r", Domain_name);}  //Query to both servers failed
	if(DNSret > 0)  // sntp server ip resolved, so init SNTP client
		printf("\n\r> Initializing SNTP from %s", Domain_name);
	else {printf("\n\r> SNTP Error!! could not resolve %s", Domain_name); ;}	
    while (1) 
		if (CntOF>61)   //Means 1sec elapsed
				CntOF=0;  //Reset Counter0 OverFlows counter
		if (SysUpTime%60==0)  //Means 1 min elapsed
				if (MinuteFlag==0)
				//>>>>> code to be executed every 1 min
					printf("\n\r\n\r> System is up for %lu minutes\n\r",SysUpTime/60);  
					printf("\n\r> Updating Time from Network");
					while (SNTP_run(&time) != 1)  //Query SNTP time
						if (i>10) break; //Timed-out
					if (i<10)
						printf("\n\r> %02d/%02d/%d, %02d:%02d:%02d", time.dd,, time.yy, time.hh,,;
							printf("\n\r> Error updating time from network");
				//>>>>> End of code to be executed every 1 min
			} else MinuteFlag=0;


/******************* Timer0 overflowinterrupt ********************/
	CntOF ++; //count overflows
	//if(CntOF>61) {CntOF=0; SysUpTime++;}  <- This makes DHCP not renewing lease

void print_network_information(void)
	//uint8_t tmpstr[6] = {0,};
	//ctlwizchip(CW_GET_ID,(void*)tmpstr); // Get WIZCHIP name
	//printf(" WIZnet chip:  %s \r\n", tmpstr);

	wiz_NetInfo gWIZNETINFO;
	if (gWIZNETINFO.dhcp == NETINFO_STATIC) {UART_SendString("\n\rStatic IP address Assigned:\r\n");}
	else {UART_SendString("\n\rDHCP IP address Assigned:\r\n");}
	printf("MAC Address : %02x:%02x:%02x:%02x:%02x:%02x\n\r",gWIZNETINFO.mac[0],gWIZNETINFO.mac[1],gWIZNETINFO.mac[2],gWIZNETINFO.mac[3],gWIZNETINFO.mac[4],gWIZNETINFO.mac[5]);
	printf("IP Address  : %d.%d.%d.%d\n\r",gWIZNETINFO.ip[0],gWIZNETINFO.ip[1],gWIZNETINFO.ip[2],gWIZNETINFO.ip[3]);
	printf("SN Mask     : %d.%d.%d.%d\n\r",[0],[1],[2],[3]);
	printf("Gateway     : %d.%d.%d.%d\n\r",[0],[1],[2],[3]);
	printf("DNS1 Server : %d.%d.%d.%d\n\r",gWIZNETINFO.dns[0],gWIZNETINFO.dns[1],gWIZNETINFO.dns[2],gWIZNETINFO.dns[3]);
	printf("DNS2 Server : %d.%d.%d.%d\n\r",DNS_2nd[0],DNS_2nd[1],DNS_2nd[2],DNS_2nd[3]);


Can you give a link to it? There may be a number of places for sources over the internet, point me to the ones you used.

Well, I have downloaded them. I am attaching them here (12.1 KB)

Thanks. The routine is very small and simple, instead of guessing what is wrong put diagnostic output after each command displaying the stage it is in (what command is going to be executed) and result of previous command. i am sure you will get what is wrong very quickly :slight_smile: