Timer components—also known as delay or debounce components—are important elements in many embedded systems. Timers keep track of of how much time has elapsed while a condition is active and only change their output after the condition has been held continuously for a specified period.
There are a huge number of different behaviors and implementations for timer components that are needed in real-world systems. As with the other components included in this example project, these timer components are only intended as example definitions that can be modified or customized to fit the needs of a particular situation.
While it is hard to speak generically about timer components due to their great variety, most timers can be broken down into two basic parts: a counter and a threshold. The counter records the duration for which a condition has been satisfied, while the threshold checks whether enough time has passed on the counter for the timer’s output to change.
Timer On and Timer Off¶
The Timer On component is a simple timer that can be used to implement logic of the form “some action shall happen if some variable has been true continuously for some period of time”. Its output starts out false. The output value changes to true if the input is held true for DT consecutive seconds, where DT is a floating-point input. If, at any point, the input is set to false, the output will immediately become false.
The Timer Off component does the exact opposite: it transitions from false to true as soon as the input becomes true, but requires the input to be false for DT seconds to transition from true to false.
The behavior of the Timer On and Timer Off components is summarized by the following rules:
- The Timer On component outputs true if the input was true at all times in the past DT seconds.
- The Timer Off component outputs true if the input was true at any time in the past DT seconds.
Internally, the example Timer On and Timer Off components are implemented in the fashion mentioned above: a counter and a comparison against a threshold. Within this basic structure, there are many choices that can be made when implementing the Timer On and Timer Off components, which can give slightly different behaviors.
A lot of the potential for variation in implementations comes from deciding what exactly “the past DT seconds” means in the two rules above. CertSAFE does not impose a notion of real-world time onto its discrete-time frame-based simulation, other than providing a user-definable frames per second value and labeling frames using this value. It is easy to make fencepost errors when modeling if you do not have a specific concept in mind of how time works. Also, the example components allow the value of DT to change over the course of a simulation, so the behavior as DT changes needs to be defined. (If you would like to disallow the DT input from changing over time, you can set the Constness property the DT Exported Name components in the timer diagrams to must be constant.)
In order to specify the precise behavior of the timer components, we need to choose a semantics of how CertSAFE simulation frames correspond to real-world time. The example implementations behave according to the following semantics:
- The value of the input at a nonnegative real time \(t\) is defined to be the value of the input at the frame with the greatest time less than or equal to \(t\). In other words, the \(i\)-th frame of a simulation (zero-indexed) covers the half-open interval \([fi, f(i + 1))\), where \(f\) is the length of a frame in seconds (the reciprocal of the frames per second value).
- At negative times (before the start of the simulation), the input value is treated as if it were false.
- When computing the output of a timer for frame \(i\), “the past \(DT\) seconds” is considered to consist of the closed interval \([fi - DT, fi]\).
- \(DT\) values less than zero are treated as if they were zero.
These choices have some interesting consequences:
- If given a \(DT\) value of zero, both the Timer On and Timer Off components reduce to the identity function (the output is equal to the input). This is because we are checking the closed interval \([fi - 0, fi]\), which consists of a single point in time, namely the start of the current frame \(fi\).
- \(DT\) values that are not an integer multiple of the length of a frame are effectively rounded up to the next frame. This is because the value of frame \(i\) remains constant during the entire duration \([fi, f(i + 1))\).
- If the \(DT\) value is increased partway through a simulation, a Timer On component can go from false to true to false to true again with the input being held true the entire time. The same applies for a Timer Off going from true to false to true to false if the input starts as true and then is changed and held at false. See Fig. 10.
It is perfectly reasonable to interpret time in CertSAFE according to different rules than the ones given above. This is simply a particular set of rules that seems to work for a reasonably large number of cases. Other interpretations can be adopted by writing different implementations for the timer components.
The Timer On/Off component combines the behaviors of the Timer On and Timer Off components. If the output of the component is currently false, it will transition to true if the input is held true for a time exceeding DT on seconds. Conversely, if the output of the component is currently true, it will transition to false if the input is held false for a time exceeding DT off seconds. The Timer On/Off component is suitable for modeling hysteresis behavior where the current output is “sticky” and only changes if the input has been different from the output continuously for some period of time.
Compared to the Timer On and Timer Off components, the Timer On/Off actually works rather differently. The Timer On/Off internally contains a small state machine that represents whether the component is currently on or off—that is, whether its output is currently true or false. There is an IC (initial condition) pin that determines the components’ state the first time it is executed. The state only changes when the input has been different from the output for greater than the required amount of time. In particular, the Timer On/Off has no analogue of the case shown in Fig. 10 where the timer goes from having elapsed to not having elapsed due to the value of the DT input increasing—once the internal state has changed, it will only switch back if the input is changed back to the original value and held there for the required period of time.
The example Timer On/Off implementation in this project uses two separate timer components internally: one that is used in the on state, and one that is used in the off state. It is also possible to implement the same behavior using a single counter and a threshold condition that changes depending on whether the timer is currently in the on state or the off state, although this is somewhat more complicated to write out explicitly.
Frames To Seconds and Seconds To Frames¶
These components convert between time in frames and time in seconds, represented as floating point values. The conversions are performed by multiplying or dividing by the project frames per second value, obtained from the Frames Per Second primitive component. These components are not timers themselves, but are used in the implementations of the timers described above, and can also be used to implement other components that work with real-world time units.