Wemos D1 mini dies after seconds of controlling a nixie clock

Hello!

I'm Simon and I bought a nixie clock kit and decided to upgrade it with a wemos D1 instead of its native PIC16F, so that it would fetch the time via NTP and also change DST automatically.

I am not a newby and I did other projects in the past, but never experienced what's happening now: After few seconds, the wemos simly dies.

Weirdly the wemos lasts proportionally to the time it has been off (i.e. if I leave it off for an hour, then it lasts for a minute, but if I re-plug it immediately after a failure, it lasts less than 5 seconds) but never more than a minute

Here's a video showing the issue: Nixie setup with Wemos D1 mini problem - YouTube

The blue led of the wemos indicate it is in the loop() and is piloting the clock. You can also see that the time is fetched correctly and displayed correctly (the flicker is from the phone camera) but then, at second 50 the wemos simply dies!

Things to consider:

  • The clock has a single K1D144 to control four nixies and it does so by alternating which digit is lighted up. In my setup each digit is on for 5ms
  • The clock iself should not be the problem because with the original PIC works fine (it's just fiddly to set the time and change it when needed)
  • The only items connected to the wemos are (1) Vdd(5v) and Gnd, (2) four pin of the K1D144 and (3) four MPSA42 transistors, to power each digit in sequence
  • The wemos never springs back to life by itself: it takes a power cycle

I can post the code if needed.

What do you think is the problem? I am not an expert in transistors, can it be some draw/residual/inverse current from them?

I suspect I need to upgrade to something a little more sturdy than a wemos, so in case, can you suggest a better suited board that has a wifi chip integrated and doesn't cost a fortune on aliexpress?

Thanks a million!

Simon

Post your code, post your circuit. What are you powering the Nixie with?

Here are both code and scheme (last page of the PDF)

It is powered by an AC 220v to AC 12v transformer

The original schematic theory was to use the 50Hz to keep time but it was not working properly, hence the upgrade

On the board there is a step up to 170v DC for the nixies and 5v DC for the PIC/Wemos

Thanks again

Simon

/*
   NTP time from here: https://github.com/PaulStoffregen/Time/blob/master/examples/TimeNTP/TimeNTP.ino
*/

#include <ESP8266WiFi.h>
#include <TimeLib.h>
#include <TimeLord.h>
#include <WiFiUdp.h>

#define DEBUG 0

// Arduino pin names for BCD Encoding
#define BCD_A D1 //white
#define BCD_B D2 //grey
#define BCD_C D3 //purple
#define BCD_D D4 //blue

// Arduino pin names for Nixie Enabling
#define Nixie1 D5 //green
#define Nixie2 D6 //yellow
#define Nixie3 D7 //orange
#define Nixie4 D8 //brown

/* Blynk and WiFi operational variables */
char ssid[] = "xxxxx"; // Your WiFi network name.
char pass[] = "xxxxx"; // Your WiFi password.

/* Variables for NTP protocol time sincronization */
char timeServer[] = "time.nist.gov"; // nl.pool.ntp.org maybe also
const int timeZone = 0;     // British Time
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets
const unsigned long SEVENTY_YEARS = 2208988800UL;

/* network variables */
WiFiUDP Udp;
unsigned int localPort = 8888;  // local port to listen for UDP packets

int frequency = 5;

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");   Serial.println(WiFi.SSID());
  // print your WiFi shield's IP address:
  Serial.print("IP Address: "); Serial.println(WiFi.localIP());
  // print the received signal strength:
  Serial.print("signal strength (RSSI) dBm: "); Serial.println(WiFi.RSSI());
}

int dstOffset (unsigned long unixTime) {
  //Receives unix epoch time and returns seconds of offset for local DST
  //Valid thru 2099, Calculations from "http://www.webexhibits.org/daylightsaving/i.html"
  //Code idea from jm_wsb @ "http://forum.arduino.cc/index.php/topic,40286.0.html"
  //Original code here: http://forum.arduino.cc/index.php?topic=197637.0
  //DST update wont be reflected until the next time sync
  time_t t = unixTime;
  int beginDSTDay = (31 - (4 + year(t) * 5 / 4) % 7);
  int beginDSTMonth = 3;
  int endDSTDay = (31 - (1 + year(t) * 5 / 4) % 7);
  int endDSTMonth = 10;
  if (((month(t) > beginDSTMonth) && (month(t) < endDSTMonth))
      || ((month(t) == beginDSTMonth) && (day(t) > beginDSTDay))
      || ((month(t) == beginDSTMonth) && (day(t) == beginDSTDay) && (hour(t) >= 1))
      || ((month(t) == endDSTMonth) && (day(t) < endDSTDay))
      || ((month(t) == endDSTMonth) && (day(t) == endDSTDay) && (hour(t) < 1)))
    return (SECS_PER_HOUR);  //Add back in one hours worth of seconds - DST in effect
  else
    return (0);  //NonDST
}

// digital clock display of the time. Refer to here: http://playground.arduino.cc/Code/Time
void digitalClockDisplay() {
  Serial.print(year());   Serial.print(" ");  Serial.print(month());   Serial.print(" ");  Serial.print(day()); Serial.print(" ");
  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());
}



void setBCDpins (int digit) {

  // D 8

  if (digit > 7) {
    digitalWrite(BCD_D, HIGH);
  } else {
    digitalWrite(BCD_D, LOW);
  }


  // C 4

  if (digit > 4 & digit < 8) {
    digitalWrite(BCD_C, HIGH);
  } else {
    digitalWrite(BCD_C, LOW);
  }


  // B 2

  if (digit == 2 | digit == 3 | digit == 6 | digit == 7) {
    digitalWrite(BCD_B, HIGH);
  } else {
    digitalWrite(BCD_B, LOW);
  }

  // A 1

  if (digit % 2 == 1) {
    digitalWrite(BCD_A, HIGH);
  } else {
    digitalWrite(BCD_A, LOW);
  }

}



void setup() {
  Serial.begin(9600);

  /* WiFi initialization and housekeeping */
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500); Serial.print("."); // Wait until connected
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  /* NTP initialization*/
  Udp.begin(localPort);
  //sendNTPpacket(timeServer);
  setSyncInterval(20); // Set seconds between re-sync

#if DEBUG == 1
  Serial.println(getNtpTime());
  Serial.print("Time Status before setSyncProvider:");
  Serial.println(timeStatus());
#endif

  setSyncProvider(getNtpTime);

#if DEBUG == 1
  Serial.print("Time Status after setSyncProvider:");
  Serial.println(timeStatus());
#endif

  pinMode(BCD_A, OUTPUT);
  pinMode(BCD_B, OUTPUT);
  pinMode(BCD_C, OUTPUT);
  pinMode(BCD_D, OUTPUT);

  pinMode(Nixie1, OUTPUT);
  pinMode(Nixie2, OUTPUT);
  pinMode(Nixie3, OUTPUT);
  pinMode(Nixie4, OUTPUT);

  digitalWrite(Nixie1, LOW);
  digitalWrite(Nixie2, LOW);
  digitalWrite(Nixie3, LOW);
  digitalWrite(Nixie4, LOW);
  

}

void loop() {

  //// Write WiFi status
  //printWifiStatus();

  //Write Time
  digitalClockDisplay();

  ////Wait 10 seconds
  //delay(10000);

  // Print hours decade
  digitalWrite(Nixie1, HIGH);
  setBCDpins(hour() / 10 );
  delay(frequency);                       // wait for a bit
  digitalWrite(Nixie1, LOW);
  
  // Print hours unit
  digitalWrite(Nixie2, HIGH);
  setBCDpins(hour() % 10 );
  delay(frequency);                       // wait for a bit
  digitalWrite(Nixie2, LOW);

  // Print minute decade
  digitalWrite(Nixie3, HIGH);
  setBCDpins(minute() / 10 );
  delay(frequency);                       // wait for a bit
  digitalWrite(Nixie3, LOW);
  
  // Print minute unit
  digitalWrite(Nixie4, HIGH);
  setBCDpins(minute() % 10);
  delay(frequency);                       // wait for a bit
  digitalWrite(Nixie4, LOW);


}

/* NTP functions */
time_t getNtpTime() {
  while (Udp.parsePacket() > 0) ; // discard any previously received packets

#if DEBUG == 1
  Serial.println("Transmit NTP Request");
#endif

  sendNTPpacket(timeServer);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {

#if DEBUG == 1
      Serial.println("Receive NTP Response");
#endif

      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      return secsSince1900 - SEVENTY_YEARS  + timeZone * SECS_PER_HOUR + dstOffset(secsSince1900 - SEVENTY_YEARS );
    }
  }

#if DEBUG == 1
  Serial.println("No NTP Response :-(");
#endif

  return 0; // return 0 if unable to get the time
}

// send an NTP request to the time server at the given address
void sendNTPpacket(char* address) {
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;
  // all NTP fields have been given values, now you can send a packet requesting a timestamp:
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}

mn17(1).pdf (684 KB)

maybe an array of opto-couplers?

something like this:

https://www.aliexpress.com/item/32719949787.html

?

simraba:
The only items connected to the wemos are (1) Vdd(5v)...

VDD (3.3volt), or the 5volt pin...

The ESP8266 is a 3.3volt processor, and shouldn't see more than 3.6volt on any pin except for the 5volt (USB) power pin.

Remove that 5volt connection if you power the WeMos from USB, or connect it to the 5volt pin of the WeMos.

The 74141 should work with 3.3volt logic (try it). If not, use level translators.
The transistors must have base current limiting resistors. 10k will do.

Transistors without base resistor are almost a short (diode) for a WeMos output pin.
I wouldn't trust the WeMos any more if it has 5volt on the 3.3volt power pin (VDD) and shorted I/O.
Leo..

Edit: A 78L05 (100mA) is not capable to power the WeMos (100mA, 400mA peaks) with an input voltage >=12volt.
Try a 7805 (TO-220), maybe with a small heatsink, or a 5volt DC/DC (buck) converter.

Nixie clock designs fascinate me. I’ve built two now. One very similar to yours, that is a multiplexed 4 digit design with a single Russian BCD driver chip and an ESP8266 to run it all, but I used in addition a port multiplier (mcp23017 predecessor) because of the limited number of ESP pins. It is powered only from a 5volt USB adapter, using 2 cascaded boost converters for the high voltage part. The other design I published here: Six Digit Nixie Clock - Exhibition / Gallery - Arduino Forum

The missing current limiting resistors, as already pointed out, is an odd design decision. Other PV-electronics clocks have these e.g. https://www.pvelectronics.co.uk/archive/qtc_v8a.pdf , in this case 4.7k. Only in special cases, e.g. emitter follower configuration, can these be omitted.

I did not see, in the original design, for how long these transistors were driven, but probably not longer than 5ms , otherwise it would have caused noticeable flicker. It could be that the pins of PIC could tolerate such abuse in a 25% duty cycle.

I would also try to see how the Wemos performs when you disconnect just the 4 pins which drive the mpsa42 transistors, that is if the debug information in the serial console indicates all is well, and the problem appears to go away. That recovery times up to one hour help is alarming though.

You no longer need that large transformer and can use a smaller 9 to 12 volt switching type power supply, since the time base is not now the mains frequency. You may have to connect it to the cathode of D1 and ground to avoid the voltage drop across the bridge rectifier.

Thanks a million for your replies

And thanks even more to @6v6gt for digging up a pvelectronics datasheet!!! Your nixie clock is also stunning: such a clean design...

I will try adding the 4.7k resitor and see if it will work

Yesterday I tried connecting only one tube and the Wemos lasted much more than a minute, but still, fainted after a while... This time it resuscitated by itself without me powering down and up again but there's clearly something odd.

To answer other questions:

  • The wemos is powered exclusively via its 5v pin (not via USB), which is connected to an onboard voltage regulator to lower the voltage to 3.3v
  • both the k155ID1 and the MPSA42 should work with 3.3v as their high logic is respectively 2v and 0.9v
  • indeed, even at 10ms there is a noticeable flicker, so I was set to use 5ms
  • Even if now I don't need the current 12v AC transformer, I'd rather keep it, so not to make the design even messier than it already is

Thanks again! Will keep you posted!

Simon

Guys I don't know how to thank you for the help!

All is well and good: the missing resistor was making so that the Wemos was going in over-current protection (somehow) and putting itself out of commission for a bit

I've added 4K7 resistor and no problem anymore!

I now have to improve the code as the NTP refresh currently shuts off the main loop() of the code and so the whole clock goes dark when the time is being refreshed.

But this is nothing complex and I will improve the code, maybe with timers, to get rid of the problem

Thanks a million again

Ciao!

Simon

The problem is that that NTP routine you have blocks. It sends a request to the NTP server, then waits in a tight loop for the reply, timing out after 1500 ms.

You can drive the display from a timer call back routine instead of in the main loop(). This might make it less sensitive to blocking code.

Ticker ticker ;
. . .
setup() {
  . . . 
  ticker.attach_ms( 1, pushOut ) ;   //  1 mS
  . . . 
}

void pushOut() { 
  // handle display of next digit 
  . . . 
  . . .
}

That nixie clock link I sent has an example of a non-blocking NTP time fetch. However, it is quite complex and was actually designed for an audio application (ESP8266 speaking clock) which could tolerate only a few ms of blocking code, and required one hundredth of a second precision.

setSyncInterval(20); // Set seconds between re-sync

Wow.
The ESP8266 has a real crystal for it's clock. and will keep accurate time for very long in my experience.
Try to update once a day, and see how much it has drifted before the next update.
Leo..

Wawa:
Try to update once a day, and see how much it has drifted before the next update.

I agree. All 3 of the clocks I have built with Wemos mini resync with NTP only every 24hrs. I've not noticed them drift significantly over that period. None of my clocks multiplex their displays, so I don't have the problem of them blanking while fetching the time. One uses a circle of 60 x ws2812 LEDs, one has 4 x 7-seg digits made from 12V led strips driven by 4 x tpic6b595, the other has a 128x64 GLCD display.

To be honest, the 20 second interval between re-synch was just a number I set up long ago (for another project in which I needed accurate time) and never bothered doing experiments on stretching it...

It just worked... And, more importantly, NIST didn't ban my address because of excessive amount of requests :slight_smile:

I'll start by changing it to 86400 in the current code and see if it needs more adjusting

Once more, thanks a lot for all the replies

Simon

Hi Guys...

So, it looked like I have spoken really too soon.

With the added 4.7kOhm resistors between the MPSA42 and the wemos I achieve a good uptime but then when I decide to go in "nixie saving mode" which would just keep time and the led column blinking but switching off the nixie, the whole clock dies after a bit

I tried upgrading the resistors to 10k as someone else had suggested: same result. So I really would like to separate the +170v part of the circuit and the +3.3v/+5v controlling part with optocouplers.

They also do it in this clock: https://www.nixieclock.biz/Downloads/4-Digit-ESP8266-Clock-Construction-Manual.pdf but they don't publish the full diagram

I have designed the attached circuit, but I would liek to ask:

  • is it ok to put a common resistor in the GND part of the emitting part of the optocoupler?
  • what resistor should I use (both if common and if I need to use 4)?
  • which optocoupler can you recommend (both single ones and 4 packaged in a dip)?

Thanks again for all the support

Simon

Forgot to mention:

net port 6 to 9 are Wemos pins

net port 10 - 13 are to MPSA42 transistors

Since only one anode will be switched on at any one time, you can get away with a common current limiting resistor for the opto couplers. 4.7k seems a bit high though for 3.3 volts.

Can you show also an example of the circuit around the MPSA42 transistors. For example, the value of the base resistor etc.

Thank you 6v6gt!

I will end up putting a plaque on the clock saying "with the generous support of 6v6gt" :slight_smile:

For the diagram, on the third post of this thread there is an attached pdf. The diagram is on the last page.

The PIC will be gone and replaced by a wemos, and while the wemos will control directly the only K155ID1, the optocoupler would be between the wemos and the mpsa42

Thanks again

Simon

I'm have a question about the calculation of the value for R1 (4k7).

As I read the datasheet for the optocoupler TLP521GB it say 10mA and approx 1.15volt.

And then should R1 = (3.3-1.15)/10mA = 2.15/10mA = 215 ohm

So 4,7k ohm is way to high.

You don't have to drive an opto coupler with 10mA.

What opto LED current you need depends on how much current the opto transistor is switching.

You can find a minimum CTR (Current Transfer Ratio) in the datasheet.
That could be 50% for the ungraded ones.
Meaning for full saturation of the transistor you should drive the opto LED with twice the current that the transistor is switching.
Leo..