Digit Fading / transition effects using HV566 Blanking

276 views
Skip to first unread message

Richard Scales

unread,
Apr 30, 2020, 11:56:06 PM4/30/20
to neonixie-l
Hello everyone,

I am contemplating having a go at implementing some form of digit cross fade effect of which I have zero experience, knowledge or understanding and I am hoping that someone could point me in the right direction.

I can see that there are established designs using HV5622 drivers which are capable of cross fading digits that change and I'd like to implement this myself.

I already use the blanking signal via a PWM signal to perform overall fading of the display (all tubes) though the trick must be maintaining full brightness for the digits that stay static whilst varying the brightness of the incoming and outgoing changing digits.

If this assumption is correct then I'm also going to assume that, even for the digits that remain static - they cannot be on all the time and there must be some 'off' time during which the changing digits can be faded. 

This all makes use of the persistence of vision thing that makes us think that the display is static.

If I'm still on the right track then I am guessing that there will be a sufficient 'off' time for the static digits to allow the fading digits (incoming and outgoing) to be presented at varying degrees of 'brightness'.

In a very rough pseudo code kind of thing:


:start of transition
Set shift register for static digits, turn all digits on, wait long enough for the 'full display' effect', turn all digits off
Set Shift register for outgoing digits only, turn on, wait long enough though reduce this period during the course of the transition, turn all digits off.
Set Shift register for the incoming digits only, turn on, wait long enough for the digits to start appearing and increase this period during the course of the transition, turn all digits off
Loop back to start until transition is complete

Am I anywhere near close with this?

Is there any published method?

I have yet to point my scope at a working clock to investigate this further - I currently have an inherent reluctance to do this following a recent episode of clumsy probing resulting in the premature expiration of the device that I was investigating :-(

It's really just the concept that I would like to fully grasp, I find that I can stare at sample code segments all day long and not make any meaningful progress, though code segments are most welcome.

All pointers gleefully received.

Richard

gregebert

unread,
May 1, 2020, 12:34:18 AM5/1/20
to neonixie-l
I have an 8-tube clock with b7971's and whenever I find the time... I will add a software routine that calculates which segments will change, and instead of changing them all at-once, they will be split into a few groups that change every 50-100msec. I think it would be too distractive for every second, but definitely ok every 10 seconds.

Technically its not really fading; more like morphing.

Richard Scales

unread,
May 1, 2020, 2:31:29 AM5/1/20
to neonixie-l
Just refining my query:

Having thought about this a little more and only assuming that my pseudo code example is anywhere near correct, would anyone be able to suggest what the relative timings might be for the period that the static digits are displayed and the range of periods for the fading in and fading out digits?

Further more, might it be OK to display things in this order:

Static Digits
Fading In Digits
Fading Out Digits

or perhaps in this order:

Static Digits
Fading In DIgits
Static Digits
Fading Out digits

or am I barking up the completely wrong tree!

Richard

Paul Andrews

unread,
May 1, 2020, 8:48:25 AM5/1/20
to neonixie-l
I do all the fading in software. Imagine you are running three faders. One for overall brightness, one for fading in and one for fading out. When you’re figuring out if a digit is one you say:

1. For static digits, if the brightness fader is on, then that digit is on, otherwise it is off.
2. For the digit fading in, if the brightness fader is on and the fade-in fader is on then the. The digit is on, otherwise it is off.
3. For the digit fading out, if the brightness fader is on and the fade-out fader is on then the digit is on, otherwise it is off.
4. Increment the brightness fader.
5. Adjust the fade-in fader so it is a bit brighter.
6. Adjust the fade out fader so it is a bit dimmer.

A ‘fader’ just needs to keep track of whether it is on or off. Like, for so many increments it is on, for a different number of increments it is off. It is easy to say that there are, for example, 100 increments (or ticks) before the cycle repeats. Then for 25% brightness you say it is on for 25 ticks and off for 75, then you start at the beginning again. This is basically how PWM works, so will effectively be PWMing the tubes yourself.

The HV chip series are easily fast enough for you to do this directly from the microprocessor.

Richard Scales

unread,
May 1, 2020, 9:45:58 AM5/1/20
to neoni...@googlegroups.com
Thank you very much for that, I'll keep reading it until I fully understand (could be some time). Are these three faders running in parallel or in series?
I think I can see how this might work if they are in parallel. Ie, assuming 100 ticks per cycle, for each tick, check the status of each fader, set and light the digits accordingly. 
Am I close? In this scheme then, each tick must have to digits switched on for a given time?
Am I still close or have I gone completely off piste?
Richard


--
You received this message because you are subscribed to a topic in the Google Groups "neonixie-l" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/neonixie-l/UWcm5_T2868/unsubscribe.
To unsubscribe from this group and all its topics, send an email to neonixie-l+...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/neonixie-l/2d0e8f3d-cb30-4dd7-b416-95f652ec956e%40googlegroups.com.

Paul Andrews

unread,
May 1, 2020, 10:36:10 AM5/1/20
to neoni...@googlegroups.com
You run them in parallel. In this scenario the faders don’t control the digits, your loop does that. It just reads the on/off state of the faders and figures out if that means a digit is on or off. Then it increments the fader and figures out if it also needs to adjust how long the ‘on’ period is for each one. Then loops again.

On May 1, 2020, at 9:45 AM, Richard Scales <scal...@gmail.com> wrote:



Richard Scales

unread,
May 1, 2020, 10:45:55 AM5/1/20
to neoni...@googlegroups.com
Thank you, I'll think more on this and create a test environment.
Thank you for your guidance.
Richard


Richard Scales

unread,
May 2, 2020, 12:05:07 AM5/2/20
to neonixie-l
I can see the concept just ahead of me - I'm still working out how to grasp it though!

If the fading process is set to run over say - 200mS , the fade completes after 200mS and would therefore leave the static displayed digit (for the 'seconds') displayed for 800mS before the fade to the next digit - this is a random guess - it may be a shorter period.

Then, I can see that during that 200mS, a digit that stays the same has to be on all of the time, A digit that is fading out has to have a 'duty cycle' that is going from full on to full off over that period and a digit that is fading in will have a 'duty cycle' that is going from full off to full on.


Then lets say that the actual fade process will occur over a number of steps - say 20 for example.

The logic that you describe in your first reply would be used to determine the duty cycles for each fade step


An outer loop would determine the duty cycles for each fade step
An inner loop would then perform the 'PWM' for the current step

Assuming a digit that was changing from '0' to '1' and that there will be 20 fade steps, duty cycle for the fading out digit will go from 100% to 0% in steps of 5% (assuming a linear fade). Similarly the duty cycle for the fading in digit would go from 0% to 100% in steps of 5%(assuming a linear fade).


In the first iteration of the 'PWM' loop - let's say that the '0' is on 100%, the '1' is on for 0%
The iteration has to last for total fade duration (200mS) divided by the number of iterations (20) - so 10mS.

For 10mS a PWM kind of signal at a given frequency (490Hz Arduino default so I chose 500Hz) has to be generated with the given duty cycles for the digits.

The '0' has 100%, the '1' has 0%

For the inner loop - which has to last 10mS and based on an assumed 'PWM' frequency of  500Hz.

The inner loop would have only 500 x 0.01 = 5 steps

For each of these steps, the '0' would be on and the '1' would be off

During each step - send the required digits to the shift register depending on their on/off state from the required duty cycle then wait the required number of mS  - in this case 10ms / 5 = 2mS.

25% of the way through the outer loop - the '0' would be on for 75% and the '1' would be on for 25% (assuming linear fade)
75% of the way through the outer loop - the '0' would be on for 25% and the '1' would be on for 75% (assuming linear fade)

Am I still on the right track?
These numbers all seem very small  - should I be working in uS with more steps?
Is the 500Hz 'PWM' frequency appropriate?

Thank you
Richard





On Friday, 1 May 2020 04:56:06 UTC+1, Richard Scales wrote:

Richard Scales

unread,
May 2, 2020, 12:21:46 AM5/2/20
to neonixie-l
Further thinking: - perhaps I don't need all those levels, perhaps just 5 levels of fade might be appropriate - in which case the outer loop is 5 iterations, each one 40mS if the overall fade process is to last 200mS, therefore the inner loop has to last for 40mS.

The inner loop emulating a PWM frequency of 500Hz then has 20 steps.

Does that sound any better?

RIchard

Paul Andrews

unread,
May 2, 2020, 6:58:30 AM5/2/20
to neoni...@googlegroups.com
The idea is correct, and your calculations look correct. I wouldn’t worry about the exact timing, you can adjust that once you have it basically working.



On May 2, 2020, at 12:21 AM, Richard Scales <ric...@scalesweb.co.uk> wrote:


--
You received this message because you are subscribed to a topic in the Google Groups "neonixie-l" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/neonixie-l/UWcm5_T2868/unsubscribe.
To unsubscribe from this group and all its topics, send an email to neonixie-l+...@googlegroups.com.

Richard Scales

unread,
May 2, 2020, 7:35:46 AM5/2/20
to neoni...@googlegroups.com
That is great news thank you.
I'm starting small and building up, still reeling with excitement having just produced a square wave at 250Hz.
Richard


Richard Scales

unread,
May 3, 2020, 12:14:44 AM5/3/20
to neonixie-l
I have a working solution to fade between digits which is mostly there, just a little fine tuning with timings and perhaps some additional fade steps but it's all good.
Thank you for all your help.
Richard

On Friday, 1 May 2020 04:56:06 UTC+1, Richard Scales wrote:

Dekatron42

unread,
May 3, 2020, 4:06:15 AM5/3/20
to neonixie-l
There's another way of dimming/fading described in this thread with source code on Github -  not mine, just remembered it.


/Martin

Owen Crawford

unread,
Jul 22, 2020, 3:38:47 AM7/22/20
to neonixie-l
Hi Richard,

You mentioned you have a working solution to digit fading?
I am pretty much in the position with designing a Nixie clock using the HV5622 chips. I have worked out most of the PCB design and got a few prototypes boards made up.
The HV5622 chips are in series and I've managed to make up some code in Arduino IDE and can control individual pins/digits using ShiftOut() which is inherently a bit slow with moving data to the registers.
I made up a fade table to quickly transition back and forth between the previous and next digit to give the illusion of cross-fading.
This worked well for the most part, until I have more than 1 digit fading, then the latency starts to become more noticeable and the digits star to flicker in transition.
After countless hours of reading, SPI seems to be the way to go as it's way faster to shift data out, however I am still in the middle of working out how to use SPI with the HV5622 registers and Arduino as I'm just getting random digits appearing all over the place.
I guess the next step after that was working out how to cross fade digits. Would you be so kind with sharing what you came up with? Better than trying to re-invent the wheel :)

Thank you.

/ Owen

Richard Scales

unread,
Jul 22, 2020, 4:14:33 AM7/22/20
to neoni...@googlegroups.com
Hello, yes I can help here, I'll reply when I get back to base but it was actually a fairly simple transition from shiftout to SPI transfer, back to you within 24hrs.
Richard

Sent from my Huawei phone
--
You received this message because you are subscribed to a topic in the Google Groups "neonixie-l" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/neonixie-l/UWcm5_T2868/unsubscribe.
To unsubscribe from this group and all its topics, send an email to neonixie-l+...@googlegroups.com.

Richard Scales

unread,
Jul 22, 2020, 10:28:06 AM7/22/20
to neonixie-l

For the SPI I have the following in my sketch:

#include <SPI.h>

In setup:

  // set up SPI
  SPI.begin();
  SPI.setFrequency(100000);
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE1);
  //set outputs for SPI
  pinMode(LEpin, OUTPUT);


Then, I have the following code that, in my case, is writing two 32 bit variables ( j and k ) out to the shift registers via SPI:

 //SPI transfer code 

  digitalWrite(LEpin, LOW);
  


//send K out 
  SPI.transfer((k >> 24) & 0xff);
  SPI.transfer((k >> 16) & 0xff);
  SPI.transfer((k >>  8) & 0xff);
  SPI.transfer(k & 0xff);
  
//send J out 
  SPI.transfer((j >> 24) & 0xff);
  SPI.transfer((j >> 16) & 0xff);
  SPI.transfer((j >>  8) & 0xff);
  SPI.transfer(j & 0xff);

  
  digitalWrite(LEpin, HIGH);


There may well be a 32 bit Spi transfer but I was modifying older shiftout based code so stuck with what I was doing previously, YMMV.


On a Wemos D1, when using SPI,  I believe that you are tied to using:

D5 for Clock
D6 for Strobe
D7 for Data

I also run the HV5622's as 12V logic levels (keeping within spec) by using CD40109 level shifters, it all works really well.

Please let us know how you get on.

- Richard

Paul Andrews

unread,
Jul 22, 2020, 6:08:47 PM7/22/20
to neoni...@googlegroups.com
There is a 32 bit shift out, at least on ESP platforms.

You aren’t limited to specific pins on the ESP8266

I am pretty sure that for these chips you should move this line 

digitalWrite(LEpin, LOW);

To just before this line:

digitalWrite(LEpin, HIGH);


On Jul 22, 2020, at 10:28 AM, Richard Scales <ric...@scalesweb.co.uk> wrote:


--
You received this message because you are subscribed to a topic in the Google Groups "neonixie-l" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/neonixie-l/UWcm5_T2868/unsubscribe.
To unsubscribe from this group and all its topics, send an email to neonixie-l+...@googlegroups.com.

Kevin A.

unread,
Jul 22, 2020, 6:39:27 PM7/22/20
to neonixie-l
If you're trying to shift at any decent frequency (which would be desirable for a smooth crossfade event) then I would not use 'digitalwrite' as it is an arduino function which takes a lot of processor time to simply change an I/O to high or low logic level. Hardware SPI is #1, but I found that a little difficult to use when I began programming my ESP32 nixie projects in the arduino framework. I eventually figured out how to do it with good results in software. 

I'll share a little snippet of my code below that I've written for several ESP32 based nixie clocks that also have crossfading. This should give you some insight into using the fastest possible software based bitbanging routines to toggle I/Os and drive your HV shift registers.

The first blocks establish the GPIOs I intend to use to drive the HV shift registers (through a 40109 level shifter of course). 

The senddata() function is the actual bitbang sequence which is being run at several kHz using an interrupt service routine. This code in particular is driving two HV shift registers which are 32 bits each, hence the for loop spanning from i = 63 to i >= 0. 

The "IRAM_ATTR" flag means that the compiled code for this function will be placed in the Internal RAM (IRAM) of the ESP32, which is much faster than storing it in the main flash. I would recommend doing some reading and trying several online examples of ESP32 interrupt service routines. It is essential for getting display routines (such as bitbanging) to run quickly enough for good crossfading results. 

"
#define GPIO22_H         (GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, 1<<22))
#define GPIO22_L         (GPIO_REG_WRITE(GPIO_OUT_W1TC_REG, 1<<22))
#define GPIO22(x)        ((x)?GPIO22_H:GPIO22_L) //HV Driver Blank (GPIO22)

#define GPIO5_H         (GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, 1<<5))
#define GPIO5_L         (GPIO_REG_WRITE(GPIO_OUT_W1TC_REG, 1<<5))
#define GPIO5(x)        ((x)?GPIO5_H:GPIO5_L) //HV Driver Latch Enable (GPIO5)

#define GPIO18_H         (GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, 1<<18))
#define GPIO18_L         (GPIO_REG_WRITE(GPIO_OUT_W1TC_REG, 1<<18))
#define GPIO18(x)        ((x)?GPIO18_H:GPIO18_L) //HV Driver Clock (GPIO18)

#define GPIO23_H         (GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, 1<<23))
#define GPIO23_L         (GPIO_REG_WRITE(GPIO_OUT_W1TC_REG, 1<<23))
#define GPIO23(x)        ((x)?GPIO23_H:GPIO23_L) //HV Driver Data (GPIO23)

...
void IRAM_ATTR senddata() {
  for (int i = 63;i >=0 ;i--)
     {
       GPIO18_H;
         if (outputbuffer[i] == 1) {
           GPIO23_H;
         }
         else {
           GPIO23_L;
         }
        GPIO18_L;
      }
GPIO5_H;
GPIO5_H;
GPIO5_L;
GPIO5_L;
}
"


You received this message because you are subscribed to the Google Groups "neonixie-l" group.
To unsubscribe from this group and stop receiving emails from it, send an email to neonixie-l+...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/neonixie-l/83799903-10B7-4851-ADCB-45BD1501C4B5%40gmail.com.

Kevin A.

unread,
Jul 22, 2020, 6:45:08 PM7/22/20
to neonixie-l
That code is for the HV5523 by the way. Make sure to pay attention to the truth table in the HV5522/5622 datasheet to know if data is clocked in on the rising edge or falling edge of the clock signal. 

btw the HV5522/5622 are nearly identical, only difference is the 5522 shifts in a counter-clockwise direction viewed from the top of the package, while the 5622 shifts clockwise. 

Owen Crawford

unread,
Jul 22, 2020, 8:26:06 PM7/22/20
to neonixie-l
Hi Richard,

Thank you, I will give it a go when and report back.

Hi Kevin,

That looks very useful, thank you.
I am currently just prototyping with an ATmega328P on an Arduino Uno board at the moment.
I haven't touched ESP32's before. Maybe I should start looking at them? :)
The only reason why I'm sticking with the ATmega328P's at the moment is because of their familiarity and have a simple DIP package which are easy to work with, especially when I start to have some controller prototype boards made up.
Can the IRAM_ATTR flag be used with 328P's I wonder? I'll do some research on that :)
I have flashed 328P's before using SPI to bypass the slow Arduino IDE boot library, however I haven't tried flashing with SPI to see if it would improve the Bitbanging frequency. Maybe it would?

By the way, I have my HV5622's hanging directly off my Uno board. What is the reasoning/benefit behind using a 40109 Level Shifter in between to control the HV5622's?

This is my prototype I have going at the moment using IN-4 tubes. I'll be using a "two-piece" Display and Controller board design in my clock when it is finally finished.

Prototype_6XIN4DD.jpg

Richard Scales

unread,
Jul 23, 2020, 12:07:05 AM7/23/20
to neonixie-l
An ESP8266 / Wemos device runs at 3v3 logic levels, the HV5622 specification indicates that it likes to run at 12V logic levels so there needs to be some conversion between the two for reliable operation.

The spec sheet for the HV5622 clearly states that the logic supply voltage should be between 10.8V and 13.2V and the logic input levels should be between supply voltage-2 and the supply voltage. Driving them with 5V logic is way out ot spec, driving with 3V3 logic even more so.

I know that many folk run them at 5V logic and I have even had some success at 3V3 logic but that is way out of spec and there is a risk that things like manufacturing changes or cable lengths may stop things working one day.

I was using 2N3906 level shifter circuits until Paul Andrews put me on to the CD40109 which is a nice compact 8 way level shifter (available in DIP or surface mount)  which I have now used in several designs and would highly recommend.

Paul, I did look briefly for the 32 bit  SPI 'command' but failed to find, I should look harder and I didn't see a way of redefining the SPI pins used :-(  I also found that moving the LE toggle from before the SPI commands to after made no difference as far as I could tell, both methods appeared to work equally well  (for me on a WeMos). I should learn more about this.

- Richard


On Friday, 1 May 2020 04:56:06 UTC+1, Richard Scales wrote:

Christian Riise Wagner

unread,
Jul 23, 2020, 6:17:48 AM7/23/20
to neonixie-l
Richard, I'm using the 32-bit SPI-write for my most recent ESP32 based clock. I'm saving the data for all six tubes and the colons in a single 64-bit variable (uint64_t), so sending out the data can be done with just four lines of code:

digitalWrite(SS, LOW);
SPI.write32(nixData);
SPI.write32(nixData >> 32);
digitalWrite(SS, HIGH);

No special setup is required to use the 32-bit SPI functions. As for the pins, looking at the ESP32 Arduino GitHub, the SPI begin function takes four variables for the pins:

void SPIClass::begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)

If the function is called with empty brackets, the default pins will be used. Has to be said that my design uses the default pins, so I haven't tested this.

Paul Andrews

unread,
Jul 23, 2020, 9:57:21 AM7/23/20
to neonixie-l
This chip works as follows: You stream data in to the shift register. On the rising edge of the LE pin, the data is transferred from the shift register to the outputs. If the LE pin is left high, the chip is in transparent latch mode - which means that any data shifted to it is immediately visible.

This is the truth table from the datasheet that shows this:

20200723_133355000_iOS.jpg

So, in other words, you should really leave the LE pin low and then toggle it after you have written the data as follows:

SPI.write32(nixData);
SPI
.write32(nixData >> 32);
digitalWrite
(SS, HIGH);

digitalWrite
(SS, LOW);

The code below works, but it leaves the chip in transparent latch mode. This is a hang-over from the code samples for using the 74HC595 chip.

Paul Andrews

unread,
Jul 23, 2020, 9:58:47 AM7/23/20
to neonixie-l
Not sure what happened to the truth table there. So here it is again (fingers crossed)

20200723_133355000_iOS.jpg

Gavin Andrews

unread,
Jul 23, 2020, 10:57:29 AM7/23/20
to neoni...@googlegroups.com
Are the tubes muxed?  I have an interrupt scheme which muxes the tubes and for each set the ontime is set within the mux cycle to allow fading of digits.

I did implement cross fade but don't like the effect to be honest so have disabled it... one effect I really do like is when it reaches 0 (after 9) it scrolls back to 0.... 9,8,7...0 

--
You received this message because you are subscribed to the Google Groups "neonixie-l" group.
To unsubscribe from this group and stop receiving emails from it, send an email to neonixie-l+...@googlegroups.com.

Richard Scales

unread,
Jul 23, 2020, 11:41:41 PM7/23/20
to neonixie-l
Thank you for the confirmation of the 32 bit SPI, Paul had mentioned this to me previously but I had not pursued it as what I had was working - similarly for the handling of the LE line - I noticed no immediately visible difference when moving the dropping of LE to after the SPI Write commands though it is clear from the truth table that it should be done this way.

I will apply these changes next time I change the code and test - thank you.

- Richard
To unsubscribe from this group and stop receiving emails from it, send an email to neoni...@googlegroups.com.

Owen Crawford

unread,
Jul 26, 2020, 12:45:39 AM7/26/20
to neonixie-l
Hi Richard,

Thank you for the insight on the use of the CD40109. I've ordered a couple Texas Instrument DIP versions off ebay. Once I get them I'll pursue putting some SPI code together using your example you posted earlier.
As you mentioned, at the moment I'm getting away with using 5v logic from the Arduino, but maybe I won't have as much luck when moving to SPI and I'll just be going around in circles trying to troubleshoot the code because I'm not running the HV5622's to spec :)

I did find a Nixie Arduino shield which appears to be using SPI and a CD4505BM similar 5 to 12v level shifter.
Do you also use 10 or 100nF caps with the HV5622's VDD and CD40109 VCC to ground?

Richard Scales

unread,
Jul 26, 2020, 12:54:40 AM7/26/20
to neonixie-l
I would also look at the suggestions for 32 bit transfers and the order of control over the LE signals that Paul has suggested - I will most certainly be doing this when I next visit my code. I know that if its not broken, one shouldn't try to fix it but just because I cant see that its not quite as it should be doesn't mean that it's right - I certainly remember when watching the signals on a scope - it was possible to see a subtle timing 'glitch' between each 8 bit SPI transfer which I would expect to vanish when using the 32 bit approach.

- Richard
Reply all
Reply to author
Forward
0 new messages