/eluavfd

A Lua module/API for VFD control in eLua

Primary LanguageC

--------------------------------------------------------------------------------
--
-- Vacuum Fluorescent Display control for eLua
--
-- Dado Sutter, Fev 2010         www.eluaproject.net
--
--------------------------------------------------------------------------------

   These are the notes for the vfd module for eLua.
   They are based on the tube we had (IV-18) and the decoder we've chosen (MAX6921)
   but they can be easily adapted to interfacing with other VFD tubes and panels.

## This is a work-in-progress document, not a final version yet ##
## Corrections, refinements and suggestions are welcomed ##




--------------------------------------------------------------------------------
--
-- The tube
--
--------------------------------------------------------------------------------

   In our first VFD interfacing project we are using this tube brought to
us by Bogdan Marinescu (www.eluaproject.net/###/authors.html) when he first came to
Brasil for the Lua Workshop 2009 (the video of the talk we presented together can
be downloaded from here ##).
   Bogdan's gift was two IV-18, a very neat, Russian made, cheap and not too hard
to find VFD tube. It has 8 numeric digits and a 9th extra position that has only
two symbols. We will call this extra symbol-only position a "digit" too, to keep
things simple. You can thus consider this tube a 9 digit, with a different segment
aarrangement in it's 9th position.
   
   FIG 1 - IV18 Pinout
   
Figure 1 shows that each independent segment of all digits are connected together,
creating a sort of Bus with 8 (segment) lines. Each individual digit has a sort
of "enable" or "select", creating another Bus but this time with 9 lines.
To light up any IV-18 segments, all we need is to do is to feed it's segment line
AND it's digit line with the high voltage Vbb that we'll talk about further down.
We can light up at the same time any combination of segments and digits. We also
note now that we cannot address/light up at the same time two different segments of
different digits. To do that, we must light one at a time for short periods, so we
fool our eyes to see them as if they are both lit simultaneously. This is the only
way to "write" different numbers in different digits at the same time and we will
call this "multiplexing" our segment and digit buses.
To complete our IV-18 description we must mention the filament, which is a simple
(but fragile!) internal resistance that needs to be powered by a DC voltage (see
power supplies below).
We also note that the segments forming the digits are not equal and this is one of
the things that make the IC-18 more appealing too.
  
   
   
--------------------------------------------------------------------------------
--
-- The Controller
--
--------------------------------------------------------------------------------
  To be able to send the higher voltage required by the VFDs, we used some nice serial
  to parallel decoders that also offer us the advantage of controlling all the lines
  with only 3 PIO pins. For this implementation we used the MAX6921. It's data sheet
  can be found here #### and the model we'll be discussing is the AWI (be careful!
  Different models have different pinouts!). Of the 20 available outputs, to control
  one IV-18 we only need to use 17; 8 for the segment bus and 9 for the digit bus.
  The MAX6921 is a simple serial to parallel converter that converts TTL levels
  serialized to it to high voltage (up to 76Vcc) parallel outputs. It also has a
  controlled latch so the outputs can be kept stable while new data is being
  clocked/serialized in.

Everything is done by 3 control pins:

  DIN (data in) - Receives the logic state of a bit you want to serialize to one of the
	outputs.
  CLK (clock) - Receives a positive pulse each time you want to shift in the DIN data.
	Once you have clocked all your data into this shift register (17 bits in our case)
	we give a positive pulse on the ... (below)
  LOAD (load/latch) - Informs the internal latch to transfer the clocked in data to the
	outputs and retain it until the next load pulse.
	
This simple protocol can be resumed like:
- Set DIN with the MSB you want to clock in (DOUT16 on the chip)
- Clock it in setting the CLK pin high and then low
- Repeat the steps above for the other 16 bits until LSB
- Set the LOAD pin high than low

The MAX6921 is powered by 5Vcc on a single pin and the high voltage to be sent to it's
outputs (Vbb) is fed through another single pin.



   


--------------------------------------------------------------------------------
--
-- The Power Supplies
--
--------------------------------------------------------------------------------

  The voltages required for the VFD tube and controller are:
   - TTL (Vcc)
     A regulated 5Vcc to power the MAX6921. The consumption of one chip is under 1mA.
   - High Voltage (Vbb)
     The literature says we should power the segments and digit lines with around 20Vcc
	 for direct uses and around 50Vcc for multiplexing. Our experience shows that the
	 tube lights quite nicely from 15Vcc up and 20Vcc seems to be enough even for slower
	 multiplexing times. But we have not tested it with higher voltages yet so we expect
	 to update this impressions soon. The current consumption with all the segments lit
	 at 20Vcc is 11mA.
   - Filament Voltage (VFilament)
     Again, the literature says we must power the filament with something between 4.2
	 and 5.6 Vcc. Five volt seems to be a good choice, so we can use the same source
	 used to power the MAX6921 (above). Our experience shows that the tube begins to
	 light with 2Vcc on the filament and the intensity of the segments doesn't vary
	 significantly from 2.5 to 5.6 Vcc (at least for 20Vcc being used as "high
	 voltage"). We are using 3Vcc hoping to save some tube's life but it is expected
	 to last for decades even when powered by the maximum allowed voltages. The current
	 consumption here is 50mA at 2.5Vcc and 81mA at 5.0Vcc. This maximum current
	 consumption is actually achieved when all the segments are off.
   
  We powered our assembly from a workbench variable power supply so we won't help you
  too much with analog and regulation details. Good tips and neat switching power supply
  projects can be found in some of the links below:

http://www.aplomb.nl/TechStuff/Switcher/Switcher.html

http://www.desmith.net/NMdS/Electronics/NixiePSU.html

http://www.electricstuff.co.uk/nixpsu.html
   


   
--------------------------------------------------------------------------------
--
-- The VFD eLua module
--
--------------------------------------------------------------------------------

  Hardware control drivers are usually coded in C or assembly, because of critical
  timings, fast response and predictable execution times requirements. We decided to
  implement our VFD driver in Lua, to show how you can achieve the same results in eLua
  with much more simplicity (and Fun! :).
  To use the eLua VFD module in your application, all you need to do is to include
a:
   
require( "vfd" )

... which will load the vfd module and make available the main control functions
in the "vfd." name-space
   
  To keep things simple, we are doing our control in a bit-bang manner, using 3 pio
  pins (for CLK, DIN and LOAD).
  Once the VFD module is loaded by require(), we need to call only once one of it's
  functions to initialize the module and configure it to your hardware.
   
   vfd.init()
      Initializes the VFD module and configures it to your hardware. 
      Default pio outputs are assumed for the currently known boards:
      EK-LM3S8962:
        DIN  - pio.PG_0
        CLK  - pio.PC_5
        LOAD - pio.PC_7
        
      eLua PUC-Rio:
        DIN  - pio.P0_24
        CLK  - pio.P0_26
        LOAD - pio.P0_28
        
  You can optionally pass one table as argument with some initialization parameters,
  if your board is not known to eLua or if you want to change the control pins used
  by default. The fields are all optional and described below:
      
      t = {}
      t.din_pin = the port/pin you want to use for the DIN line (ex: pio.PB_3)
      t.clk_pin = the port/pin you want to use for the CLK line
      t.load_pin = idem
      vfd.init( t )
      
  Now we come to the fun part of it, which is using the VFD module to write what we
  want to the VFD.
  The basic primitive is the set() function that takes two arguments: segments and
  digits
      
      vfd.set( segments, digits )
      
      - segments: An 8 bit Lua number, where each bit represent a segment. A logic 1
	  sets the segment on and a 0 sets it off.  As our IV-18 VFD has (mostly)
	  7-segment digits with a decimal point, we wired our assembly in a way that it
	  reproduces the usual notation for 7-segment led displays:
      
           a
        -------
        |     |
       f|     |b
        |  g  |
        -------
        |     |
       e|     |c
        |  d  |
        ------- dp

      Figure 2
      



      Figure 2 shows the segment identification letters. They are arranged in the
	  "segments" argument of the set() function with "a" being the MSB and "dp" being
	  the LSB, as shown in Figure 3.
      


      a    b    c    d    e    f    g    dp
      bit7 ............................. bit0
      
      Figure 3
      



Obs: the ninth "digit" on the left of IV-18 has only two segments. The dot is lit by
the "a" bit and the dash by the "b" bit.

- digits: Like the segments argument above, digit is a Lua number, this time with 9
bits, each representing a digit position on the VFD. The rightmost digit on the tube
correspond to bit0 and the leftmost (actually the dot & dash symbol) to bit8.



  Some examples of the set( segments, digits ) function usage may worth more than my
  bad english words. It is also easier if we use the 0x Lua hexadecimal notation for
  numbers in our examples:

1) Write the number 1 in the leftmost digit:

vfd.set( 0x60, 0x001 )

0x60 is 01100000, which means segments b and c set (lit)
0x001 is 000000001, which means the leftmost digit selected/enabled.

2) Write 66 right aligned:

vfd.set( 0x3A, 0x003 )

0x3A is 00111010, meaning segments c, d, e, f, g lit
0x003 is 000000011, meaning digits 1 and 2 selected

3) Write 33 centered:

vfd.set( 0xF2, 0x018 )

0xF2 is 11110010, meaning segments a, b, c, d, g lit
0x018 is 000011000, meaning digits 4 and 5 selected

4) Light up the decimal points of the four leftmost digits:

vfd.set( 0x01, 0x0F0 )

0x01 is 00000001, meaning the dp segment lit
0x0F0 is 011110000, meaning digits 5,6,7,8 selected

5) Light up the dot symbol on the 9th digit (symbols) on the left:

vfd.set( 0x01, 0x100 )

0x01 is 00000001, meaning the dot symbol (and dp segments) lit
0x100 is 100000000, meaning digit 9 selected.

6) Light up the dash symbol on the 9th digit (symbols) on the left:

vfd.set( 0x02, 0x100 )

0x02 is 00000010, meaning the dash symbol (and g segments) lit
0x100 is 100000000, meaning the digit 9 is selected



  The examples above show how simple it is to light up segments of a digit or equal
  segments in more than one digit. To write numbers (or some possible letters) that
  have a different set of lit segments to form it, we need to write them separately
  and quickly alternate between them (multiplex), to our eyes see them as all ###
  (continue .......)

      
      
Writing strings, numbers and symbols:

  To write numbers, symbols and the few possible letters we use the setstring()
  primitive.
  As it has to multiplex the numbers for some time to make our eyes think they are
  all lit at the same time, there is a second argument that controls this "time". It
  is simply a loop limit control number though, not a time-calibrated value.
  (Experiment with numbers between 100 and 500 first...). In future implementations,
  this primitive could return only the segments and digits mapped to the wanted string
  and the caller program could take care of the multiplexing. Some coroutine-coordinated
  schemes might bring some fun too.

  The primitive function to write strings is vfd.setstring( str, time ) and it's
arguments are:
- str:
  The string of numbers and/or possible symbols and letters to be written to VFD.
  The string is rendered right aligned.
  Maximum length is 8 characters but the dots (one or more, up to 8) do NOT count as
  positions (because they will be rendered on the same position of the preceding
  character).
  No check is being made for valid strings and sizes, so be careful.
- time:
  A number to control the time the string will be shown on the VFD. Pls read the
  introductory text above.
  VFD is cleared after the string is shown for this "time" (not time-calibrated !) and
  the control is given back to the caller program or interpreter.

      
      
Easy using all of this:

  To illustrate the uses of the set() and setstring() primitives we wrote two simple
  programs that define some functions to play with the VFD.
  artvfd.lua defines some (questionable :) art functions and numvfd.lua defines
  functions to write strings, numbers and symbols on the VFD.
  To use them, simply call Lua from the eLua shell, loading the program you want to try
  first:

# lua -l artvfd

or

# lua -l numvfd

  For each one of them, you will then have the following functions defined, that can be
  called from the interpreter command line or used in directly typed simple scripts:

#### Describe the functions ........

ART VFD

-- Blink all segments of all digits
function blinkall()

-- Wide dashes going up & down
function art1()

-- Wide dashes going up and paralell dashes comming down
function art2()

-- As art2() but digits are kept lit while going up or down
function art3()

-- Vertical dashes dancing
function art4()

-- A dash going all arround the digits' edges
function art5()

-- A dash going all arround the digits' edges and centers
function art6()

-- Show simultaneously each possible segment in a different digit
function art7()

-- Bubbles going "up" in random side positions
function bubble1()

-- Bubles on random sides and on random digit positions  
function bubble2()

-- Random seg pattern in a random digit position
function random1()

-- Random seg patterns in random digit positions  
function random2()

-- One dot, bouncing between the edges
function dots1()

-- One dot at a random digit position
function dots2()

-- Random number of dots at random digits positions
function dots3()

-- eLua written statically in the middle
function elua1()

-- eLua scrolls in both directions
function elua2()

-- Letters comming one by one from right to left
function elua3()





NumVFD

-- Upper counter right aligned
function num1()

-- Random 8 digit numbers right aligned
function num2()

-- The number Pi with 7 decimals
function pi()

-- The version number of eLua running on the platform
function eluaversion()

-- The version number of Lua running on the platform
function luaversion()