-
Notifications
You must be signed in to change notification settings - Fork 1
/
vfd.lua
executable file
·295 lines (252 loc) · 8.57 KB
/
vfd.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
--------------------------------------------------------------------------------
--
-- VFD - Vacuum Fluorescent Display tube control for eLua (www.eluaproject.net)
--
-- Implemented for IV-18 tubes and MAX6921 decoders
-- Pls see www.eluaproject.net for more details
--
-- Feb 2010
--
-- Dado Sutter, Fernando Araújo, Marcelo Politzer, Téo Benjamin
-- IV-18 Tubes were a gift from Bogdan Marinescu
--
--------------------------------------------------------------------------------
local pio, bit, tmr, pd, mbed = pio, bit, tmr, pd, mbed
local pairs, ipairs, collectgarbage = pairs, ipairs, collectgarbage
local strbyte, strsub = string.byte, string.sub
local mathmodf, mathfmod, mathlog10 = math.modf, math.fmod, math.log10
module (...)
-- Module and interface initialization
-- Can be called with an optional table parameter, with optional fields to
-- setup non-default values or configure unknown platform targets.
function init( t )
t = t or {}
WORD_SIZE = t.word_size or 17 -- Can be extended for multiple VFD control
if pd.board() == "ELUA-PUC" then
clk_pin = t.clk_pin or pio.P0_24
din_pin = t.din_pin or pio.P0_26
LOAD_PIN = t.load_pin or pio.P0_28
-- BLANK_PIN = t.blank_pin or pwm pin on blank ctrl to set intensity ....
elseif pd.board() == "EK-LM3S8962" then
clk_pin = t.clk_pin or pio.PC_5
din_pin = t.din_pin or pio.PG_0
load_pin = t.load_pin or pio.PC_7
elseif pd.board() == "STR-E912" then
clk_pin = t.clk_pin or pio.P6_0
din_pin = t.din_pin or pio.P6_1
load_pin = t.load_pin or pio.P6_2
elseif pd.board() == "MBED" then
clk_pin = t.clk_pin or mbed.pio.P5
din_pin = t.din_pin or mbed.pio.P6
load_pin = t.load_pin or mbed.pio.P7
--[[
elseif pd.board() == "EK-LM3S6965" then
clk_pin = t.clk_pin or
din_pin = t.din_pin or
load_pin = t.load_pin or
elseif pd.board() == "ELUA-PUC" then
clk_pin = t.clk_pin or
din_pin = t.din_pin or
load_pin = t.load_pin or
elseif pd.board == "ATEVK1100" then
clk_pin = t.clk_pin or
din_pin = t.din_pin or
load_pin = t.load_pin or
--]]
elseif ( clk_pin and din_pin and load_pin ) == nil then
error("vfd.init() does not know your platform and/or you haven't correctly specified clk_pin, din_pin or load_pin" )
end
pio.pin.setdir( pio.OUTPUT, clk_pin, load_pin, din_pin )
-- VFD chars table
-- Each value is the segment byte to write the key on vfd
-- Table is indexed by the chars
vfdc = { [ "0" ] = 0xFC,
[ "1" ] = 0x60,
[ "2" ] = 0xDA,
[ "3" ] = 0xF2,
[ "4" ] = 0x66,
[ "5" ] = 0xB6,
[ "6" ] = 0xBE,
[ "7" ] = 0xE0,
[ "8" ] = 0xFE,
[ "9" ] = 0xE6,
[ " " ] = 0x00,
[ "_" ] = 0x10,
[ "-" ] = 0x02,
[ "=" ] = 0x12,
[ "E" ] = 0x9E,
[ "L" ] = 0x1C,
[ "U" ] = 0x7C,
[ "A" ] = 0xEE,
[ "S" ] = 0xB6,
[ "O" ] = 0xFC,
[ "L" ] = 0x1C,
[ "P" ] = 0xCE,
[ "C" ] = 0x9C,
[ "I" ] = 0x60,
[ "F" ] = 0x8E
-- [ "." ] = 0x01, -- lit on the same digit of a char
}
-- Another VFD char table, now indexed by string.byte( char ), to avoid
-- creating too many orphan strings when indexing by string.sub
-- and forcing the garbage collector too soon
-- Only one of these tables (vfdc or vfdb) will be needed on final version
-- (probably vfdb)
vfdb = {}
for k, v in pairs( vfdc ) do
vfdb[ strbyte( k ) ] = v
end
vfdc = nil
collectgarbage()
clear()
end
--------------------------------------------------------------------------------
--
-- The main VFD segments rendering function
-- segs is 8 bit, with a, b, c, d, e, f, g, dp from msb to lsb
-- digits is 9 bits, with S1 left, ..., S8/right, sign/left again, from msb to lsb
--
--------------------------------------------------------------------------------
function set( segs, digits )
local data = bit.lshift( segs, 9 ) + digits
for i = WORD_SIZE - 1, 0, -1 do
pio.pin.setval( bit.isset( data, i ) and 1 or 0, din_pin )
pio.pin.sethigh( clk_pin )
pio.pin.setlow( clk_pin )
end
pio.pin.sethigh( load_pin )
pio.pin.setlow( load_pin )
end
-- Turn off all segments of all digits
function clear()
-- set( 0x00, 0x00 ) This was the old implementation
-- Now we send only the 9 digit zeros for faster execution
pio.pin.setval( 0, din_pin )
for i = 1, 9 do
pio.pin.sethigh( clk_pin )
pio.pin.setlow( clk_pin )
end
pio.pin.sethigh( load_pin )
pio.pin.setlow( load_pin )
end
-- Turn on all segments of all digits
function setall()
set( 0xFF, 0x1FF )
end
--[[
-------------------------------------------------------------------------------
-- Now a primitive to write numbers, symbols and possible letters.
-- We left some examples here but only one setstring() should be needed.
-- They should simply return some data and let the caller program control
-- the needed multiplexing of the segments and digits buses or they could
-- possibly do this in a coroutine-coordinated manner. But we decided to keep
-- the multiplexing control on them to ilustrate and keep things simple. A loop
-- at the end of each function multiplexes the segs/digits control and a second
-- argument "time" in each function controls the limits of this loop.
-- This was the initial implementation to write numbers
-- Will probably be replaced by the setstring (further down) for better
-- performance. Although it works nice, setnum() has too much math operations
-- and doesn't write letters or symbols
function setnum( num, time )
local nums =
{ [ 0 ] = 0xFC, 0x60, 0xDA, 0xF2, 0x66, 0xB6, 0xBE, 0xE0, 0xFE, 0xE6 }
local ndigits = mathmodf( mathlog10( num ) ) + 1 -- # of digits to write
local t = {}
for i = 1, ndigits do
t[ i ] = nums[ mathfmod( num, 10 ) ]
num = mathmodf( num / 10 )
end
for n = 1, time do
for i = 1, ndigits do
set( t[ i ], bit.bit( i - 1 ) )
end
end
end
-- This was the initial implementation to write "writeable" strings & numbers
-- It is simple and nice but it creates new strings when string.sub indexing
-- that become orphan, consuming RAM and triggering Garbage Collection sooner
-- or later.
function setstring1( str, time )
for n = 1, time do
for i = #str, 1, -1 do
set( vfdc[ strsub( str, -i, -i ) ], bit.bit( i - 1 ) )
end
end
end
-- This is an attempt to substitute setstring1 (above) and avoid orphan strings
-- overproduction. It doesn't seem to be much slower and it index the segments
-- table by numbers (string.byte). Not sure yet if it is worth though ...
function setstring2( str, time )
for n = 1, time do
for i = #str, 1, -1 do
set( vfdb[ strbyte( str, -i, -i ) ], bit.bit( i - 1 ) )
end
end
end
-- This is like setstring1 but now Dots are processed to become part of the
-- preceding number digit and not ugly rendered on an independent digit.
function setstring3( str, time )
local d = {}
local di = 1
local dotpending = false
for i = 1, #str do
local c = strsub( str, -i, -i )
if c ~= "." then
d[ di ] = vfdc[ c ]
if dotpending then
d[ di ] = d[ di ] + 0x01
dotpending = false
end
di = di + 1
else
dotpending = true
end
end
for n = 1, time do
for i = #d, 1, -1 do
set( d[ i ], bit.bit( i - 1 ) )
end
end
end
--]]
--------------------------------------------------------------------------------
--
-- The best current candidate for the setstring primitive
--
--------------------------------------------------------------------------------
function setstring( str, time )
local d = {} -- Segments set/lit for each vfd digit
local dotpending = false
for i = 1, #str do
local cb = strbyte( str, -i, -i ) -- character str.byte buffer
if cb ~= 46 then -- 46 = string.byte(".")
d[ #d + 1 ] = vfdb[ cb ]
if dotpending then
d[ #d ] = d[ #d ] + 0x01 -- set bit0 for dot/dp
dotpending = false
end
else
dotpending = true
end
end
-- now multiplex/show the digits for some time
for n = 1, time do
for i, v in ipairs( d ) do
set( v, bit.bit( i - 1 ) )
end
end
end
--[[
-- ## Some future functions for when pwm is beeing used to control intensity
-- on the BLANK_PIN
function hide()
pwm.setup( PWM_ID, PWM_CLK, 0 )
end
function show()
pwm.setup( PWM_ID, PWM_CLK, PWM_DUTY )
end
function setintensity( duty )
PWM_DUTY = duty
pwm.setup( PWM_ID, PWM_CLK, PWM_DUTY )
end
--]]