Lifted the pull-ups on the RTC module and completely removed the level shifters. Still glitching:
12:04:06.458 -> Date: 2025/12/16 Time: 12:03:57
12:04:07.458 -> Date: 2000/61/121 Time: 131:154:00
12:04:08.440 -> Date: 2025/12/16 Time: 12:03:59
Lifted the pull-ups on the RTC module and completely removed the level shifters. Still glitching:
12:04:06.458 -> Date: 2025/12/16 Time: 12:03:57
12:04:07.458 -> Date: 2000/61/121 Time: 131:154:00
12:04:08.440 -> Date: 2025/12/16 Time: 12:03:59
Ok, commented out the LCD display. Still glitching:
2:10:31.431 -> Date: 2025/12/16 Time: 12:10:22
12:10:32.442 -> Date: 2000/0/10 Time: 163:92:00
12:10:33.387 -> Date: 2025/12/16 Time: 12:10:24
Removed all reference to LCD and library, LCD SDA/SCL wires still in curcuit. Still glitching:
12:16:40.290 -> Date: 2025/12/16 Time: 12:16:33
12:16:41.210 -> Date: 2025/12/16 Time: 12:16:34
12:16:42.166 -> Date: 2025/12/16 Time: 12:16:35
12:16:43.133 -> Date: 2025/12/16 Time: 12:16:36
12:16:44.064 -> Date: 2000/0/10 Time: 16:31:00
12:16:45.015 -> Date: 2000/0/25 Time: 24:114:00
12:16:45.965 -> Date: 2000/0/72 Time: 33:36:00
12:16:46.916 -> Date: 2000/0/24 Time: 41:117:00
Current test program:
/*
* Created by ArduinoGetStarted.com
*
* This example code is in the public domain
*
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-lcd-clock
*/
//#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
//LiquidCrystal_I2C lcd(0x27, 20, 4); // I2C address 0x27 (from DIYables LCD), 16 column and 2 rows
RTC_DS1307 rtc;
void setup() {
Serial.begin(9600);
/*
lcd.init(); // initialize the lcd
lcd.backlight(); // open the backlight
delay(1000);
*/
Serial.println("Starting");
// SETUP RTC MODULE
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (true)
;
}
// automatically sets the RTC to the date & time on PC this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
void loop() {
DateTime now = rtc.now();
//delay(500);
int year = now.year();
int month = now.month();
int day = now.day();
int hour = now.hour();
int minute = now.minute();
int second = now.second();
/*
lcd.clear();
lcd.setCursor(0, 0); // start to print at the first row
lcd.print("Date: ");
lcd.print(year);
lcd.print("/");
lcd.print(month);
lcd.print("/");
lcd.print(day);
lcd.setCursor(0, 1); // start to print at the second row
lcd.print("Time: ");
if(hour < 10){
lcd.print("0");
}
lcd.print(hour);
lcd.print(":");
if(minute < 10){
lcd.print("0");
}
lcd.print(minute);
lcd.print(":");
if(second < 10){
lcd.print("0");
}
lcd.print(second);
*/
Serial.print("Date: ");
Serial.print(year);
Serial.print("/");
Serial.print(month);
Serial.print("/");
Serial.print(day);
Serial.print(" Time: ");
if(hour < 10){
Serial.print("0");
}
Serial.print(hour);
Serial.print(":");
if(minute < 10){
Serial.print("0");
}
Serial.print(minute);
Serial.print(":");
if(second < 10){
Serial.print("0");
}
Serial.println(second);
delay(950); // Update every second
}
If I were in your situation, I'd start all over again with the simplest circuit possible.
Everything should be connected to 3.3 V to start with.
If that works, add the level shifter and switch to 5 V.
Once that has been tested properly, continue.
If pull-ups are required, use the ESP32 internal ones.
Keep the connections as short as possible — small breadboards are quite useful for this kind of project.
Check continuity for GND and VCC.
Also, I had the idea that RTCs are kind of slow — reading them every second could be a problem.
Is there any other library available?
You'll need to add a 7660 voltage converter and a couple of caps, change a solder jumper and a couple of resistor values. That will generate a negative voltage for the display so that the contrast works well.
I've done this to 16x2 and 20x4 displays. It only takes a few minutes, and ends up as bright and contrast-y as when it was run on 5V.
I don't believe the 1307 will is spec'd to run below 4.5V. A 3231 is spec'd to run at 3.3V, and be much more accurate as well.
Away from my PC using iPhone I asked Chat GPT this, from recalling reading your thread earlier. Sorry if poorly constructed, but it might offer some line to pursue.
You said:
Using ESP32 and syncing NTP time synchronization with RTC getting weird series monitor output like Date: 2000/0/25 Time: 24:114:00 12:16:45.965 -> Date: 2000/0/72 Time: 33:36:00
ChatGPT said:
Those values aren’t random — they’re classic symptoms of invalid or uninitialized time data being interpreted as a date/time structure on the ESP32.
Let’s break down what’s going wrong and how to fix it.
What the weird output tells us
Example output:
Date: 2000/0/25 Time: 24:114:00
Date: 2000/0/72 Time: 33:36:00
Key red flags
Month = 0
Day > 31
Hour > 23
Minute > 59
Year stuck at 2000
This means:
The tm structure (or RTC registers) is being filled with garbage or partially updated data, not real time.
Most common causes on ESP32
Reading time before NTP sync completes (most common)
NTP sync is asynchronous. If you read the time immediately after calling configTime() or esp_sntp_init(), the clock is still invalid.
Result: Epoch = 0 or junk → decoded as nonsense date values.
RTC not initialized or restored correctly
If you’re:
Using an external RTC (DS3231, etc.)
Or reading ESP32 internal RTC after deep sleep
…and you never set it with valid epoch time, you’ll see exactly this behavior.
Mixing struct tm sources incorrectly
Common mistake:
Writing some fields manually
Letting others come from localtime() / getLocalTime()
The tm struct must be fully valid.
The correct ESP32 NTP pattern (important)
Proper way to wait for NTP sync
configTime(gmtOffset_sec, daylightOffset_sec, "pool.ntp.org");
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
return;
}
Serial.println(&timeinfo, "%Y/%m/%d %H:%M:%S");
getLocalTime() blocks until time is valid (or times out).
If you skip this, you get garbage.
If you’re syncing NTP → RTC (external)
Correct flow:
Wait for NTP time to be valid
Convert to epoch
Write epoch to RTC
Read RTC later only after it has been set
Example:
time_t now;
time(&now);
if (now < 1600000000) { // sanity check (~2020)
Serial.println("Time not valid yet");
return;
}
rtc.adjust(DateTime(now));
Sanity checks you should add
Always verify before printing:
if (timeinfo.tm_year < 120 || // year < 2020
timeinfo.tm_mon > 11 ||
timeinfo.tm_mday > 31 ||
timeinfo.tm_hour > 23 ||
timeinfo.tm_min > 59) {
Serial.println("Invalid time data");
return;
}
Why the year is often “2000”
Epoch = 0 → Jan 1, 1970
Some RTC libraries offset years internally
ESP32 RTC defaults can map this into year 2000
So “2000” is often a tell-tale sign of uninitialized time
Quick checklist
Call configTime()
Wait for getLocalTime() to succeed
Only then write to RTC
Never read RTC before it’s been set
Don’t partially fill struct tm
If you want, paste:
Your NTP sync code
How you write/read the RTC
Whether deep sleep is involved
and I’ll pinpoint the exact line causing the corruption.
Wow, a lot of replies. Thanks. To answer some questions:
rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));It might be well to consider looking at the success/failure return from Adafruit_I2CDevice::write_then_read which is called from RTC_DS1307::now. If the call to read the current time from the RTC is failing, then everything that follows is garbage. A temporary mod to RTC_DS1307::now to give some indication of success/failure (turning on an LED if it fails, for example) would give you a place to start looking or eliminate a possibility. Because right now you really don't seem to have any idea where the problem is starting.
Oh Brother, have you ever got that right!
I've tried two different RTC modules and two different Nano 33 IOTs, in all possible configurations. I've tried with and without pull-up resistors on an RTC module. I've pretty much convinced myself that the issue is not a specific piece of hardware. Which either leaves hardware incompatibility or software.
15:32:24.924 -> Date: 2025/12/16 Time: 15:32:17
15:32:29.942 -> Date: 2025/12/16 Time: 15:32:22
15:32:34.958 -> Date: 2025/12/16 Time: 15:32:27
15:32:39.914 -> Date: 2025/12/16 Time: 15:32:33
15:32:44.928 -> Date: 2025/12/16 Time: 15:32:38
15:32:49.938 -> Date: 2000/0/20 Time: 116:123:00
15:32:54.944 -> Date: 2000/0/81 Time: 03:12:00
15:32:59.919 -> Date: 2025/12/16 Time: 15:32:53
15:33:04.970 -> Date: 2025/12/16 Time: 15:32:58
15:33:09.950 -> Date: 2025/12/16 Time: 15:33:03
15:33:14.957 -> Date: 2025/12/16 Time: 15:33:08
15:33:19.974 -> Date: 2025/12/16 Time: 15:33:13
15:33:24.960 -> Date: 2025/12/16 Time: 15:33:18
15:33:29.963 -> Date: 2025/12/16 Time: 15:33:23
15:33:34.974 -> Date: 2025/12/16 Time: 15:33:28
15:33:39.956 -> Date: 2025/12/16 Time: 15:33:33
15:33:44.967 -> Date: 2025/12/16 Time: 15:33:38
15:33:49.936 -> Date: 2165/165/165 Time: 15:33:43
15:33:54.955 -> Date: 2165/165/15 Time: 15:33:48
15:33:59.957 -> Date: 2025/12/16 Time: 15:33:53
15:34:04.941 -> Date: 2025/12/16 Time: 15:33:58
It seems a lot of these odd values won't even fit in the relevant DS1307 registers. For example, the highest month value you could read from the month register is 19. And of course the 1307 would never put that value in that register. And when you look at this:
you have to think of I2C errors, except that it's the same error twice in a row, and the hh:mm:ss values on the same transmission are correct.
Well, I've never used the DS1307, the Nano 33 IOT, or the Adafruit library, so I can't do much to help figure it out. Do you have a regular Nano, or something like it running the Atmega328P?
Does anybody know if the raw Wire code that works on a Nano would also work on the 33 IOT? If so, we could come up with code that doesn't use an RTC library. Just grasping at straws, looking for ways to diagnose WTF is going on.
Which is why I suggested looking at the return from the low level I2C routine called in RTC_DS1307::now to figure out if that's working or not.
Then, I'd pull out one of those cheap USB logic analyzers and start looking at what's on the I2C itself. I2C is slow speed, so you'd easily be able to gather many seconds of data and see what's actually on the bus when the corruption occurs. You could use the aforementioned LED signal as a trigger. Since Pulseview has a pre trigger buffer, you'd be able to see the data the caused the error (assuming there is one).
Or you could just keep replacing bits and hoping that some combination mysteriously starts working.
Stick with it, Baby!
Once a bunny-hop man, always a bunny-hop man.
I imagine 6V6GT will agree.....
This code works with a DS3231 and a regular Nano. But it only uses the Wire.h library, so it might work with a DS1307 and Nano 33 IOT.
// This works on a DS3231 and Nano v3. The RTC must alread have been
// set to the correct time.
#include <Wire.h>
const int RTCaddr = 0x68; // I2C address of RTC
byte i;
byte value[6]; // date/time values
unsigned long oldmillis;
void readTime () {
Wire.beginTransmission(RTCaddr); // address of DS3231
Wire.write(0); // select register to begin
Wire.endTransmission();
delay(10);
Wire.requestFrom(RTCaddr, 7); // the 7 date/time registers
for (i = 0; i < 6; i++) {
value[5 - i] = bcd2dec(Wire.read()); // store in value[]
if (i == 2) Wire.read(); // read and toss day of week
}
}
byte bcd2dec(byte n) {
return n - 6 * (n >> 4);
}
void printValues() { // display timestamp in format
zeroFill(value[0]);
Serial.print("/");
zeroFill(value[1]);
Serial.print("/");
zeroFill(value[2]);
Serial.print(" ");
zeroFill (value[3]);
Serial.print(":");
zeroFill(value[4]);
Serial.print(":");
zeroFill(value[5]);
Serial.println();
}
void zeroFill (byte digit) { // add leading zeroes when needed
if (digit < 10) Serial.print("0");
Serial.print(digit);
}
void setup() {
Serial.begin(115200);
delay(3000);
Wire.begin();
oldmillis = millis();
}
void loop() {
while ((millis() - oldmillis) < 1000);
oldmillis = millis();
readTime();
printValues();
}
Well this is new:
19:14:26.247 -> 25/12/16 19:14:20
19:14:27.241 -> 25/12/16 19:14:21
19:14:28.255 -> 25/12/16 19:14:22
19:14:29.236 -> 25/12/16 19:14:23
19:14:30.237 -> 25/12/16 19:14:24
19:14:31.220 -> 25/12/16 19:14:25
19:14:32.222 -> 25/12/16 19:14:26
19:14:33.221 -> 165/165/165 165:27:27
19:14:34.250 -> 03/25/12 00:19:14
19:14:35.222 -> 25/12/16 19:14:29
19:14:36.237 -> 25/12/16 19:14:30
19:14:37.238 -> 25/12/16 19:14:31
19:14:38.251 -> 25/12/16 19:14:32
19:14:39.262 -> 25/12/16 19:14:33
19:14:40.256 -> 25/12/16 19:14:34
19:14:41.237 -> 04/04/09 44:06:03
19:14:42.220 -> 165/165/165 19:14:36
19:14:43.321 -> 25/12/16 19:14:37
19:14:44.253 -> 25/12/16 19:14:38
19:14:45.248 -> 165/12/16 19:14:39
19:14:46.247 -> 25/12/16 19:14:40
19:14:47.264 -> 25/12/16 19:14:41
19:14:48.220 -> 25/12/16 19:14:42
19:14:49.263 -> 25/12/16 19:14:43
19:14:50.224 -> 165/12/16 19:14:44
19:14:51.243 -> 25/12/16 19:14:45
19:14:52.273 -> 165/16/16 19:14:46
19:14:53.254 -> 25/12/16 19:14:47
19:14:54.262 -> 25/12/16 19:14:48
19:14:55.236 -> 25/12/16 19:14:49
19:14:56.245 -> 25/12/16 19:14:50
19:14:57.264 -> 25/12/16 19:14:51
19:14:58.220 -> 25/12/16 19:14:52
19:14:59.230 -> 25/12/16 19:14:53
19:15:00.234 -> 25/12/16 19:14:54
19:15:01.220 -> 25/12/16 19:14:55
19:15:02.221 -> 25/12/16 19:14:56
19:15:03.240 -> 25/12/16 19:14:57
19:15:04.225 -> 25/12/16 19:14:58
19:15:05.235 -> 25/12/16 19:14:59
19:15:06.263 -> 25/12/16 19:15:00
19:15:07.220 -> 25/12/16 19:15:01
19:15:08.255 -> 25/12/16 19:15:02
19:15:09.237 -> 25/12/16 19:15:03
19:15:10.222 -> 25/12/16 19:15:04
19:15:11.245 -> 25/12/16 19:15:05
19:15:12.221 -> 25/12/16 19:15:06
19:15:13.260 -> 25/12/16 19:15:07
19:15:14.235 -> 165/165/165 165:08:08
19:15:15.251 -> 25/12/16 19:15:09
19:15:16.220 -> 25/12/16 19:15:10
19:15:17.247 -> 25/12/16 19:15:11
19:15:18.261 -> 25/12/16 19:15:12
19:15:19.260 -> 25/12/16 19:15:13
19:15:20.221 -> 25/12/16 19:15:14
19:15:21.233 -> 25/12/16 19:15:15
19:15:22.241 -> 25/12/16 19:15:16
19:15:23.252 -> 165/165/165 165:165:165
19:15:24.236 -> 25/12/16 19:15:18
19:15:25.241 -> 25/12/16 19:15:19
19:15:26.241 -> 25/12/16 19:15:20
19:15:27.244 -> 25/12/16 19:15:21
19:15:28.221 -> 25/12/16 19:15:22
19:15:29.249 -> 25/12/16 19:15:23
19:15:30.239 -> 25/12/16 19:15:24
19:15:31.241 -> 25/12/16 19:15:25
19:15:32.249 -> 25/12/16 19:15:26
19:15:33.237 -> 25/12/16 19:15:27
19:15:34.255 -> 25/12/16 19:15:28
19:15:35.254 -> 25/12/16 19:15:29
19:15:36.238 -> 25/12/16 19:15:30
19:15:37.249 -> 25/12/16 19:15:31
19:15:38.221 -> 25/12/16 19:15:32
19:15:39.246 -> 25/12/16 19:15:33
19:15:40.241 -> 25/12/16 19:15:34
19:15:41.274 -> 165/165/165 15:15:35
19:15:42.273 -> 25/12/16 19:15:36
19:15:43.224 -> 165/165/165 13:15:37
19:15:44.257 -> 25/12/16 19:15:38
19:15:45.258 -> 25/12/16 19:15:39
19:15:46.227 -> 25/12/16 19:15:40
19:15:47.221 -> 25/12/16 19:15:41
19:15:48.250 -> 25/12/16 19:15:42
19:15:49.243 -> 25/12/16 19:15:43
19:15:50.222 -> 25/12/16 19:15:44
19:15:51.222 -> 165/165/00 19:15:45
19:15:52.264 -> 165/16/16 19:15:46
19:15:53.260 -> 25/12/16 19:15:47
19:15:54.222 -> 25/12/16 19:15:48
19:15:55.253 -> 25/12/16 19:15:49
19:15:56.222 -> 25/12/16 19:15:50
19:15:57.245 -> 25/12/16 19:15:51
19:15:58.253 -> 25/12/16 19:15:52
19:15:59.247 -> 25/12/16 19:15:53
19:16:00.222 -> 25/12/16 19:15:54
19:16:01.221 -> 165/165/165 165:165:165
19:16:02.248 -> 165/165/165 165:165:165
19:16:03.261 -> 165/165/165 165:165:165
19:16:04.221 -> 165/165/165 165:165:165
19:16:05.250 -> 165/165/165 165:165:165
19:16:06.221 -> 165/165/165 165:165:165
19:16:07.222 -> 165/165/165 165:165:165
19:16:08.222 -> 165/165/165 165:165:165
19:16:09.239 -> 165/165/165 165:165:165
19:16:10.244 -> 165/165/165 165:165:165
19:16:11.228 -> 165/165/165 165:165:165
19:16:12.246 -> 165/165/165 165:165:165
19:16:13.237 -> 165/165/165 165:165:165
19:16:14.260 -> 165/165/165 165:165:165
19:16:15.242 -> 165/165/165 165:165:165
19:16:16.228 -> 165/165/165 165:165:165
19:16:17.221 -> 165/165/165 165:165:165
Ok, so it's not the library. Well, I just don't know. You are using a built-in hardware I2C peripheral, right? Not some bit banged I2C. Anyway, it looks like an I2C problem to me, but I don't know what would cause it if not excess pullup resistors. It's like it's being interrupted from time to time, but that shouldn't be possible. And I don't know what the 165 stuff is all about.
Edit: When I said "not the library" I meant not the Adafruit RTC library. But it could be a problem with the Wire.h library for the 33 IOT. Or it could be problem with the 33 IOT. Others have had I2C problems with the Nano 33 IOT:
https://forum.arduino.cc/t/i2c-wire-problem-with-nano-33-iot/987526
After many iterations of testing and experimenting, I finally hit on the solution. Well, ShermanP did.
I swapped the RTC module that still had the pull-up resistors installed and tried that with his code. I still had the odd glitch, but it was about 1 in every 180 - 200 iterations (didn't matter if the time was posted once per second or once every five).
Then I reconnected the LCD display (that still has the resistors). No glitches in over an hour.
So it appears to be some incompatibility with the Adafruit RTClib library (to be fair, maikarg first raised that possibility).
VCC to that DS1307 RTC module is 5v, it won't run on 3.3v. The LCD display is still running on 3.3v. I've ordered a DS3231, which is supposed to run on 3.3v so we'll see if that makes a difference.
Thanks to all!
Not clear exactly what pullup resistor configuration ended up working with no glitches with my code. Also, did that configuration still not work with the Adafruit code?
I'm back to my original physical configuration, excepting the LCD is supplied with 3.3v. The I2C daughter board on the LCD display has 4.7K pull-up resistors. The RTC module has 3.3K resistors.
Definitely a software issue, compounded by removing the resistors from the RTC module. Poor troubleshooting technique on my part, I should have gone back to original before testing your code. Change one thing at a time...
You might want to research whether you can run the display on 3.3V. I think the display needs a negative voltage to run properly for a long time, and I'm not sure the driver setup can do that with only 3.3V coming in. Well, I'm just vaguely remembering stuff, but you should find out for sure.