DLI DIN4 User's Guide
|
The DIN4 has user-defined input/output facilities which can be used from the web UI, REST API or user scripts. The "Input/Output" main menu item leads you to the page allowing you to control the pins and ports (if they're present on your power controller model).
The DIN4 has pins with customizable behaviour which may be connected by nets to perform real-time operations.
I/O pins have mode and level 'driver' parameters. Those dictate how the pin's active/tristate mode and high/low level are calculated. Some of the drivers can be locked by the hardware (e.g. open collector outputs have their level fixed at 'low', you can only switch the mode from tristate to active) so you won't be able to change them. Otherwise, they can be set to Active (High for level) or Tristate (Low for level) or to a name of a signal net (see below); then the pin's characteristic will depend on the value of the named net's value.
The input/mode/level signal bits table in pin properties indicates pin's capabilities. If input bit count is 0, the pin is output-only so it makes no sense trying to read it. If mode or level bit counts are 0, the corresponding configuration value is locked by the hardware and cannot be modified.
Usually, pins in Tristate High state are pulled up; pins in Tristate Low state aren't. Pin properties give a summary of what configurations the pin can assume, i.e. how the mode and level drivers are mapped to IEEE1164 signal states '0' (Forcing 0, ), '1' (Forcing 1,
), 'L' (Weak 0,
), 'H' (Weak 1,
) and 'Z' (High impedance,
). Available stable pin states can be activated by clicking the related icons next to their names. Current states are indicated by highlighted icons (
,
,
,
,
). Unavailable pin states are indicated by dimmed icons (
,
,
,
,
). States not available for any of the device's pins are left out for all of them.
The icon can be used to open detailed pin properties and configure mode and level drivers using signal nets (see below). The
icon indicates that the pin's mode or level is controlled by a net. The
icon indicates that the pin's mode and level are locked by hardware and cannot be changed.
Driver values for mode and level (depending on the pin's capabilities) can be selected here; choosing a net as a driver will activate the parameter if the net value is nonzero, and deactivate it if the net value is zero. Confirm your changes with .
Nets are what you use when you want to have more complex pin behaviour (and also to read input pin levels as a useful side effect). A net has a value which can be assigned manually or computed using pin input values and values of nets in the previous cycle. Pins' levels and modes can be controlled by nets, with built-in transition safety (i.e. switching from pullup to active low and back will avoid the active high state). You may also receive change notifications for signal nets in user scripts.
A net's name can consist of alphanumerics, the underscore '_' and the pound sign '#' (useful for marking inverted logic).
Net names starting with the double underscore ('__') are reserved and should not be referenced or modified by users.
Net expressions are essentially characteristic equations for the nets in question.
Net values, and intermediate values appearing in a net expression, are N
-bit integers. They are interpreted by arithmetic and comparison operations to be signed in two's complement notation.
The special value -2^(N-1)
('100...0', the smallest normally representable signed integer value) is reserved to encode 'Not-a-Number' values. The value is handled specially by built-in arithmetic operators, but not logical, bitwise or comparison operators. In particular, arithmetic on Not-a-Number operands yields Not-a-Number (propagation), Not-a-Number == Not-a-Number holds, and Not-a-Number compares smaller than any valid number. The maximum/minimum representable valid values are, therefore, 2^(N-1)-1
and -2^(N-1)+1
, respectively.
Net expression syntax is a subset of Lua syntax with the following limitations stemming from the nature of signal net definition which has to do with manipulating multibit signals:
The following details concern arithmetic operators and are intended to make operation fully defined and predictable as well as compatible with Lua and expected behaviour:
Explicit bitwise addition/subtraction semantics (two's complement, wrap-around, ignoring saturation and Not-a-Number values) can be requested by using the corresponding special functions (see below).
The API is comprised of literals nil
and false
(corresponding to the integer value 0) and true
(corresponding to the integer value 1) and the following operators and globals:
Operator | Global | Evaluates to |
x and y | land(x,y) | logical AND of x and y |
x or y | lor(x,y) | logical OR of x and y |
lxor(x,y) | logical XOR of x and y | |
x & y | band(x,y) | bitwise AND of x and y |
x | y | bor(x,y) | bitwise OR of x and y |
x ~ y | bxor(x,y) | bitwise XOR of x and y |
x << y | shl(x,y) | x, shifted left by y bits |
x >> y | shr(x,y) | x, shifted right by y bits |
x + y | add(x,y) | x + y |
x - y | sub(x,y) | x - y |
x * y | mul(x,y) | x * y |
x / y | div(x,y) | x / y |
x // y | idiv(x,y) | x / y treated as integer |
x % y | mod(x,y) | x % y |
x == y | eq(x,y) | 1 if x == y and 0 otherwise |
x ~= y | neq(x,y) | 0 if x == y and 1 otherwise |
x < y | lt(x,y) | 1 if x < y and 0 otherwise |
x > y | gt(x,y) | 1 if x > y and 0 otherwise |
x <= y | le(x,y) | 1 if x <= y and 0 otherwise |
x >= y | ge(x,y) | 1 if x >= y and 0 otherwise |
not x | lnot(x) | 1 if x == 0 and 0 otherwise |
~x | bnot(x) | bitwise NOT of x (all bits inverted) |
-x | neg(x) | 0-s complement of x (all bits inverted+1) |
iff(cond,t,f) | f if cond == 0 and t otherwise | |
badd(x,y) | x + y with bitwise semantics | |
bsub(x,y) | x - y with bitwise semantics | |
pin[name] | the value of the named pin (name must be a string constant) | |
net[name] | the value of the named net (name must be a string constant) | |
apin[name] | the value of the named pin interpreted as an analog signal (see below) | |
anet[name] | the value of the named net interpreted as an analog signal (see below) |
So, every net can reference pins (reading their input values), or nets (including itself). It is not a syntax error to reference a nonexisting net (otherwise complex schemes wouldn't be possible to enter a net at a time) or a nonexisting or unreadable pin, but such references return the value 0 (until, in the case of a net, it appears).
Standard Lua syntax rules apply to net[]
, etc. indexing operations, so you can address net q1
as net["q1"]
or net.q1
, but net #R
only as net["#R"]
.
Every net output is latched, that is, it is stored in a memory area on every step. When a net's value is read to compute another net's value, the previous step's value is used, so e.g. an expression 'not net.Q
' for net Q
makes sense, and produces a rapidly oscillating output. On creation, all net values are initialized with the value 0.
This latching behaviour allows for edge detection, e.g. if you have net Q
you can create a helper net Q_
which copies it and introduces a one-step delay as a side effect:
Q_: net.Q
and add edge-detecting nets:
Q_rise: net.Q and not net["Q_"] Q_fall: not net.Q and net["Q_"]
Due to this latching behaviour, situations which have a diminishing probability in real-life circuits can happen with certainty in emulated circuits. For instance, consider that you already have nets #R
and #S
and want to produce an SR latch on two NAND logical elements. If you naively follow the classic schematic and create the two nets:
Q: not (net["#S"] and net["#Q"]) #Q: not (net["#R"] and net["Q"])
at once, the following will happen (considering #R
and #S
are both 1
, i.e. hold state):
Q
and #Q
start out with value 0
;Q
and #Q
assume the value 1
because not (1 and 0) = 1
;Q
and #Q
assume the value 0
because not (1 and 1) = 0
;The result is not state being held, but an oscillation! If you have configured the nets in question for change reporting, the DIN4 may become slow to respond. In a real device, the signal propagation times would never be exactly equal so the situation would be resolved into one of the stable states, but this is not so in emulation.
One possible advice on avoiding such situations is to use the minimum number of nets. E.g. a similar latch could be produced by the following net (replacing net["#Q"]
in the expression for Q
with the expression for #Q
):
Q: not (net["#S"] and not (net["#R"] and net["Q"]))
or, equivalently,
Q: (net["#R"] and net["Q"]) or not net["#S"]
It has a single positive feedback loop and doesn't exhibit the above problem. It also explicitly makes #S
dominate #R
(in case of conflict, Q
is 1). If you want #R
to dominate, all you need is move the parentheses:
Q: net["#R"] and (net["Q"] or not net["#S"])
The GPIO net resource usage is displayed at the bottom of the page. Attempts to use more resources than there are available will result in failures (visible in the system log). You may need to refresh the page after reconfiguring nets or pins to obtain up-to-date information.
The DIN4 has a 16-bit counter incremented at 57600 Hz (note that the frequency is in general model-specific). It is exposed as a special input pin named clk
. Delay-sensitive activities can use this pin to derive other timing-related signals. You may need to create nets holding previous signal values to account for overflows.
For example, to create a counter that increments at 100 Hz, create the following nets:
clkz
with expression pin.clk
which will hold the previous clock value;tck
with expression (net.tck+(bsub(pin.clk,net.clkz)&65535))%(57600//100)
which will overflow every 100Hz (note that it's self-referential);tckz
with expression net.tck
which will hold the previous tck
value;cnt
with expression badd(net.cnt,net.tck<net.tckz)
which will increment on every tck
overflow, i.e. every 100 Hz.Note that cnt
will be a binary counter with wraparound.
Analog signals (e.g. ones read from an ADC channel or an external sensor) are commonly presented in a fixed-point format as signed two's complement integers with the upper half storing the integer part, and the lower half storing the fractional part. The values of the readings match those in e.g. scripting meter.values[key].value
, that is, they are the physical values measured by the channel or sensor, expressed in SI units (e.g. volts for voltage, degrees Kelvin for temperature, etc.). To handle pin or net signals in this format, reference them using apin[]
or anet[]
instead of pin[]
and net[]
, respectively.
Literals representing analog signals may need to explicitly include the dot '.' or the exponent symbol ('e' or 'E') to be treated as such; '3/2' yields '1' as an integer but '3./2' or '3.0/2' or '3e0/2' yield '1.5' in a fixed-point format.
Additionally, analog pins represent readings
from a disconnected sensor as Not-a-Number. Not-a-Number == Not-a-Number holds in net code, so a way to explicitly check for signal presence could be e.g. apin[...]~=0./0
. The '.' is essential to indicate an analog Not-a-Number (matching the format of the analog pin reading).
Analog signal representation matters when analog signals are operands of arithmetic or comparison operators. To ensure proper operation, it's required to use the apin[]
/anet[]
('a' for 'analog') symbols to address the pins or nets you want to treat as such.
You may get a warning if you address a pin or net incorrectly (using e.g. pin
instead of apin
or vice versa), but otherwise this distinction is not enforced, since you may have reasons to reinterpret a value.
While the primary use case for signal nets is driving output signals in close-to-real time, their values can also be reported to the main system for handling in user scripts or debugging.
The following reporting modes are supported:
A net's latest value is updated only as long as reporting is enabled for it by choosing one of the above modes.
Note that nets that change often (e.g. fast counters, ADC readings, etc.) may overload the system in change reporting mode; under overload, some of the change notifications will be dropped, so that only the most recent value out of several successive change notifications will be seen. Note that the reporting process itself takes up processing time, so net updates may become several times slower under load as well.
Consider the following options, or combinations thereof, to reduce load:
For example, suppose you need your user script to act on the value of the analog pin adc1
. The following nets could be used:
n0
= apin.adc1
(naive reading, will cause likely unnecessary load in change reporting mode, not recommended);n1
= apin.adc1 >= 3.0
(naive threshold);n2
= iff(apin.adc1 >= 3.1,true,iff(apin.adc1 <= 2.9, false, net.n2)
(threshold with hysteresis);n3
= iff(apin.adc1 > anet.n3 + 0.1 or apin.adc1 < anet.n3 - 0.1, apin.adc1, anet.n3)
(updates conditional on minimal change threshold).Alternately, suppose you need to act on the value of the digital pin in1
connected to a physical switch. The following sample net combinations could be used:
n1
= pin.in1
(naive reading, will see contact chatter and cause likely unnecessary load in change reporting mode, not recommended);hist
= (pin.in1 | (net.hist << 1)) & 0xFF
(keeping track of pin state history) and net n1
= iff(net.hist == 0xFF, true, iff(net.hist == 0, false, net.n1)
(changing state only when the previous 8 states agree);sum
= iff(pin.in1 and net.sum < 8, net.sum + 1, iff(not pin.in1 and net.sum > 0, net.sum - 1, net.sum))
(keeping track of pin state history) and net n1
= iff(net.sum >= 6, true, iff(net.sum <= 2, false, net.n1)
(changing state with hysteresis depending on previous states).Refer to scripting documentation for further details on accessing the values.