summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/devices/nld_ne555.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist/devices/nld_ne555.cpp')
-rw-r--r--src/lib/netlist/devices/nld_ne555.cpp286
1 files changed, 125 insertions, 161 deletions
diff --git a/src/lib/netlist/devices/nld_ne555.cpp b/src/lib/netlist/devices/nld_ne555.cpp
index dc6e3e5696a..a94d868373d 100644
--- a/src/lib/netlist/devices/nld_ne555.cpp
+++ b/src/lib/netlist/devices/nld_ne555.cpp
@@ -1,61 +1,17 @@
-// license:GPL-2.0+
+// license:BSD-3-Clause
// copyright-holders:Couriersud
-/*!
- * \file nld_NE555.cpp
- *
- * \page NE555 NE555: PRECISION TIMERS
- *
- * The Swiss army knife for timing purposes
- *
- * \section ne555_1 Synopsis
- *
- * \snippet devsyn.dox.h NE555 synopsis
- * \snippet devsyn.dox.h NE555_DIP synopsis
-
- * \section ne555_11 "C" Synopsis
- *
- * \snippet devsyn.dox.h NE555 csynopsis
- * \snippet devsyn.dox.h NE555_DIP csynopsis
- *
- * For the \c NE555 use verbose pin assignments like \c name.TRIG or \c name.OUT.
- * For the \c NE555_DIP use pin numbers like \c name.1.
- *
- * \section ne555_2 Connection Diagram
- *
- * <pre>
- * +--------+
- * GND |1 ++ 8| VCC
- * TRIG |2 7| DISCH
- * OUT |3 6| THRES
- * RESET |4 5| CONT
- * +--------+
- * </pre>
- *
- * Naming conventions follow Texas Instruments datasheet
- *
- * \section ne555_3 Function Table
- *
- * Please refer to the datasheet.
- *
- * \section ne555_4 Limitations
- *
- * Internal resistor network currently fixed to 5k.
- *
- * \section ne555_5 Example
- * \snippet ne555_astable.c ne555 example
- */
-
-#include "nld_ne555.h"
-#include "netlist/analog/nlid_twoterm.h"
-#include "netlist/solver/nld_solver.h"
+
+
+#include "analog/nlid_twoterm.h"
+#include "solver/nld_solver.h"
+
+#include "plib/pmath.h"
#define R_OFF (1E20)
-#define R_ON (25) // Datasheet states a maximum discharge of 200mA, R = 5V / 0.2
+#define R_ON (1)
+
+namespace netlist::devices {
-namespace netlist
-{
- namespace devices
- {
NETLIB_OBJECT(NE555)
{
NETLIB_CONSTRUCTOR(NE555)
@@ -64,35 +20,122 @@ namespace netlist
, m_R3(*this, "R3")
, m_ROUT(*this, "ROUT")
, m_RDIS(*this, "RDIS")
- , m_RESET(*this, "RESET") // Pin 4
- , m_THRES(*this, "THRESH") // Pin 6
- , m_TRIG(*this, "TRIG") // Pin 2
+ , m_RESET(*this, "RESET", NETLIB_DELEGATE(inputs)) // Pin 4
+ , m_THRES(*this, "THRESH", NETLIB_DELEGATE(inputs)) // Pin 6
+ , m_TRIG(*this, "TRIG", NETLIB_DELEGATE(inputs)) // Pin 2
, m_OUT(*this, "_OUT") // to Pin 3 via ROUT
, m_last_out(*this, "m_last_out", false)
, m_ff(*this, "m_ff", false)
, m_last_reset(*this, "m_last_reset", false)
+ , m_overshoot(*this, "m_overshoot", 0.0)
+ , m_undershoot(*this, "m_undershoot", 0.0)
+ , m_overshoot_limit(0.0)
{
- register_subalias("GND", m_R3.m_N); // Pin 1
- register_subalias("CONT", m_R1.m_N); // Pin 5
- register_subalias("DISCH", m_RDIS.m_P); // Pin 7
- register_subalias("VCC", m_R1.m_P); // Pin 8
- register_subalias("OUT", m_ROUT.m_P); // Pin 3
-
- connect(m_R1.m_N, m_R2.m_P);
- connect(m_R2.m_N, m_R3.m_P);
- connect(m_RDIS.m_N, m_R3.m_N);
- connect(m_OUT, m_ROUT.m_N);
+ register_sub_alias("GND", "R3.2"); // Pin 1
+ register_sub_alias("CONT", "R1.2"); // Pin 5
+ register_sub_alias("DISCH", "RDIS.1"); // Pin 7
+ register_sub_alias("VCC", "R1.1"); // Pin 8
+ register_sub_alias("OUT", "ROUT.1"); // Pin 3
+
+ connect("R1.2", "R2.1");
+ connect("R2.2", "R3.1");
+ connect("RDIS.2", "R3.2");
+ connect("_OUT", "ROUT.2");
}
- NETLIB_UPDATEI();
- NETLIB_RESETI();
+ NETLIB_RESETI()
+ {
+ /* FIXME make resistances a parameter, properly model other variants */
+ m_R1().set_R(nlconst::magic(5000));
+ m_R2().set_R(nlconst::magic(5000));
+ m_R3().set_R(nlconst::magic(5000));
+ m_ROUT().set_R(nlconst::magic(20));
+ m_RDIS().set_R(nlconst::magic(R_OFF));
+
+ m_last_out = true;
+ // Check for astable setup, usually TRIG AND THRES connected. Enable
+ // overshoot compensation in this case.
+ if (m_TRIG.net() == m_THRES.net())
+ m_overshoot_limit = nlconst::magic(0.5);
+ }
private:
- analog::NETLIB_SUB(R_base) m_R1;
- analog::NETLIB_SUB(R_base) m_R2;
- analog::NETLIB_SUB(R_base) m_R3;
- analog::NETLIB_SUB(R_base) m_ROUT;
- analog::NETLIB_SUB(R_base) m_RDIS;
+ NETLIB_HANDLERI(inputs)
+ {
+ // FIXME: assumes GND is connected to 0V.
+
+ const auto reset = m_RESET();
+
+ const nl_fptype v_threshold = clamp_hl(m_R2().P()(), nlconst::magic(0.7), nlconst::magic(1.4));
+ const nl_fptype v_trigger = clamp_hl(m_R2().N()(), nlconst::magic(0.7), nlconst::magic(1.4));
+
+ // avoid artificial oscillation due to overshoot compensation when
+ // the control input is used.
+ const auto overshoot_limit = std::min(m_overshoot_limit, std::max(0.0, (v_threshold - v_trigger) / 3.0));
+
+ if (!reset && m_last_reset)
+ {
+ m_ff = false;
+ }
+ else
+ {
+#if (NL_USE_BACKWARD_EULER)
+ const bool threshold_exceeded = (m_THRES() + m_overshoot > v_threshold);
+ const bool trigger_exceeded = (m_TRIG() - m_overshoot > v_trigger);
+#else
+ const bool threshold_exceeded = (m_THRES() + m_overshoot > v_threshold);
+ const bool trigger_exceeded = (m_TRIG() - m_undershoot > v_trigger);
+#endif
+ if (!trigger_exceeded)
+ m_ff = true;
+ else if (threshold_exceeded)
+ {
+ m_ff = false;
+ }
+ }
+
+ const bool out = (!reset ? false : m_ff);
+
+ if (m_last_out && !out)
+ {
+#if (NL_USE_BACKWARD_EULER)
+ m_overshoot += ((m_THRES() - v_threshold)) * 2.0;
+#else
+ m_overshoot += ((m_THRES() - v_threshold));
+#endif
+ m_overshoot = plib::clamp(m_overshoot(), nlconst::zero(), overshoot_limit);
+ //if (this->name() == "IC6_2")
+ // printf("%f %s %f %f %f\n", exec().time().as_double(), this->name().c_str(), m_overshoot(), m_R2.P()(), m_THRES());
+ m_RDIS().change_state([this]()
+ {
+ m_RDIS().set_R(nlconst::magic(R_ON));
+ });
+ m_OUT.push(m_R3().N()());
+ }
+ else if (!m_last_out && out)
+ {
+#if (NL_USE_BACKWARD_EULER)
+ m_overshoot += (v_trigger - m_TRIG()) * 2.0;
+ m_overshoot = plib::clamp(m_overshoot(), nlconst::zero(), overshoot_limit);
+#else
+ m_undershoot += (v_trigger - m_TRIG());
+ m_undershoot = plib::clamp(m_undershoot(), nlconst::zero(), overshoot_limit);
+#endif
+ m_RDIS().change_state([this]()
+ {
+ m_RDIS().set_R(nlconst::magic(R_OFF));
+ });
+ // FIXME: Should be delayed by 100ns
+ m_OUT.push(m_R1().P()());
+ }
+ m_last_reset = reset;
+ m_last_out = out;
+ }
+ NETLIB_SUB_NS(analog, R_base) m_R1;
+ NETLIB_SUB_NS(analog, R_base) m_R2;
+ NETLIB_SUB_NS(analog, R_base) m_R3;
+ NETLIB_SUB_NS(analog, R_base) m_ROUT;
+ NETLIB_SUB_NS(analog, R_base) m_RDIS;
logic_input_t m_RESET;
analog_input_t m_THRES;
@@ -102,98 +145,19 @@ namespace netlist
state_var<bool> m_last_out;
state_var<bool> m_ff;
state_var<bool> m_last_reset;
+ state_var<nl_fptype> m_overshoot;
+ state_var<nl_fptype> m_undershoot;
+ nl_fptype m_overshoot_limit;
- nl_double clamp(const nl_double v, const nl_double a, const nl_double b)
- {
- nl_double ret = v;
- nl_double vcc = m_R1.m_P();
-
- if (ret > vcc - a)
- ret = vcc - a;
- if (ret < b)
- ret = b;
- return ret;
- }
- };
-
- NETLIB_OBJECT_DERIVED(NE555_dip, NE555)
- {
- NETLIB_CONSTRUCTOR_DERIVED(NE555_dip, NE555)
+ nl_fptype clamp_hl(const nl_fptype v, const nl_fptype a, const nl_fptype b) noexcept
{
- register_subalias("1", "GND"); // Pin 1
- register_subalias("2", "TRIG"); // Pin 2
- register_subalias("3", "OUT"); // Pin 3
- register_subalias("4", "RESET"); // Pin 4
- register_subalias("5", "CONT"); // Pin 5
- register_subalias("6", "THRESH"); // Pin 6
- register_subalias("7", "DISCH"); // Pin 7
- register_subalias("8", "VCC"); // Pin 8
+ const nl_fptype vcc = m_R1().P()();
+ return plib::clamp(v, b, vcc - a);
}
};
- NETLIB_RESET(NE555)
- {
- m_R1.reset();
- m_R2.reset();
- m_R3.reset();
- m_ROUT.reset();
- m_RDIS.reset();
-
- /* FIXME make resistances a parameter, properly model other variants */
- m_R1.set_R(5000);
- m_R2.set_R(5000);
- m_R3.set_R(5000);
- m_ROUT.set_R(20);
- m_RDIS.set_R(R_OFF);
-
- m_last_out = true;
- }
-
- NETLIB_UPDATE(NE555)
- {
- // FIXME: assumes GND is connected to 0V.
-
- const auto reset = m_RESET();
-
- if (!reset && m_last_reset)
- {
- m_ff = false;
- }
- else
- {
- const nl_double vt = clamp(m_R2.m_P(), 0.7, 1.4);
- const bool bthresh = (m_THRES() > vt);
- const bool btrig = (m_TRIG() > clamp(m_R2.m_N(), 0.7, 1.4));
-
- if (!btrig)
- m_ff = true;
- else if (bthresh)
- m_ff = false;
- }
-
- const bool out = (!reset ? false : m_ff);
-
- if (m_last_out && !out)
- {
- m_RDIS.update();
- m_OUT.push(m_R3.m_N());
- m_RDIS.set_R(R_ON);
- }
- else if (!m_last_out && out)
- {
- m_RDIS.update();
- // FIXME: Should be delayed by 100ns
- m_OUT.push(m_R1.m_P());
- m_RDIS.set_R(R_OFF);
- }
- m_last_reset = reset;
- m_last_out = out;
- }
-
NETLIB_DEVICE_IMPL(NE555, "NE555", "")
- NETLIB_DEVICE_IMPL(NE555_dip, "NE555_DIP", "")
NETLIB_DEVICE_IMPL_ALIAS(MC1455P, NE555, "MC1455P", "")
- NETLIB_DEVICE_IMPL_ALIAS(MC1455P_dip, NE555_dip, "MC1455P_DIP", "")
- } //namespace devices
-} // namespace netlist
+
+} // namespace netlist::devices