<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>HAL Components on STMBLv5 Documentation</title><link>https://freakontrol.github.io/stmbl/docs/hal_components/</link><description>Recent content in HAL Components on STMBLv5 Documentation</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://freakontrol.github.io/stmbl/docs/hal_components/index.xml" rel="self" type="application/rss+xml"/><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/acim_flux/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/acim_flux/</guid><description>&lt;h1 id="acim_flux">
 ACIM_FLUX
 &lt;a class="anchor" href="#acim_flux">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>acim_flux&lt;/code> component models the rotor flux of an induction motor in the
rotor flux frame and gives the slip that keeps that frame oriented.&lt;/p>
&lt;h2 id="model">
 Model
 &lt;a class="anchor" href="#model">#&lt;/a>
&lt;/h2>
&lt;p>With i_mr the magnetizing current behind the rotor flux (psi_r = Lm * i_mr):&lt;/p>
&lt;p>tr * d(i_mr)/dt = id - i_mr
slip = iq / (tr * i_mr) [rad/s electrical]
torque = 3/2 * pp * lmr * i_mr * iq lmr = Lm^2 / Lr&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/acim_foc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/acim_foc/</guid><description>&lt;h1 id="acim_foc">
 ACIM_FOC
 &lt;a class="anchor" href="#acim_foc">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>acim_foc&lt;/code> component turns a torque command into d and q current
commands for an induction motor in the rotor flux frame, using the flux
model of acim_flux.&lt;/p>
&lt;h2 id="behaviour">
 Behaviour
 &lt;a class="anchor" href="#behaviour">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>d: &lt;code>id_n * scale&lt;/code> (scale from acim_fw, 1 below the corner), reached at
&lt;code>id_rate&lt;/code> A/s from 0 at every enable, so the bridge never steps the full
magnetizing current into one leg.&lt;/li>
&lt;li>Torque is held at 0 (&lt;code>ready&lt;/code> = 0, t_max = 0) until i_mr has reached 90% of
the d command once; after that &lt;code>ready&lt;/code> stays 1 until the next disable.&lt;/li>
&lt;li>q: torque / (3/2 * pp * lmr * i_mr), limited so |i| stays within max_cur
with d taking priority.&lt;/li>
&lt;li>Flux boost (optional, &lt;code>k_boost&lt;/code> &amp;gt; 0): while the flux is below the
ramped d command, d gets k_boost * (d - i_mr) on top, so i_mr rises in
about tr / (1 + k_boost) instead of tr: faster torque after field
weakening and a shorter magnetizing at enable. Only upward; going into
field weakening is not sped up, so the acim_fw loop keeps its gain. The
boost only takes current q does not need: |d| &amp;lt;= sqrt(max_cur^2 - q^2),
and with &lt;code>boost_max&lt;/code> &amp;gt; 0 never more than boost_max * id_n on top of d
(0.3 keeps the enable peak near the current limit).&lt;/li>
&lt;li>t_max: torque the current limit allows at the present flux, capped by
acim_fw&amp;rsquo;s t_lim when that is nonzero. Link pid0.max_torque and
pid0.neg_min_torque to it.&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>en&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, fault0.en_out&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>torque&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, torque command [Nm]&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>scale&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, flux fraction from acim_fw, 1 = rated&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>t_lim&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, torque limit from acim_fw [Nm], 0 = none&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>i_mr&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, magnetizing current from acim_flux [A]&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>id_n&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, rated magnetizing current [A peak]&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>id_rate&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, d current ramp [A/s]&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>max_cur&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, current limit [A peak]&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>lmr&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Lm^2/Lr [H]&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>polecount&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, pole pairs&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>k_boost&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, flux boost gain, 0 = off&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>boost_max&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, largest boost as a fraction of id_n, 0 = only the current limit&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>d_cmd&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, to hv0.d_cmd&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>q_cmd&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, to hv0.q_cmd&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>t_max&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, available torque [Nm]&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>t_min&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, -t_max&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>ready&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, 1 = magnetized, torque allowed&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>boost&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, d current added by the flux boost [A]&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/acim_foc.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/acim_fw/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/acim_fw/</guid><description>&lt;h1 id="acim_fw">
 ACIM_FW
 &lt;a class="anchor" href="#acim_fw">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>acim_fw&lt;/code> component is the induction motor&amp;rsquo;s field weakening: it lowers
the flux command (&lt;code>scale&lt;/code>, 1 = rated flux) to hold the modulation &lt;code>duty&lt;/code> at
&lt;code>duty_setpoint&lt;/code>, and gives a constant power torque limit &lt;code>t_lim&lt;/code>.&lt;/p>
&lt;p>This is acim_ttc&amp;rsquo;s regulator on its own. &lt;code>duty&lt;/code> unlinked reads 0, so scale
sits at 1 and there is no field weakening, which is stmbl&amp;rsquo;s default; linking
&lt;code>acim_fw0.duty = hv0.duty&lt;/code> is the machine builder&amp;rsquo;s choice.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/acim_ttc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/acim_ttc/</guid><description>&lt;h1 id="acim_ttc">
 ACIM_TTC
 &lt;a class="anchor" href="#acim_ttc">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>acim_ttc&lt;/code> component is responsible for controlling an AC Induction Motor (ACIM) using Torque and Flux control strategies. It reads motor parameters and control settings, calculates derived parameters, updates the control algorithm in real-time, and supports different operating modes. The component ensures that the motor operates within safe and efficient boundaries by adjusting the velocity, position, and torque limits accordingly.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>acim_ttc&lt;/code> component is designed for controlling an AC Induction Motor (ACIM) using Torque and Flux control strategies. This component operates within a hardware abstraction layer (HAL) framework, providing real-time control and non-real-time initialization functions.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/adc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/adc/</guid><description>&lt;h1 id="adc">
 ADC
 &lt;a class="anchor" href="#adc">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>adc&lt;/code> (F4 logic board) converts the raw sin/cos samples of the two feedback connectors, which the ADCs capture by DMA, into scaled sin/cos values for the feedback components, and can stream the raw samples to Servoterm as a scope. The feedback templates wire it, e.g. conf/template/res_fb0.txt (&lt;code>res0.sin = adc0.sin0&lt;/code>, &lt;code>res0.cos = adc0.cos0&lt;/code>, &lt;code>res0.quad = adc0.quad&lt;/code>, &lt;code>adc0.res_mode = res0.res_mode&lt;/code>) and conf/template/enc_fb0.txt (&lt;code>enc_fb0.sin = adc0.sin0l&lt;/code>, &lt;code>enc_fb0.cos = adc0.cos0l&lt;/code>, &lt;code>enc_fb0.amp = adc0.amp0&lt;/code>).&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/and/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/and/</guid><description>&lt;h1 id="and">
 AND
 &lt;a class="anchor" href="#and">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>and&lt;/code> is a four input logic AND. F4 component, used e.g. in &lt;code>conf/bene_sanyo.txt&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Output&lt;/strong> (&lt;code>rt&lt;/code>):&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>out&lt;/code> = 1 if all of &lt;code>in0&lt;/code>..&lt;code>in3&lt;/code> are &amp;gt; 0, otherwise 0.&lt;/li>
&lt;li>Unused inputs default to 0, so they must be set to 1 (e.g. &lt;code>and0.in3 = 1&lt;/code>).&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in0&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Logic input, true if &amp;gt; 0&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in1&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Logic input, true if &amp;gt; 0&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in2&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Logic input, true if &amp;gt; 0, set to 1 if unused&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in3&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Logic input, true if &amp;gt; 0, set to 1 if unused&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, 1 if all inputs are &amp;gt; 0&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/and.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/angle/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/angle/</guid><description>&lt;h1 id="angle">
 ANGLE
 &lt;a class="anchor" href="#angle">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>angle&lt;/code> component owns the commutation angle and the synchronous
electrical speed sent to hv0 (&lt;code>hv0.pos&lt;/code>, &lt;code>hv0.vel&lt;/code>), for every motor type.&lt;/p>
&lt;h2 id="sources-src">
 Sources (&lt;code>src&lt;/code>)
 &lt;a class="anchor" href="#sources-src">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>0 feedback: &lt;code>pos = pos_fb&lt;/code>, &lt;code>vel = vel_fb&lt;/code>. A pure pass-through, used by
the PMSM templates (pos_fb = vel2.pos_out or pmsm_ttc0.pos_out, vel_fb =
vel2.vel).&lt;/li>
&lt;li>1 feedback plus slip: &lt;code>pos = pos_m * polecount + integral of slip&lt;/code>,
&lt;code>vel = vel_m * polecount + slip&lt;/code>. Indirect field orientation for an
induction motor on an encoder: pos_m is the mechanical rotor angle,
vel_m the mechanical rotor speed, slip comes from acim_flux. The angle
is built from the encoder, not from vel_m, so the lag of a speed
estimate during a ramp does not show up as a lower slip.&lt;/li>
&lt;li>2 observer: &lt;code>pos = pos_obs&lt;/code>, &lt;code>vel = vel_obs&lt;/code>.&lt;/li>
&lt;li>3 open loop: &lt;code>vel = vel_cmd&lt;/code> (electrical), &lt;code>pos&lt;/code> integrates it. V/f and I/f.&lt;/li>
&lt;/ul>
&lt;p>Switching into an integrating source (1, 3) starts from the current angle,
so the switch itself does not move the field. Switching into 0 or 2 takes
the source&amp;rsquo;s angle as is; a sequencer that switches onto the observer is
expected to do it once the observer has locked.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/avg/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/avg/</guid><description>&lt;h1 id="avg">
 AVG
 &lt;a class="anchor" href="#avg">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>avg&lt;/code> scales and offsets a signal and low pass filters it (first order). F4 component, typically used to turn an analog spindle speed input into a velocity command, e.g. &lt;code>avg0.mult = 0.1047&lt;/code> (rpm to rad/s), &lt;code>ramp0.vel_ext_cmd = avg0.out&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Output&lt;/strong> (&lt;code>rt&lt;/code>):&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>out &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">LP&lt;/span>(in &lt;span style="color:#f92672">*&lt;/span> mult &lt;span style="color:#f92672">+&lt;/span> offset) &lt;span style="color:#75715e">// first order low pass at lpf Hz
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Until &lt;code>mult&lt;/code> is set the output is only &lt;code>offset&lt;/code>.&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Signal&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Filtered in * mult + offset&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>lpf&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Filter cutoff (Hz), default 100&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>mult&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Multiplier, no default (0)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>offset&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Offset added after mult, default 0&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/avg.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/biquad/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/biquad/</guid><description>&lt;h1 id="biquad">
 BIQUAD
 &lt;a class="anchor" href="#biquad">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>biquad&lt;/code> is a second order filter for a command signal, typically a notch on the torque command at a mechanical resonance. &lt;code>conf/template/filters.txt&lt;/code> loads it (opt-in, &lt;code>link filters&lt;/code> after &lt;code>link pmsm&lt;/code>) between &lt;code>pid0&lt;/code> and &lt;code>dob0&lt;/code>, passing through (&lt;code>type&lt;/code> 0) until set. The wiring, by hand or as in the template:&lt;/p>
&lt;ul>
&lt;li>&lt;code>biquad0.in = pid0.torque_cmd&lt;/code>&lt;/li>
&lt;li>&lt;code>pmsm_ttc0.torque = biquad0.out&lt;/code> (the template: &lt;code>dob0.in = biquad0.out&lt;/code>)&lt;/li>
&lt;li>&lt;code>biquad0.rt_prio = 8.3&lt;/code> (after &lt;code>pid0&lt;/code>, before &lt;code>dob0&lt;/code> and the torque controller)&lt;/li>
&lt;/ul>
&lt;p>&lt;code>frf&lt;/code> (&lt;code>conf/template/id_frf.txt&lt;/code>) goes after &lt;code>biquad0&lt;/code> when both are loaded.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/conf/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/conf/</guid><description>&lt;h1 id="conf">
 CONF
 &lt;a class="anchor" href="#conf">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>conf&lt;/code> has no code: it is a set of named parameter pins that hold the motor, feedback, limit and tuning values of a drive in one place. A motor config sets them (conf/template/conf.txt shows the defaults a new config starts from, e.g. &lt;code>conf0.r = 1&lt;/code>, &lt;code>conf0.max_ac_cur = 6&lt;/code>), and the templates link them to the components that use them, e.g. &lt;code>hv0.r = conf0.r&lt;/code>, &lt;code>pid0.pos_bw = conf0.pos_bw&lt;/code>, &lt;code>fault0.max_dc_volt = conf0.max_dc_volt&lt;/code>, &lt;code>fb_switch0.mot_offset = conf0.mot_fb_offset&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/curpid/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/curpid/</guid><description>&lt;h1 id="curpid">
 CURPID
 &lt;a class="anchor" href="#curpid">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>curpid&lt;/code> is the d/q current controller. From a d/q current command and the measured d/q currents it computes the d/q voltages with a PI controller plus resistance, back EMF and cross coupling feed forward and a predictor for the PWM delay. It also limits the current command to &lt;code>max_cur&lt;/code>. In voltage mode it passes the command through as a voltage. It runs on the F3 (HV board) as &lt;code>curpid0&lt;/code>, loaded by &lt;code>stm32f303/src/main.c&lt;/code> (rt_prio 3). There all its inputs come from &lt;code>ls0&lt;/code> (the F4&amp;rsquo;s command and motor config) and &lt;code>dq0&lt;/code> (measured currents), and &lt;code>ud&lt;/code>/&lt;code>uq&lt;/code> go to &lt;code>idq0&lt;/code>. No F4 template loads it.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/dc_limits/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/dc_limits/</guid><description>&lt;h1 id="dc_limits">
 DC_LIMITS
 &lt;a class="anchor" href="#dc_limits">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>dc_limits&lt;/code> is the brushed DC motor version of &lt;code>pmsm_limits&lt;/code>: it estimates the armature current and torque that can be reached with the available voltage, at standstill, at the present velocity and within the next control period. It is compiled into the F4 firmware.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;p>All work is done in &lt;code>rt&lt;/code>. Inputs are clamped to &lt;code>lq &amp;gt;= 0.0001&lt;/code>, &lt;code>psi &amp;gt;= 0.01&lt;/code>, &lt;code>r &amp;gt;= 0.001&lt;/code>. The back EMF is &lt;code>indq = vel * psi&lt;/code> and &lt;code>volt = ac_volt&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/dc_ttc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/dc_ttc/</guid><description>&lt;h1 id="dc_ttc">
 DC_TTC
 &lt;a class="anchor" href="#dc_ttc">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>dc_ttc&lt;/code> (torque to current) converts a torque command (Nm) into an armature current command (A) for a brushed DC motor. It runs on the F4 board and is loaded by &lt;code>conf/template/dc.txt&lt;/code>: &lt;code>dc_ttc0.torque = pid0.torque_cmd&lt;/code>, &lt;code>dc_ttc0.psi = conf0.psi&lt;/code>, &lt;code>hv0.q_cmd = dc_ttc0.cur&lt;/code> with &lt;code>hv0.phase_mode = 3&lt;/code> (DC output) and &lt;code>hv0.cmd_mode = 1&lt;/code> (current mode).&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Conversion&lt;/strong> (in &lt;code>rt&lt;/code>): &lt;code>cur = torque / psi&lt;/code>, with &lt;code>psi&lt;/code> (equal to the back EMF constant in V/(rad/s)).&lt;/li>
&lt;/ol>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>psi&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Torque constant (Nm/A), min 0.001&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>torque&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Torque command (Nm)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>cur&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Current command (A)&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/dc_ttc.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/debounce/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/debounce/</guid><description>&lt;h1 id="debounce">
 DEBOUNCE
 &lt;a class="anchor" href="#debounce">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>debounce&lt;/code> filters a logic signal with an integrating timer, so short pulses are ignored. F4 component, used in &lt;code>conf/wobl.txt&lt;/code> (&lt;code>fault0.en = debounce0.out&lt;/code>).&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Timer&lt;/strong> (&lt;code>rt&lt;/code>):&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>timer&lt;/code> counts up by the period while &lt;code>in&lt;/code> &amp;gt; 0 and down otherwise.&lt;/li>
&lt;li>When &lt;code>timer&lt;/code> exceeds &lt;code>debounce_time&lt;/code>, &lt;code>out&lt;/code> becomes 1 (and &lt;code>timer&lt;/code> is clamped to &lt;code>debounce_time&lt;/code>). When &lt;code>timer&lt;/code> reaches 0, &lt;code>out&lt;/code> becomes 0.&lt;/li>
&lt;li>The delay is the same for both edges; short glitches only move the timer and do not change &lt;code>out&lt;/code>.&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Logic input, true if &amp;gt; 0&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Debounced output&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>debounce_time&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Debounce time (s), default 0&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>timer&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Debounce timer (internal state, s)&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/debounce.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/dmm/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/dmm/</guid><description>&lt;h1 id="dmm">
 DMM
 &lt;a class="anchor" href="#dmm">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>dmm&lt;/code> reads the absolute position of a DMM servo motor encoder that streams its angle continuously over RS485 into the fb0 connector of the F4 logic board. conf/template/encdmm_fb0.txt loads it and wires &lt;code>fb_switch0.mot_pos = dmm0.pos&lt;/code>, &lt;code>fb_switch0.mot_abs_pos = dmm0.pos&lt;/code>, &lt;code>fb_switch0.mot_state = 3&lt;/code>, &lt;code>fault0.mot_fb_error = dmm0.error&lt;/code> and &lt;code>io0.fb0y = dmm0.error&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Receiver (hw_init)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>USART6 in half-duplex mode on PC6 at 1.875 Mbaud 8N1, the fb0 transmitter (PD15) is switched off, so the drive only listens. DMA2 stream 1 writes the incoming bytes into a 15 byte circular buffer.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Frame format&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>A frame has 4 bytes. Byte 0 holds the MSBs of the other three bytes (bits 0..2), 4 bits F (unused here) and a 0 in bit 7; bytes 1..3 carry 7 data bits and a 1 in bit 7.&lt;/li>
&lt;li>Byte 1 + MSB = angle high byte, byte 2 + MSB = angle low byte, byte 3 + MSB = CRC-8 (polynomial x^8 + x^3 + 1) over the 16 bit angle.&lt;/li>
&lt;/ul>
&lt;ol start="3">
&lt;li>&lt;strong>Decoding (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>From the current DMA write position, the component looks for a valid frame starting 7, 8, 9 or 10 bytes back (the newest 3 bytes are skipped because they may belong to an incomplete frame). A frame is valid if the CRC and the four framing bits match.&lt;/li>
&lt;li>On success &lt;code>pos = angle * 2 * pi / 65536 - pi&lt;/code> (rad, one turn = 16 bit) and &lt;code>error = 0&lt;/code>; if no valid frame is found &lt;code>error = 1&lt;/code> and &lt;code>pos&lt;/code> keeps its last value.&lt;/li>
&lt;/ul>
&lt;blockquote class="book-hint warning">
&lt;p>The receive buffer is never cleared (see the TODO in &lt;code>rt&lt;/code>). If the encoder stops sending, the last valid frame stays in the buffer and &lt;code>error&lt;/code> stays 0 with a frozen &lt;code>pos&lt;/code>, so a cable break is not detected. &lt;code>dmm&lt;/code> and &lt;code>usart&lt;/code> both use USART6 and DMA2 stream 1 and cannot be loaded together.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/dob/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/dob/</guid><description>&lt;h1 id="dob">
 DOB
 &lt;a class="anchor" href="#dob">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>dob&lt;/code> is a disturbance (load torque) observer on the torque command. It estimates the torque the rigid body model cannot explain (load, friction, cutting force, cogging) and subtracts it from the torque command, so the drive cancels the disturbance before the velocity integrator has to. &lt;code>conf/template/filters.txt&lt;/code> loads it (opt-in, &lt;code>link filters&lt;/code> after &lt;code>link pmsm&lt;/code>) between &lt;code>biquad0&lt;/code> and the torque controller, passing through (&lt;code>k&lt;/code> 0) until set; &lt;code>conf/fanuc_a3-3000.txt&lt;/code> links it with &lt;code>k&lt;/code> 1 and the friction feedforward off. The wiring, by hand or as in the template:&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/dq/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/dq/</guid><description>&lt;h1 id="dq">
 DQ
 &lt;a class="anchor" href="#dq">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>dq&lt;/code> turns three phase values (normally the measured phase currents) into the stationary alpha/beta frame (Clarke transform) and then into the rotating d/q frame (Park transform) at the rotor angle &lt;code>pos&lt;/code>. It runs on the F3 (HV board) as &lt;code>dq0&lt;/code>, loaded by &lt;code>stm32f303/src/main.c&lt;/code> (rt_prio 2): &lt;code>dq0.u/v/w = io0.iu/iv/iw&lt;/code>, &lt;code>dq0.pos = ls0.pos&lt;/code>, &lt;code>dq0.mode = ls0.phase_mode&lt;/code>, and &lt;code>d&lt;/code>/&lt;code>q&lt;/code> feed &lt;code>curpid0&lt;/code> and are sent back to the F4 by &lt;code>ls0&lt;/code>. &lt;code>si&lt;/code>/&lt;code>co&lt;/code> go to &lt;code>hv0&lt;/code> for its dead time compensation.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/emf/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/emf/</guid><description>&lt;h1 id="emf">
 EMF
 &lt;a class="anchor" href="#emf">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>emf&lt;/code> measures the back EMF of a coasting motor on the F3 (HV board): with the bridge off it demodulates every PWM period&amp;rsquo;s unfiltered phase voltage sample against the rotor angle and sums the flux linkage &lt;code>psi&lt;/code>, its 5th and 7th harmonic back EMF, and &lt;code>psi&lt;/code> per magnet pole, to tell a demagnetised magnet from a weak rotor. It is loaded by &lt;code>stm32f303/src/main.c&lt;/code> as &lt;code>emf0&lt;/code> (rt_prio 7, the last in the chain). It is controlled from the F4 through config words and read back one result at a time through a state word: &lt;code>idpmsm&lt;/code>&amp;rsquo;s psi test drives it (conf/template/id_pmsm.txt links &lt;code>hv0.emf_run/emf_sel/emf_pp&lt;/code> to &lt;code>idpmsm0&lt;/code> and &lt;code>idpmsm0.emf_val = hv0.emf_val&lt;/code>). It runs on the F3 because the F4 only sees each phase voltage every ~2 ms and through &lt;code>io0&lt;/code>&amp;rsquo;s filter.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/en/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/en/</guid><description>&lt;h1 id="en">
 EN
 &lt;a class="anchor" href="#en">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>en&lt;/code> is an enable sequencer: after its input has been active for a while it switches on two enable outputs one after the other, and it restarts when a fault occurs. It runs on the F4 board. &lt;code>conf/template/en.txt&lt;/code> uses it to enable the drive automatically after power up: &lt;code>en0.en_in = 1&lt;/code>, &lt;code>fault0.en = en0.en_out0&lt;/code>, &lt;code>en0.fault = fault0.fault&lt;/code>, &lt;code>en0.time = 1&lt;/code>. In &lt;code>conf/move.txt&lt;/code> &lt;code>en_out1&lt;/code> enables the drive and homing.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/enc_cmd/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/enc_cmd/</guid><description>&lt;h1 id="enc_cmd">
 ENC_CMD
 &lt;a class="anchor" href="#enc_cmd">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>enc_cmd&lt;/code> reads an incremental position command (quadrature or step/dir) with an STM32 hardware timer on the F4 board and outputs it as an angle. It is loaded by &lt;code>conf/template/enc_cmd.txt&lt;/code> (&lt;code>enc_cmd0.res = conf0.cmd_res&lt;/code>, &lt;code>rev0.in = enc_cmd0.pos&lt;/code>, &lt;code>fault0.cmd_error = enc_cmd0.error&lt;/code>), so the command position goes through &lt;code>rev0&lt;/code> to build a multiturn command. It can also drive a fault/ready line back to the controller.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Connector and timer selection (&lt;code>remap&lt;/code>, read once in hw_init)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>remap = 0&lt;/code> (default): CMD connector, A = PA15, B = PB3 on TIM2 (32 bit). Fault line = CMD C (PB5), its line driver enable PB9 is switched on.&lt;/li>
&lt;li>&lt;code>remap = 1&lt;/code>: FB0 connector, A = PD12, B = PD13 on TIM4. Fault line = FB0 Z (PD14), enable PD15.&lt;/li>
&lt;li>&lt;code>remap = 2&lt;/code>: FB1 connector, A = PE9, B = PE11 on TIM1. Fault line = FB1 Z (PE13), enable PE14.&lt;/li>
&lt;li>&lt;code>remap = 3&lt;/code> (&amp;ldquo;bene style&amp;rdquo;, used by &lt;code>conf/bene_sanyo.txt&lt;/code> and &lt;code>conf/spindle_slip_uf.txt&lt;/code>): A = PA8, B = PA9 on TIM1. Fault line = CMD D (PB8), enable PB2.&lt;/li>
&lt;li>Any other value returns from hw_init without configuring anything, &lt;code>pos&lt;/code> then reads a timer that was never set up.&lt;/li>
&lt;li>A and B get the timer alternate function with pull-ups, the fault pin and its enable are push-pull outputs.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Signal type (&lt;code>mode&lt;/code>, read once in hw_init)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>mode = 0&lt;/code> (default): quadrature. The timer runs in X4 encoder mode (counts every edge of A and B, so 4 counts per line), auto-reload = &lt;code>res - 1&lt;/code>.&lt;/li>
&lt;li>&lt;code>mode = 1&lt;/code>: step/dir, step on A, direction on B. &lt;code>mode = 2&lt;/code>: dir/step, direction on A, step on B. Direction high counts up.&lt;/li>
&lt;li>In step/dir the timer is a free running 32 bit up counter clocked by the rising edges of the step input. Each edge of the direction input captures the count in hardware (input capture), and the TIM2 interrupt (priority 1, above the rt) adds the steps since the last direction edge with the old sign. So the step at which the direction changed is exact whatever the interrupt latency; it only has to be taken before the next direction edge, else the capture overflow flag marks it as lost. The STM32 encoder modes cannot decode step/dir: they count a step pulse&amp;rsquo;s rising and falling edge with opposite signs.&lt;/li>
&lt;li>&lt;code>mode = 3&lt;/code> (up/down) is not supported, and neither is step/dir on &lt;code>remap&lt;/code> 1..3 (16 bit timers, their DMA belongs to the feedback components). Then &lt;code>error&lt;/code> is set and the timer is not set up.&lt;/li>
&lt;li>Both inputs use the digital input filter &lt;code>input_filter&lt;/code> (IC1F/IC2F code), clamped, without prescaler.&lt;/li>
&lt;/ul>
&lt;ol start="3">
&lt;li>&lt;strong>Position output (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>Quadrature: each rt cycle the counter is read and converted:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>pos &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">mod&lt;/span>(counter &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#f92672">*&lt;/span> pi &lt;span style="color:#f92672">/&lt;/span> res); &lt;span style="color:#75715e">// rad, wrapped to +-pi
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>In quadrature &lt;code>res&lt;/code> is counts per revolution at X4, so lines x 4 (a 2000 line encoder is &lt;code>res = 8000&lt;/code>), the same convention as &lt;code>enc_fb&lt;/code>. The counter wraps once per revolution; the multiturn tracking is done downstream (e.g. &lt;code>rev0&lt;/code>).&lt;/li>
&lt;li>Step/dir: the rt takes a pending direction edge, reads the count and adds the steps since the last edge with the current sign, with interrupts off. The signed step count is kept modulo &lt;code>res&lt;/code>, and &lt;code>pos = mod(steps * 2 * pi / res)&lt;/code>, so in step/dir &lt;code>res&lt;/code> is steps per revolution.&lt;/li>
&lt;li>&lt;code>res&lt;/code> is clamped to &amp;gt;= 1, and in quadrature on the 16 bit timers (&lt;code>remap&lt;/code> 1..3) to &amp;lt;= 65536. If it changes at runtime the auto-reload register is updated (quadrature only).&lt;/li>
&lt;/ul>
&lt;ol start="4">
&lt;li>&lt;strong>Error and fault output (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The template links &lt;code>error&lt;/code> to &lt;code>fault0.cmd_error&lt;/code>, so it trips fault 1 (CMD error).&lt;/li>
&lt;li>A &lt;code>fault&lt;/code> of 0 drives the fault line low (e.g. &lt;code>enc_cmd0.fault = fault0.fault&lt;/code> or an inverted enable signal).&lt;/li>
&lt;/ul>
&lt;blockquote class="book-hint warning">
&lt;p>Breaking change: before this version quadrature &lt;code>res&lt;/code> was counts per revolution at 2 counts per line (lines x 2), with auto-reload &lt;code>2 * res - 1&lt;/code>. Configs that use quadrature &lt;code>enc_cmd&lt;/code> need &lt;code>res&lt;/code> (&lt;code>conf0.cmd_res&lt;/code>) doubled. With an old value the drive moves twice the commanded distance, and with commutation from the command input (autophasing) the commutation angle is wrong. Step/dir is unchanged.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/enc_fb/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/enc_fb/</guid><description>&lt;h1 id="enc_fb">
 ENC_FB
 &lt;a class="anchor" href="#enc_fb">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>enc_fb&lt;/code> reads an incremental quadrature encoder (A/B with optional index Z, optionally with analog sin/cos tracks) on the FB0 connector of the F4 board. It is loaded by &lt;code>conf/template/enc_fb0.txt&lt;/code> (and &lt;code>encws_fb0.txt&lt;/code>, which disables the index), which links &lt;code>enc_fb0.pos&lt;/code>, &lt;code>abs_pos&lt;/code> and &lt;code>state&lt;/code> to &lt;code>fb_switch0.mot_*&lt;/code>, &lt;code>sin&lt;/code>/&lt;code>cos&lt;/code>/&lt;code>quad&lt;/code>/&lt;code>amp&lt;/code> to the &lt;code>adc0&lt;/code> sin0l/cos0l/quad/amp0 pins and &lt;code>vel&lt;/code> to &lt;code>vel1.vel&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Hardware (hw_init)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>FB0 A = PD12, B = PD13, Z = PD14 are connected to TIM4 (V4 board) in encoder mode (TI1 and TI2 edges, 4 counts per line, B input inverted), auto-reload = &lt;code>res - 1&lt;/code>, with &lt;code>res&lt;/code> clamped to &amp;gt;= 1.&lt;/li>
&lt;li>A and B use the timer&amp;rsquo;s digital input filter at fCK_INT with N = 8 (about 95 ns at 84 MHz), so short glitches are ignored.&lt;/li>
&lt;li>Channel 3 of the same timer captures the counter value on the Z (index) input.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Count and quadrant correction (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The counter and the A/B port are latched together at the start of the rt interrupt (&lt;code>DMA2_Stream0_IRQHandler&lt;/code> in &lt;code>main.c&lt;/code>, about 4 us after the last sin/cos sample), close to the time the analog quadrant was sampled.&lt;/li>
&lt;li>&lt;code>qdiff = quad - oquad&lt;/code>, where &lt;code>quad&lt;/code> is the quadrant computed by the ADC component from the analog sin/cos signals. If they differ by one quadrant the count is corrected by +-1 so the digital count matches the analog signals, then wrapped to 0..res-1.&lt;/li>
&lt;li>&lt;code>pos = mod(count * 2 * pi / res)&lt;/code>. If &lt;code>res&lt;/code> changes at runtime the timer auto-reload is updated.&lt;/li>
&lt;/ul>
&lt;ol start="3">
&lt;li>&lt;strong>Index and absolute position (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>If &lt;code>en_index &amp;gt; 0&lt;/code> and an index capture happened, the captured count is stored as the offset and &lt;code>state&lt;/code> becomes 3.&lt;/li>
&lt;li>&lt;code>abs_pos = minus(pos, offset)&lt;/code>. Before the first index the offset is 0.&lt;/li>
&lt;li>If &lt;code>indexprint &amp;gt; 0&lt;/code>, the nrt function prints the captured counter value (&lt;code>cnt = ...&lt;/code>) once per index event.&lt;/li>
&lt;/ul>
&lt;ol start="4">
&lt;li>&lt;strong>Signal check and interpolation (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>If &lt;code>amp &amp;gt; min_amp&lt;/code> or &lt;code>|vel| &amp;gt; 0.15&lt;/code>: &lt;code>error = 0&lt;/code>, &lt;code>state&lt;/code> is at least 1, and the interpolated position is computed from the analog angle:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>ipos &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">mod&lt;/span>(pos &lt;span style="color:#f92672">+&lt;/span> (&lt;span style="color:#66d9ef">int&lt;/span>)(ires &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#a6e22e">mod&lt;/span>(&lt;span style="color:#ae81ff">4&lt;/span> &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#a6e22e">atan2&lt;/span>(sin, cos) &lt;span style="color:#f92672">+&lt;/span> pi) &lt;span style="color:#f92672">/&lt;/span> pi) &lt;span style="color:#f92672">/&lt;/span> ires &lt;span style="color:#f92672">*&lt;/span> pi &lt;span style="color:#f92672">/&lt;/span> res);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>i.e. the sin/cos phase adds a fine offset of +-half a count, quantised to &lt;code>ires&lt;/code> steps.&lt;/li>
&lt;li>Otherwise &lt;code>error = 1&lt;/code> and &lt;code>state = 0&lt;/code>. For a plain digital encoder without sin/cos &lt;code>amp&lt;/code> must be set to a constant above &lt;code>min_amp&lt;/code> (e.g. &lt;code>enc_fb0.amp = 5&lt;/code> in &lt;code>conf/haas_spindle_slip_uf.txt&lt;/code>), otherwise the encoder is reported as faulty at standstill.&lt;/li>
&lt;/ul>
&lt;blockquote class="book-hint warning">
&lt;p>The &lt;code>state&lt;/code> drops back to 0 whenever the amplitude/velocity check fails, even after an index was found (the stored index offset is kept).&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/encf/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/encf/</guid><description>&lt;h1 id="encf">
 ENCF
 &lt;a class="anchor" href="#encf">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>encf&lt;/code> reads Fanuc serial absolute encoders (tested with the Aa64 type, A860-360) on the FB0 connector of the F4 board. It is loaded by &lt;code>conf/template/fanuc_fb0.txt&lt;/code> (used e.g. by &lt;code>conf/fanuc_a6-2000.txt&lt;/code>), which links &lt;code>encf0.pos&lt;/code>/&lt;code>abs_pos&lt;/code>/&lt;code>state&lt;/code> to &lt;code>fb_switch0.mot_*&lt;/code> and &lt;code>encf0.com_pos&lt;/code> to &lt;code>fb_switch0.com_pos&lt;/code>/&lt;code>com_abs_pos&lt;/code>, and sets &lt;code>encf0.hold = fault0.en_out&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Hardware (nrt_init)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The request pulse is generated with SPI3 (MOSI on PC12, prescaler 32, 16 bit word): every rt cycle the word &lt;code>req_len&lt;/code> is written to SPI3 (see 2), which gives a request pulse of about 8.4 us. The FB0 line driver enable PD15 is switched on.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Request timing (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The encoder latches its position on the request, so the request goes out at a fixed point: first in rt, the capture buffer is copied out, TIM4 and the DMA are restarted, then the request is armed. The copy is decoded after that. Sent at the end of rt, after the decode, the latch time wandered with the frame&amp;rsquo;s bit pattern (Y, 15 Oct: about 1 us rms, 0.24 rad/s of &lt;code>vel1&lt;/code> noise and 0.8 A of iq noise at 126 rad/s).&lt;/li>
&lt;li>With &lt;code>req_sync&lt;/code> = 1 the rt only arms the word; the frt timer interrupt (TIM5, priority 0, &lt;code>src/main.c&lt;/code>) writes it to SPI3 first thing on its next update. TIM5 and the ADC that paces the rt both count TIM3, so this is always the same update, a fixed time after the timer edge. &lt;code>req_phase&lt;/code> shows the TIM5 count at arming (33 of 59 on Y, about 22 us before the update). On Y this lowered &lt;code>vel1&lt;/code> noise above 200 Hz from 0.14 to 0.105 rad/s and iq noise from 0.45 to 0.37 A; &lt;code>pos_advance&lt;/code> stayed the same. &lt;code>req_sync&lt;/code> = 0 writes SPI3 from the rt code.&lt;/li>
&lt;li>The encoder answer is received on FB0 A (PD12): TIM4 channel 1 captures every edge (both polarities) and DMA1 stream 0 (channel 2) stores up to 160 capture times.&lt;/li>
&lt;/ul>
&lt;ol start="3">
&lt;li>&lt;strong>Bit decoding (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>TIM4 counts at 84 MHz, so the default &lt;code>freq&lt;/code> of 1.024 MHz gives 82.03 ticks per bit. A bench sweep decoded CRC-clean frames for &lt;code>freq&lt;/code> from about 986k to 1060k, so the default sits in the middle.&lt;/li>
&lt;li>The time between two edges is multiplied by &lt;code>1 / bit_ticks&lt;/code> and rounded to get the number of equal bits; every even-numbered interval is written as 1s. The frame is built in three 32 bit words and the write is bounded to the 80 bit frame buffer, so a noisy frame with too many bits is cut off instead of overrunning memory. Bits after the last edge up to bit 76 are set to 1 (idle line).&lt;/li>
&lt;li>If fewer than 51 bits were decoded: &lt;code>error = 1&lt;/code>, &lt;code>state = 1&lt;/code> and the position pins keep their last value.&lt;/li>
&lt;/ul>
&lt;ol start="4">
&lt;li>&lt;strong>Frame content and CRC (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>A 5 bit CRC (ITU CRC-5, from the Mesa &lt;code>fabsread&lt;/code> notes) over bits 76..1, MSB first and computed four bits at a time with a nibble table, must be 0. On success &lt;code>crc_ok&lt;/code> is incremented, otherwise &lt;code>crc_er&lt;/code> is incremented and &lt;code>error = 1&lt;/code>, &lt;code>state = 1&lt;/code> (the position pins keep their last value).&lt;/li>
&lt;li>Fields: battery fail bit -&amp;gt; &lt;code>batt&lt;/code>, un-indexed bit -&amp;gt; &lt;code>index&lt;/code> (1 = not yet indexed), 22 bit single-turn position (6 low bits + 16 high bits), 16 bit turn counter (used for &lt;code>turns&lt;/code>, see 5), 10 bit commutation track -&amp;gt; &lt;code>com_pos&lt;/code>.&lt;/li>
&lt;li>&lt;code>abs_pos = pos22 * 2 * pi / 2^22&lt;/code> and &lt;code>com_pos = com * 2 * pi / 1024&lt;/code> (rad), wrapped to [-pi, pi) by sign-extending the integer count (same result as &lt;code>mod()&lt;/code> without the &lt;code>fmodf&lt;/code>). According to the Mesa notes the commutation track has four 0..1023 cycles per turn and is always absolute.&lt;/li>
&lt;/ul>
&lt;ol start="5">
&lt;li>&lt;strong>Position, turns and state (rt, on every valid frame)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>pos&lt;/code> is the 22 bit count shifted by &lt;code>pos_offset * 64&lt;/code> and wrapped as a 22 bit count to [-pi, pi). The offset applies in every state; &lt;code>pos_offset&lt;/code> = 0 gives &lt;code>pos = abs_pos&lt;/code>.&lt;/li>
&lt;li>The encoder steps its own turn count where its unsigned count wraps (&lt;code>abs_pos&lt;/code> = 0), half a turn away from the +-pi wrap. &lt;code>encf&lt;/code> keeps a turn count referenced to the +-pi wrap of &lt;code>abs_pos&lt;/code> (the encoder&amp;rsquo;s count, + 1 on the negative half) and takes it from the encoder only while &lt;code>abs_pos&lt;/code> is more than a quarter turn from 0, so a few counts of mismatch at the encoder&amp;rsquo;s own step cannot glitch it. &lt;code>turns&lt;/code> is then shifted so that it steps exactly where &lt;code>pos&lt;/code> wraps and equals the encoder&amp;rsquo;s count at &lt;code>pos = pos_offset&lt;/code>. &lt;code>pos_offset&lt;/code> = 32768 puts the wrap of &lt;code>pos&lt;/code> at the encoder&amp;rsquo;s own step.&lt;/li>
&lt;li>The count is taken from the encoder at once, whatever the position, after more than 10 frames without a valid frame (and at start), for 3 frames after the un-indexed bit changes, and on a jump of &lt;code>pos&lt;/code> of more than 1/32 turn between two frames. This follows the encoder when it re-references its position and turns at the first index after a battery loss (it clears the un-indexed bit one frame before the count jumps).&lt;/li>
&lt;li>&lt;code>hold&lt;/code> &amp;gt; 0 (the template links &lt;code>fault0.en_out&lt;/code>, so while the drive is enabled): a re-reference at the index would step &lt;code>pos&lt;/code> and &lt;code>turns&lt;/code> by up to a turn, and the position loop would pull the motor back by that much. Instead, a step that motion does not explain (more than 1/32 turn per frame, or during the re-take frames a change of more than 2^12 counts, 1/1024 turn, from the previous frame&amp;rsquo;s motion) is added to an offset, output on &lt;code>hold_off&lt;/code> in turns, which is added to &lt;code>pos&lt;/code> and &lt;code>turns&lt;/code> so they stay continuous. The offset is dropped when &lt;code>hold&lt;/code> goes to 0, so the new reference shows while the drive is disabled. &lt;code>abs_pos&lt;/code> and &lt;code>com_pos&lt;/code> are never offset and stay true for commutation.&lt;/li>
&lt;li>&lt;code>state = 1&lt;/code> while the encoder reports un-indexed, during those 3 re-take frames and for the frame in which a held offset is dropped (so &lt;code>linrev&lt;/code> re-takes its turns), else 3. An encoder that is indexed at power up reads 3 from the first frame; after the first index crossing &lt;code>state&lt;/code> reads 3 from the frame after the re-reference, so &lt;code>fb_switch&lt;/code> does not switch commutation to &lt;code>abs_pos&lt;/code> from the old count.&lt;/li>
&lt;li>Until then &lt;code>fb_switch&lt;/code> commutates from the commutation track (&lt;code>com_pos&lt;/code> + &lt;code>conf0.com_fb_offset&lt;/code>, measured by &lt;code>id_pmsm&lt;/code>), see &lt;code>fanuc_fb0.txt&lt;/code>. For a multiturn position link &lt;code>linrev0.abs_rev = encf0.turns&lt;/code>, &lt;code>linrev0.abs_pos = encf0.pos&lt;/code>, &lt;code>linrev0.abs_state = encf0.state&lt;/code>.&lt;/li>
&lt;/ul>
&lt;ol start="6">
&lt;li>&lt;strong>Debug output (nrt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The raw 76 bit frame is printed as a string of 0/1.&lt;/li>
&lt;/ul>
&lt;blockquote class="book-hint warning">
&lt;p>The turn and re-take state is kept in file-static variables, so only one &lt;code>encf&lt;/code> instance works. The TX enable (PD15), SPI3 and TIM4 pins are hard coded for the V4 board. The frame layout was only verified for Aa64 encoders; for Aa1000 (A860-370) the extra low resolution bits are not used.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/encm/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/encm/</guid><description>&lt;h1 id="encm">
 ENCM
 &lt;a class="anchor" href="#encm">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>encm&lt;/code> reads Mitsubishi serial absolute encoders (2.5 Mbit/s, byte oriented request/reply protocol) on the FB0 connector of the F4 board. It is loaded by &lt;code>conf/template/encm_fb0.txt&lt;/code> (used by &lt;code>conf/mitsu.txt&lt;/code> and &lt;code>conf/wobl.txt&lt;/code>), which links &lt;code>encm0.pos&lt;/code> to &lt;code>fb_switch0.mot_pos&lt;/code> and &lt;code>mot_abs_pos&lt;/code>, &lt;code>encm0.state&lt;/code> to &lt;code>fb_switch0.mot_state&lt;/code> and &lt;code>encm0.error&lt;/code> to &lt;code>fault0.mot_fb_error&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Hardware (hw_init)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>USART6 at 2.5 Mbaud, 8N1. TX = PC6, line driver enable = PD15.&lt;/li>
&lt;li>The reply is received by DMA2 stream 1 (channel 5) into a 15 byte buffer.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Command selection (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>If &lt;code>cmd &amp;gt; 0&lt;/code> this byte is sent as request. Otherwise it depends on &lt;code>id&lt;/code>:&lt;/li>
&lt;li>&lt;code>id = 0&lt;/code> (unknown): request 0x92 (read encoder id), any length accepted.&lt;/li>
&lt;li>&lt;code>id = 32&lt;/code>: request 0x02, 7 reply bytes expected, 13 bit single-turn position.&lt;/li>
&lt;li>&lt;code>id = 61&lt;/code>, &lt;code>65&lt;/code> and all others: request 0x32, 9 reply bytes expected, 17 bit single-turn position.&lt;/li>
&lt;/ul>
&lt;ol start="3">
&lt;li>&lt;strong>Reply check and decoding (rt)&lt;/strong>, done on the reply to the request of the previous rt cycle:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>Checksum: the XOR of all received bytes must be 0, otherwise &lt;code>crc_error = 1&lt;/code>.&lt;/li>
&lt;li>Fewer than 3 bytes or not the expected number: &lt;code>dma_error = 1&lt;/code>.&lt;/li>
&lt;li>First byte different from the sent command: &lt;code>cmd_error = 1&lt;/code>.&lt;/li>
&lt;li>Any of these sets &lt;code>error = 1&lt;/code>, &lt;code>state = 0&lt;/code>.&lt;/li>
&lt;li>Reply to 0x02: &lt;code>ipos = (buf2 &amp;lt;&amp;lt; 11) + ((buf3 &amp;amp; 0x1f) &amp;lt;&amp;lt; 19)&lt;/code>; reply to 0x32: &lt;code>ipos = (buf2 &amp;amp; 0x80) + (buf3 &amp;lt;&amp;lt; 8) + (buf4 &amp;lt;&amp;lt; 16)&lt;/code>; both give &lt;code>state = 3&lt;/code>.&lt;/li>
&lt;li>Reply to 0x92: &lt;code>id = buf2&lt;/code>, so the next cycle uses the matching position request.&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>pos &lt;span style="color:#f92672">=&lt;/span> ipos &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#f92672">*&lt;/span> pi &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>&lt;span style="color:#f92672">^&lt;/span>&lt;span style="color:#ae81ff">24&lt;/span> &lt;span style="color:#f92672">-&lt;/span> pi; &lt;span style="color:#75715e">// rad, -pi..pi
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="4">
&lt;li>&lt;strong>Request (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The TX enable is set, the command byte is sent and the rt function busy-waits for the USART transmit-complete flag, then the TX enable is cleared and the RX DMA is restarted.&lt;/li>
&lt;/ul>
&lt;blockquote class="book-hint warning">
&lt;p>The protocol was reverse engineered: the byte meanings in the source comments are guesses, multiturn data is not decoded, and only a plain XOR checksum is checked. After the id reply &lt;code>pos&lt;/code> is set to -pi (ipos = 0) for one cycle but &lt;code>state&lt;/code> stays 0. The busy-wait in rt (&amp;ldquo;irq here will cause problems&amp;rdquo;) and the hard coded USART6/PC6/PD15/DMA2 stream 1 make it V4 specific; DMA2 stream 1 is also used by &lt;code>encs&lt;/code> and &lt;code>dmm&lt;/code>, so these cannot be loaded together.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/encs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/encs/</guid><description>&lt;h1 id="encs">
 ENCS
 &lt;a class="anchor" href="#encs">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>encs&lt;/code> reads Sanyo Denki serial absolute encoders (tested with PA035C, 2.5 Mbit/s) on the Z line of the FB0 connector of the F4 board. It is loaded by &lt;code>conf/template/encs_fb0.txt&lt;/code> (used e.g. by &lt;code>conf/bene_sanyo.txt&lt;/code>), which links &lt;code>encs0.pos&lt;/code> to &lt;code>fb_switch0.mot_pos&lt;/code> and &lt;code>mot_abs_pos&lt;/code>, &lt;code>encs0.state&lt;/code> to &lt;code>fb_switch0.mot_state&lt;/code> and &lt;code>encs0.error&lt;/code> to &lt;code>fault0.mot_fb_error&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Hardware (hw_init)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The half-duplex data line is FB0 Z (PD14), the line driver enable is FB0 Z TXEN (PD15).&lt;/li>
&lt;li>Transmit: the request is bit-banged by DMA2 stream 1 (channel 7, TIM8 update) writing a 24 word pattern to the GPIO set/reset register. TIM8 runs with prescaler 1 and period 32, about 2.545 MHz per bit.&lt;/li>
&lt;li>Receive: TIM4 channel 3 captures every edge on PD14 (both polarities), DMA1 stream 7 (channel 2) stores up to 300 capture times.&lt;/li>
&lt;li>The request frame is fixed: start bit, sync, frame code, encoder address 0, command code CDF1 (&amp;ldquo;absolute lower 24 bit data request&amp;rdquo;) and a precomputed CRC.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Reply decoding (rt)&lt;/strong>, done on the reply to the request of the previous rt cycle:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The time between edges is divided by 33 timer ticks per bit and rounded; every odd-numbered interval is written as 1s, the rest of the 54 bit frame is filled with 1 (idle line).&lt;/li>
&lt;li>The frame consists of three 18 bit words (start bit, 16 data bits, stop bit). Only the start (0) and stop (1) bits are checked.&lt;/li>
&lt;li>Position: 16 bits from word B plus the MSB (bit 16) from word C, 17 bit single turn:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>pos &lt;span style="color:#f92672">=&lt;/span> (pos0_15 &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">65536&lt;/span> &lt;span style="color:#f92672">+&lt;/span> pos16) &lt;span style="color:#f92672">*&lt;/span> pi &lt;span style="color:#f92672">-&lt;/span> pi; &lt;span style="color:#75715e">// rad, -pi..pi
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="3">
&lt;li>&lt;strong>Request (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>PD14 is switched to output, TX enable set, the TX DMA is started and the rt function busy-waits until it completes (about 9 us), then PD14 is switched back to the timer input, the capture timer is reset and the RX DMA is restarted.&lt;/li>
&lt;/ul>
&lt;blockquote class="book-hint warning">
&lt;p>The CRC, the alarm/status fields and the multiturn bits of the reply are not checked or used. The GPIO mode register access is hard coded for PD14 (V4 board). DMA2 stream 1 is also used by &lt;code>encm&lt;/code> and &lt;code>dmm&lt;/code>, and TIM8 by &lt;code>yaskawa&lt;/code>, so these cannot be loaded together with &lt;code>encs&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/endat/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/endat/</guid><description>&lt;h1 id="endat">
 ENDAT
 &lt;a class="anchor" href="#endat">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>endat&lt;/code> is an experimental driver for Heidenhain EnDat 2.1 absolute encoders on the FB0 connector of the F4 board. It uses SPI3 in bidirectional single-wire mode for clock and data and the protocol helpers in &lt;code>shared/endat.c&lt;/code>. No config template loads it.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Hardware (nrt_init)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>SPI3 master, prescaler 32 (about 1.3 MHz clock), clock = PC10, bidirectional data = PC12.&lt;/li>
&lt;li>Line driver enables: PD10 for the clock (always on), PD15 for the data line (on only while sending).&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Request state machine (rt)&lt;/strong>, selected by &lt;code>endat_state&lt;/code>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>0: reset error; 1: select memory &amp;ldquo;state&amp;rdquo;; 2: read error register; 3: read warning register; 4: select parameter memory 0; 5: read position length; 6: read encoder type; 7: select parameter memory 1; 8: read multiturn bits; 9/10: read resolution low/high word; 11: select parameter memory 2; 12: read maximum velocity; 13: read position.&lt;/li>
&lt;li>If &lt;code>req &amp;gt; 0&lt;/code> it overrides the command byte (e.g. 7 = read position).&lt;/li>
&lt;li>After a successful reply &lt;code>endat_state&lt;/code> is incremented, after a failed one it is reset to 0 (so the whole parameter sequence is read again).&lt;/li>
&lt;li>In state 12 &lt;code>error&lt;/code>/&lt;code>state&lt;/code> follow the encoder error bit (F1): error bit set or failed reply -&amp;gt; &lt;code>error = 1&lt;/code>, &lt;code>state = 0&lt;/code>, &lt;code>endat_state = 0&lt;/code>; otherwise &lt;code>state = 1&lt;/code>, &lt;code>error = 0&lt;/code>. In all other states &lt;code>state = 0&lt;/code>.&lt;/li>
&lt;/ul>
&lt;ol start="3">
&lt;li>&lt;strong>Transfer (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The mode command (2 + 6 bits, or 32 bits with address and data) is sent (bit order prepared by &lt;code>endat_tx()&lt;/code>) with the data driver enabled, then the driver is switched off and &lt;code>bytes&lt;/code> bytes (max 8) are clocked in.&lt;/li>
&lt;li>Before receiving, a byte left in the SPI receive register from the last frame is dropped. SPI3 is disabled one SPI clock after the second to last byte, so exactly &lt;code>bytes&lt;/code> bytes are clocked from the encoder. If a byte does not arrive within a polling timeout, the received data is set to 0 instead of hanging the rt function.&lt;/li>
&lt;li>The received bits are shifted right by &lt;code>skip&lt;/code> and then until the first 1 (start bit) is found; the total shift is shown on &lt;code>shift&lt;/code> (max 32).&lt;/li>
&lt;li>The reply is decoded by &lt;code>endat_rx()&lt;/code>: for a position read the error bit goes to &lt;code>f1&lt;/code>, the single-turn value (&lt;code>pos_len&lt;/code> bits) and multiturn value (&lt;code>mpos_len&lt;/code> bits) to &lt;code>pos&lt;/code>/&lt;code>mpos&lt;/code>, the 5 CRC bits to &lt;code>crc&lt;/code>. Parameter reads fill &lt;code>endat_error&lt;/code>, &lt;code>endat_warning&lt;/code>, &lt;code>type&lt;/code>, &lt;code>pos_res&lt;/code>, &lt;code>max_vel&lt;/code>, and update &lt;code>pos_len&lt;/code>/&lt;code>mpos_len&lt;/code> from the encoder memory.&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>pos &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">mod&lt;/span>(pos_raw &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#f92672">*&lt;/span> pi &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>&lt;span style="color:#f92672">^&lt;/span>pos_len); &lt;span style="color:#75715e">// rad, +-pi
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="4">
&lt;li>&lt;strong>Debug output (nrt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>If &lt;code>print_time &amp;gt; 0&lt;/code>, &lt;code>timer&lt;/code> counts up in rt and every &lt;code>print_time&lt;/code> seconds the nrt function prints the last request, received raw bits, position, multiturn and CRC bits.&lt;/li>
&lt;/ul>
&lt;blockquote class="book-hint danger">
&lt;p>Experimental and incomplete. The CRC is read but never checked. The state handling looks inconsistent: the position read (13) takes the default branch, so after one successful read &lt;code>endat_state&lt;/code> becomes 14, which sends nothing and falls back to 0; after the parameter sequence it then stays in state 12 (reading max velocity), so &lt;code>pos&lt;/code> is no longer updated unless &lt;code>req&lt;/code> is set to 7. &lt;code>state&lt;/code> never reaches 3, so &lt;code>fb_switch&lt;/code> will not accept it as a valid feedback. SPI3 is shared with &lt;code>encf&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/fanuc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/fanuc/</guid><description>&lt;h1 id="fanuc">
 FANUC
 &lt;a class="anchor" href="#fanuc">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>fanuc&lt;/code> component decodes the four digital commutation tracks &lt;code>C1&lt;/code>, &lt;code>C2&lt;/code>, &lt;code>C4&lt;/code> and &lt;code>C8&lt;/code> of a Fanuc pulse coder into an absolute commutation angle. It is used on the F4 board via &lt;code>conf/template/fanuc_io.txt&lt;/code>, which reads the tracks from &lt;code>io0.C12&lt;/code>, &lt;code>io0.CTX&lt;/code>, &lt;code>io0.CRX&lt;/code> and &lt;code>io0.C54&lt;/code> (with &lt;code>io0.cmd_remap = 1&lt;/code>) and links &lt;code>fanuc0.pos&lt;/code> to &lt;code>fb_switch0.com_pos&lt;/code> / &lt;code>fb_switch0.com_abs_pos&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Code word&lt;/strong> (&lt;code>rt&lt;/code>):&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The 4-bit word is built as&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>t &lt;span style="color:#f92672">=&lt;/span> C1 &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#f92672">*&lt;/span> C2 &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">4&lt;/span> &lt;span style="color:#f92672">*&lt;/span> C4 &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span> &lt;span style="color:#f92672">*&lt;/span> C8;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="2">
&lt;li>&lt;strong>Lookup table&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>A fixed table maps the 16 possible words (a Gray-code sequence) to the sector numbers 0..15:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>t: &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#ae81ff">3&lt;/span> &lt;span style="color:#ae81ff">4&lt;/span> &lt;span style="color:#ae81ff">5&lt;/span> &lt;span style="color:#ae81ff">6&lt;/span> &lt;span style="color:#ae81ff">7&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span> &lt;span style="color:#ae81ff">9&lt;/span> &lt;span style="color:#ae81ff">10&lt;/span> &lt;span style="color:#ae81ff">11&lt;/span> &lt;span style="color:#ae81ff">12&lt;/span> &lt;span style="color:#ae81ff">13&lt;/span> &lt;span style="color:#ae81ff">14&lt;/span> &lt;span style="color:#ae81ff">15&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sector: &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">15&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#ae81ff">13&lt;/span> &lt;span style="color:#ae81ff">14&lt;/span> &lt;span style="color:#ae81ff">12&lt;/span> &lt;span style="color:#ae81ff">11&lt;/span> &lt;span style="color:#ae81ff">5&lt;/span> &lt;span style="color:#ae81ff">6&lt;/span> &lt;span style="color:#ae81ff">4&lt;/span> &lt;span style="color:#ae81ff">3&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span> &lt;span style="color:#ae81ff">7&lt;/span> &lt;span style="color:#ae81ff">9&lt;/span> &lt;span style="color:#ae81ff">10&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>The output is &lt;code>pos = mod(sector / 16 * 2 * pi)&lt;/code> (22.5 deg per sector). There is no error detection: every code is treated as valid.&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>C1&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Commutation track C1 (bit 0, high when &amp;gt; 0)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>C2&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Commutation track C2 (bit 1, high when &amp;gt; 0)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>C4&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Commutation track C4 (bit 2, high when &amp;gt; 0)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>C8&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Commutation track C8 (bit 3, high when &amp;gt; 0)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>pos&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Absolute commutation angle (rad, +-pi)&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/fanuc.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/fault/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/fault/</guid><description>&lt;h1 id="fault">
 FAULT
 &lt;a class="anchor" href="#fault">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>fault&lt;/code> is the central enable / fault state machine of the F4 board. It collects error flags, temperatures, voltages, currents and controller saturation, decides whether the drive is disabled, phasing, enabled or faulted, gates the other components with &lt;code>en_out&lt;/code>, &lt;code>en_fb&lt;/code> and &lt;code>en_pid&lt;/code>, controls the motor brake and fans, outputs a derating factor &lt;code>scale&lt;/code>, and after a stop can decelerate the motor regeneratively (&lt;code>rstop&lt;/code>) or ask the F3 for short-circuit braking (&lt;code>sbrake&lt;/code>). It is loaded by nearly every template (&lt;code>pid.txt&lt;/code>, &lt;code>mpid.txt&lt;/code>, &lt;code>uf.txt&lt;/code>, the &lt;code>id_*&lt;/code> templates, &amp;hellip;). Typical links: &lt;code>hv0.en = fault0.en_out&lt;/code>, &lt;code>fb_switch0.en = fault0.en_fb&lt;/code>, &lt;code>pid0.en = fault0.en_pid&lt;/code>, &lt;code>hv0.scale = fault0.scale&lt;/code>, &lt;code>fault0.fb_ready = fb_switch0.state&lt;/code>, &lt;code>fault0.hv_error = hv0.fault&lt;/code>, &lt;code>fault0.sat = pid0.sat&lt;/code>, &lt;code>io0.state = fault0.state&lt;/code>, &lt;code>io0.fault = fault0.fault&lt;/code>, and the limits from &lt;code>conf0&lt;/code>. pid.txt also links &lt;code>hv0.sbrake = fault0.sbrake&lt;/code>, &lt;code>hv0.sbrake_arm = fault0.sbrake_en&lt;/code>, &lt;code>pid0.stop = fault0.rstop&lt;/code>, &lt;code>fault0.vel_fb = vel1.vel&lt;/code>; ipm.txt links &lt;code>fault0.ipm_temp = ipm0.temp&lt;/code>. The commands &lt;code>enable&lt;/code> and &lt;code>disable&lt;/code> set &lt;code>fault0.en&lt;/code> to 1 or 0.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/fb_switch/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/fb_switch/</guid><description>&lt;h1 id="fb_switch">
 FB_SWITCH
 &lt;a class="anchor" href="#fb_switch">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>fb_switch&lt;/code> combines up to three feedback sources (motor, commutation and joint feedback) into the position feedback for the position loop, the position used for velocity estimation and the commutation angle for the current loop. If no absolute source is available it performs autophasing. F4 component, loaded by the &lt;code>pid&lt;/code>/&lt;code>mpid&lt;/code> templates; e.g. &lt;code>fb_switch0.mot_pos = enc_fb0.ipos&lt;/code>, &lt;code>fb_switch0.com_state = uvw0.state&lt;/code>, &lt;code>pid0.pos_fb = fb_switch0.pos_fb&lt;/code>, &lt;code>vel1.pos_in = fb_switch0.vel_fb&lt;/code>, &lt;code>fault0.fb_ready = fb_switch0.state&lt;/code>, &lt;code>hv0.d_cmd = fb_switch0.id&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/field/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/field/</guid><description>&lt;h1 id="field">
 FIELD
 &lt;a class="anchor" href="#field">#&lt;/a>
&lt;/h1>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>vele_n&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>velm_n&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>i_n&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>t_n&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>vel_boost&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>t_boost&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>vel&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>vel_mode&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in_mode&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>t&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>iq&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>id&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>iq_max&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>iq_min&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>t_max&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>t_min&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>slip&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>velm&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>vele&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/field.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/flux_obs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/flux_obs/</guid><description>&lt;h1 id="flux_obs">
 FLUX_OBS
 &lt;a class="anchor" href="#flux_obs">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>flux_obs&lt;/code> is a hybrid rotor flux observer for an induction motor on an encoder (review item B5). It measures the rotor flux angle and magnitude from voltage and current, without tr, and can trim the current model&amp;rsquo;s slip so that the field orientation follows the measured flux at speed. Below its crossover it falls back to the current model (&lt;code>acim_flux&lt;/code>), so at low speed nothing changes.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/fluxopt/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/fluxopt/</guid><description>&lt;h1 id="fluxopt">
 FLUXOPT
 &lt;a class="anchor" href="#fluxopt">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>fluxopt&lt;/code> reduces the flux of an induction motor at light load (&lt;code>acim_foc&lt;/code>) to cut the copper loss. &lt;code>conf/template/acim_foc.txt&lt;/code> loads it between the field weakening and the field oriented control with &lt;code>fluxopt0.torque = pid0.torque_cmd&lt;/code>, &lt;code>fluxopt0.scale_in = acim_fw0.scale&lt;/code>, &lt;code>fluxopt0.id_n = acim_foc0.id_n&lt;/code>, &lt;code>fluxopt0.lmr = acim_flux0.lmr_act&lt;/code>, &lt;code>fluxopt0.polecount = conf0.polecount&lt;/code> and &lt;code>acim_foc0.scale = fluxopt0.scale&lt;/code>. It is off there (&lt;code>min&lt;/code> 1); &lt;code>fluxopt0.min = 0.5&lt;/code> in a config turns it on.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/fmove/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/fmove/</guid><description>&lt;h1 id="fmove">
 FMOVE
 &lt;a class="anchor" href="#fmove">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>fmove&lt;/code> implements force guided movement (admittance control): a measured force moves an axis like a virtual mass with damping and friction, and after the force is released the axis moves automatically to a target. F4 component, used in &lt;code>conf/move.txt&lt;/code> with a load cell (&lt;code>fmove0.force_in = hx0.out0&lt;/code>, &lt;code>fmove0.en = home0.en_out&lt;/code>, &lt;code>home0.pos_in = fmove0.mpos&lt;/code>).&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;p>Motion is calculated in &lt;code>rt&lt;/code>, &lt;code>nrt&lt;/code> prints the status. &lt;code>pos&lt;/code>, &lt;code>vel&lt;/code>, &lt;code>acc&lt;/code> and the limits are in axis units (e.g. m), &lt;code>scale&lt;/code> converts to motor angle. Default &lt;code>scale&lt;/code> = 1000 / 25 * 2pi * 2.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/frf/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/frf/</guid><description>&lt;h1 id="frf">
 FRF
 &lt;a class="anchor" href="#frf">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>frf&lt;/code> measures the frequency response of the mechanics with the position loop running (stepped sine) and fits a two-mass model to it, mainly to find the coupling anti-resonance for &lt;code>conf0.j_lpf&lt;/code>. It is loaded by &lt;code>conf/template/id_frf.txt&lt;/code>, which replaces &lt;code>id_lpf&lt;/code>&amp;rsquo;s ring down and is run before &lt;code>id_pid&lt;/code> (&lt;code>j_lpf&lt;/code> changes the plant the gains are tuned against). It sits between &lt;code>pid0&lt;/code> and the torque controller (after &lt;code>biquad0&lt;/code> if that is loaded):&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/gain/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/gain/</guid><description>&lt;h1 id="gain">
 GAIN
 &lt;a class="anchor" href="#gain">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>gain&lt;/code> computes a velocity dependent factor between 0 and 1. F4 component; not used by any config in &lt;code>conf/&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Output&lt;/strong> (&lt;code>rt&lt;/code>):&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>scale = CLAMP(|vel / MAX(max_vel, 0.1)|, 0, 1)&lt;/code>, i.e. 0 at standstill rising linearly to 1 at &lt;code>max_vel&lt;/code>.&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>vel&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Velocity (rad/s)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>max_vel&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Velocity for factor 1 (rad/s), min 0.1&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>scale&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Factor 0..1&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/gain.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/hal_test/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/hal_test/</guid><description>&lt;h1 id="hal_test">
 HAL_TEST
 &lt;a class="anchor" href="#hal_test">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>hal_test&lt;/code> is a debugging component that burns CPU time in the rt and frt threads to test HAL timing and overrun handling. F4 component; not used by any config in &lt;code>conf/&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Busy loops&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>rt&lt;/code> runs an empty loop &lt;code>rt_wait&lt;/code> times, &lt;code>frt&lt;/code> runs one &lt;code>frt_wait&lt;/code> times. Both default to 0 (no load).&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>rt_wait&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Busy loop iterations per rt period&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>frt_wait&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Busy loop iterations per frt period&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/hal_test.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/home/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/home/</guid><description>&lt;h1 id="home">
 HOME
 &lt;a class="anchor" href="#home">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>home&lt;/code> performs a homing sequence with a home switch by adding a moving offset to a position, and releases the axis with &lt;code>en_out&lt;/code> when homing is done. F4 component, used in &lt;code>conf/move.txt&lt;/code>: &lt;code>home0.pos_in = fmove0.mpos&lt;/code>, &lt;code>rev0.in = home0.pos_out&lt;/code>, &lt;code>home0.home_in = th0.out_not&lt;/code>, &lt;code>fmove0.en = home0.en_out&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;p>All work is done in &lt;code>rt&lt;/code>. The homing velocity is limited to &lt;code>|home_vel|&lt;/code> and changes by at most &lt;code>home_acc&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/hv/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/hv/</guid><description>&lt;h1 id="hv">
 HV
 &lt;a class="anchor" href="#hv">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>hv&lt;/code> runs on the F4 logic board and is its end of the UART link to the F3 power (HV) board. Every rt period it sends the current/voltage command, the commutation angle and velocity, the short brake flags and one word of current loop configuration to the F3, and unpacks the F3 reply (dq feedback, fault code and one word of state such as DC link voltage and temperatures). It also carries the &lt;code>hv&lt;/code> terminal pass-through, the &lt;code>hv_update&lt;/code> F3 firmware update and the &lt;code>hv_verify&lt;/code> read back of the F3 flash. The F3 side of the link is the F3 &lt;code>ls&lt;/code> component (stm32f303/src/comps/ls.c); the F3 bridge driver that shares this name is stm32f303/src/comps/hv.c, documented as page hv_f3.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/hv_f3/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/hv_f3/</guid><description>&lt;h1 id="hv_f3">
 HV_F3
 &lt;a class="anchor" href="#hv_f3">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>hv&lt;/code> on the F3 (HV board) side: it turns the three phase voltages from &lt;code>idq0&lt;/code> into TIM8 compare values that drive the power stage. It adds a dead time compensation, then the space vector (midpoint) common mode offset, keeps every pulse above a minimum on and off time, follows the PWM period that &lt;code>ls0&lt;/code> sets to phase lock the board to the F4, and holds all low sides on while &lt;code>io0&lt;/code> short-circuit brakes. It is loaded by &lt;code>stm32f303/src/main.c&lt;/code> as &lt;code>hv0&lt;/code> (rt_prio 6, after &lt;code>idq0&lt;/code>) and is not configured by the user directly: its settings (&lt;code>drop_k&lt;/code>, &lt;code>drop_knee&lt;/code>, &lt;code>arr&lt;/code>) come from the F4 through &lt;code>ls0&lt;/code>. This page is the F3 component and is published as &lt;code>hv_f3&lt;/code>. The F4-side counterpart, which configures the HV board and sends it the commands, is the &lt;code>hv&lt;/code> component.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/hx711/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/hx711/</guid><description>&lt;h1 id="hx711">
 HX711
 &lt;a class="anchor" href="#hx711">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>hx&lt;/code> (file src/comps/hx711.c) reads up to two HX711 24 bit load cell ADCs connected to the fb1 connector of the F4 logic board by bit-banging their clock and data lines, and outputs the scaled readings as &lt;code>out0&lt;/code>/&lt;code>out1&lt;/code>. conf/template/hx.txt loads it (&lt;code>hx0.gain = 100&lt;/code>); conf/move.txt uses &lt;code>hx0.out0&lt;/code> as force input for &lt;code>fmove0&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Wiring (hw_init)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>Clock (PD_SCK of both chips): fb1 Z line, driven as an output with the Z transmitter enabled.&lt;/li>
&lt;li>Data: DOUT of chip 0 on fb1 line A, DOUT of chip 1 on fb1 line B. &lt;code>data_inv&lt;/code> and &lt;code>clk_inv&lt;/code> are for inverting line drivers/receivers.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Reading (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>timer&lt;/code> counts up by the rt period. Once &lt;code>timer &amp;gt; time&lt;/code> and chip 0 signals a finished conversion (data line low), the component clocks 24 bits out of both chips at the same time, MSB first, then one more clock pulse, which selects channel A with gain 128 for the next conversion. &lt;code>timer&lt;/code> is then reset.&lt;/li>
&lt;li>Each clock half period is a busy loop of &lt;code>sleep&lt;/code> NOPs, so a read blocks &lt;code>rt&lt;/code> for roughly 50 clock half periods.&lt;/li>
&lt;li>Conversion to the outputs:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>out &lt;span style="color:#f92672">=&lt;/span> raw &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">0x7fffff&lt;/span> &lt;span style="color:#f92672">*&lt;/span> gain &lt;span style="color:#f92672">+&lt;/span> offset;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote class="book-hint warning">
&lt;p>The value is shifted once more after the last bit, so &lt;code>raw&lt;/code> is twice the HX711 reading and the sign is taken from bit 22 of the reading instead of bit 23: readings are scaled by 2 (absorbed by &lt;code>gain&lt;/code> when calibrating) and wrap around beyond half of the HX711 input range. Only chip 0 is checked for data ready; chip 1 is assumed to convert in sync. There is no plausibility or saturation check (see the TODO in the code).&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/idacim/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/idacim/</guid><description>&lt;h1 id="idacim">
 IDACIM
 &lt;a class="anchor" href="#idacim">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>idacim&lt;/code> identifies an AC induction motor. A standstill test measures the stator resistance &lt;code>r&lt;/code> (with the inverter dead time voltage &lt;code>drop&lt;/code> separated from it), the leakage inductance &lt;code>l&lt;/code> (sigma*Ls) by injection at two frequencies around the current loop&amp;rsquo;s crossover, and the rotor time constant &lt;code>tr&lt;/code> and rotor side magnetizing inductance &lt;code>lmr&lt;/code> (Lm^2/Lr) by d current steps; an optional current ladder (&lt;code>knee&lt;/code>) fits how tr changes with flux. From these and the motor plate it computes a &lt;code>vf&lt;/code> parameter set. An optional rotating test spins the rotor open loop; with an encoder it first reads &lt;code>tr&lt;/code> and the inertia from up and down speed ramps at two currents, can check &lt;code>tr&lt;/code> with the rotor turning under FOC (&lt;code>rot_tr_vel&lt;/code>), then sweeps the flux, each level at the ramps&amp;rsquo; top emf and at half that speed, and fits the magnetizing curve (&lt;code>acim_flux0.lmr&lt;/code>, &lt;code>lmr_sat&lt;/code>, &lt;code>i_knee&lt;/code>, &lt;code>tr_sat&lt;/code>, &lt;code>i_dip&lt;/code>, &lt;code>lmr_dip&lt;/code>, &lt;code>tr_dip&lt;/code>, &lt;code>acim_foc0.id_n&lt;/code>). A separate pole pair test reads &lt;code>conf0.polecount&lt;/code> and the direction. It runs on the F4 board, drives &lt;code>hv0&lt;/code> directly and is loaded by the &lt;code>id_acim&lt;/code> template.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/iddac/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/iddac/</guid><description>&lt;h1 id="iddac">
 IDDAC
 &lt;a class="anchor" href="#iddac">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>iddac&lt;/code> (loaded by &lt;code>conf/template/id_dac.txt&lt;/code> as &lt;code>id_dac&lt;/code>) is a one shot identification on the F4 board that searches the F3 hardware overcurrent comparator threshold &lt;code>hv0.dac&lt;/code> that trips at a wanted phase current &lt;code>cur&lt;/code> (A peak). It drives &lt;code>hv0&lt;/code> in current mode itself, bisects the dac, and prints the &lt;code>hv0.dac = ...&lt;/code> line to append to the config. Nothing is saved; for normal operation use &lt;code>ocdac&lt;/code> or a fixed &lt;code>hv0.dac&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/iddc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/iddc/</guid><description>&lt;h1 id="iddc">
 IDDC
 &lt;a class="anchor" href="#iddc">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>iddc&lt;/code> identifies a brushed DC motor: winding resistance &lt;code>r&lt;/code>, inductance &lt;code>l&lt;/code> and the torque/back-emf constant &lt;code>psi&lt;/code>, and detects a reversed motor. It runs on the F4 board, drives &lt;code>hv0&lt;/code> on the q axis only (the template sets &lt;code>hv0.phase_mode = 3&lt;/code>, 180 degree 2 phase / H-bridge) and is loaded by the &lt;code>id_dc&lt;/code> template. Afterwards continue with &lt;code>id_mot&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Setup&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>At the console, &lt;code>link id_dc&lt;/code>. The template wires &lt;code>iddc0.en = fault0.en_out&lt;/code>, disables &lt;code>pid0&lt;/code> and the position error fault, and connects &lt;code>hv0.en&lt;/code>, &lt;code>cur_bw&lt;/code>, &lt;code>cmd_mode&lt;/code>, &lt;code>q_cmd&lt;/code>, &lt;code>pos&lt;/code>, &lt;code>rev&lt;/code>, &lt;code>r&lt;/code>, &lt;code>l&lt;/code> to this component and &lt;code>hv0.uq_fb&lt;/code>, &lt;code>iq_fb&lt;/code>, &lt;code>pwm_volt&lt;/code>, &lt;code>vel1.vel&lt;/code> back into it.&lt;/li>
&lt;li>&lt;code>hv0.r&lt;/code> and &lt;code>hv0.l&lt;/code> are wired to this component&amp;rsquo;s &lt;code>r&lt;/code> and &lt;code>l&lt;/code>, so the current loop uses the estimate as it forms. While the state is 0 the nrt function resets &lt;code>r&lt;/code> 0.1 ohm, &lt;code>l&lt;/code> 1 mH, &lt;code>psi&lt;/code> 0.055 and &lt;code>out_rev&lt;/code> 0.&lt;/li>
&lt;li>Set &lt;code>test_cur&lt;/code> and &lt;code>test_vel&lt;/code> after enabling or before; they are not reset.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Resistance and inductance (&lt;code>state&lt;/code> 1.x), rotor blocked&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>When &lt;code>en&lt;/code> goes high the state goes to &lt;code>1.0&lt;/code>; the nrt function prints &amp;ldquo;block the rotor&amp;rdquo; and waits in &lt;code>1.1&lt;/code>. Set &lt;code>iddc0.state = 1.2&lt;/code> to start. &lt;code>en&lt;/code> low returns to &lt;code>0&lt;/code> from any state.&lt;/li>
&lt;li>&lt;code>1.2&lt;/code> (2 s): current mode, &lt;code>cur_bw&lt;/code> 10, &lt;code>q_cmd = test_cur&lt;/code>. &lt;code>r&lt;/code> is low-passed from &lt;code>uq_fb / iq_fb&lt;/code> (factor 0.01 per rt tick). At the end &lt;code>avg_test_volt = test_cur * r&lt;/code>, limited to &lt;code>pwm_volt / 2&lt;/code>.&lt;/li>
&lt;li>&lt;code>1.3&lt;/code> (1 s): voltage mode. &lt;code>q_cmd&lt;/code> alternates every rt tick between &lt;code>1.5 * avg_test_volt&lt;/code> and &lt;code>0.5 * avg_test_volt&lt;/code>; the current and voltage for both levels are low-passed into &lt;code>tmp0&lt;/code>..&lt;code>tmp3&lt;/code> and&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>l &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#f92672">|&lt;/span>tmp1 &lt;span style="color:#f92672">-&lt;/span> tmp3&lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#f92672">|&lt;/span>tmp0 &lt;span style="color:#f92672">-&lt;/span> tmp2&lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">*&lt;/span> period;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;code>1.4&lt;/code> (nrt): prints &lt;code>conf0.r&lt;/code> and &lt;code>conf0.l&lt;/code>, then goes to &lt;code>2.0&lt;/code>, which prints &amp;ldquo;unblock the rotor&amp;rdquo; and waits (in state &lt;code>3.1&lt;/code>).&lt;/li>
&lt;/ul>
&lt;ol start="3">
&lt;li>&lt;strong>Torque constant (&lt;code>state&lt;/code> 2.2), rotor free&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>Set &lt;code>iddc0.state = 2.2&lt;/code>. For 5 s the motor runs in current mode (&lt;code>cur_bw&lt;/code> 250) under a simple speed loop on &lt;code>|vel_fb|&lt;/code> towards &lt;code>test_vel&lt;/code>: the error is limited to &lt;code>test_vel / 100&lt;/code>, integrated with &lt;code>ki&lt;/code> into &lt;code>cur_sum&lt;/code>, and &lt;code>q_cmd = vel_bw * period * error + cur_sum&lt;/code>. &lt;code>q_cmd&lt;/code> has no own limit; only the drive&amp;rsquo;s current limits apply.&lt;/li>
&lt;li>While &lt;code>|vel_fb| &amp;gt; 0.1&lt;/code> rad/s, &lt;code>psi = (uq_fb - iq_fb * r) / vel_fb&lt;/code> is low-passed with time constant &lt;code>pi&lt;/code>.&lt;/li>
&lt;li>At the end a negative &lt;code>psi&lt;/code> is made positive and &lt;code>out_rev = 1&lt;/code> is set. State &lt;code>2.3&lt;/code> (nrt) prints &lt;code>conf0.psi&lt;/code> (Vs/rad = Nm/A) and, if reversed, &lt;code>conf0.out_rev = 1&lt;/code>, then goes to &lt;code>2.4&lt;/code> (done).&lt;/li>
&lt;/ul>
&lt;blockquote class="book-hint warning">
&lt;p>Untested per the template (no DC motor was available). The inductance test uses the per-tick dV/dI method that the &lt;code>idacim&lt;/code> source documents as reading 2x to 6x high (the formula uses the full voltage swing, and the feedback delay makes the one-tick slope unpredictable), so treat &lt;code>l&lt;/code> as a rough value. The 5 s speed test ramps &lt;code>cur_sum&lt;/code> at no more than &lt;code>ki * test_vel / 100&lt;/code> A/s (1 A/s by default), so the motor may not reach &lt;code>test_vel&lt;/code>; &lt;code>psi&lt;/code> is still averaged at whatever speed it reaches. After &lt;code>1.4&lt;/code> the nrt function moves to state &lt;code>3.1&lt;/code> but prints &lt;code>iddc0.state = 2.2&lt;/code> as the start command, which is what you must type.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/idm/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/idm/</guid><description>&lt;h1 id="idm">
 IDM
 &lt;a class="anchor" href="#idm">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>idm&lt;/code> identifies the mechanical parameters of the axis: inertia, viscous damping, coulomb friction and a constant torque offset (e.g. gravity on a vertical axis). It runs on the F4 board and is loaded by the &lt;code>id_mot&lt;/code> template (bare motor, results for &lt;code>conf0.j&lt;/code>, &lt;code>conf0.d&lt;/code>, &lt;code>conf0.f&lt;/code>, &lt;code>conf0.o&lt;/code>) and, through &lt;code>id_sys&lt;/code> (which links &lt;code>id_mot&lt;/code> and sets &lt;code>idm0.sys = 1&lt;/code>), for the inertia of the coupled load (&lt;code>conf0.j_sys&lt;/code>). It moves the axis back and forth through &lt;code>pid0&lt;/code>, adapts the inertia (and first estimates of the others) until the feedback torque of the position/velocity loop no longer correlates with them, then fits friction, damping and offset over constant speed stretches at several speeds. A breakaway test at standstill, the torque it takes to get the axis moving in each direction (static friction and static load, see 5.), is a diagnostic: the &lt;code>id_brk&lt;/code> template runs it on its own, and &lt;code>id_sys&lt;/code> ends with it when &lt;code>brk&lt;/code> is set to 1.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/idpmsm/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/idpmsm/</guid><description>&lt;h1 id="idpmsm">
 IDPMSM
 &lt;a class="anchor" href="#idpmsm">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>idpmsm&lt;/code> identifies a permanent magnet synchronous motor on the drive itself: winding resistance &lt;code>r&lt;/code> together with the inverter dead time curve (&lt;code>hv0.drop_k&lt;/code>, &lt;code>hv0.drop_knee&lt;/code>), d and q inductance &lt;code>ld&lt;/code>/&lt;code>lq&lt;/code>, pole pairs &lt;code>pp&lt;/code>, feedback direction &lt;code>out_rev&lt;/code>, commutation offset &lt;code>com_offset&lt;/code> (plus &lt;code>com_fb_offset&lt;/code> for a commutation track such as &lt;code>encf&lt;/code>&amp;rsquo;s) and flux linkage &lt;code>psi&lt;/code> (plus a per pole back emf map from the F3&amp;rsquo;s &lt;code>emf0&lt;/code>). It runs on the F4 board and is loaded by the &lt;code>id_pmsm&lt;/code> config template, which takes over &lt;code>hv0&lt;/code> (enable, command mode, d/q commands, commutation angle, &lt;code>r&lt;/code>, &lt;code>l&lt;/code>, &lt;code>lq&lt;/code>, current loop bandwidth) and prints the results as &lt;code>conf0.*&lt;/code> and &lt;code>hv0.*&lt;/code> lines to append to the config.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/idq/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/idq/</guid><description>&lt;h1 id="idq">
 IDQ
 &lt;a class="anchor" href="#idq">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>idq&lt;/code> is the inverse of &lt;code>dq&lt;/code>: it turns d/q values (normally the voltages from the current controller) at the rotor angle &lt;code>pos&lt;/code> into the alpha/beta frame (inverse Park) and then into three phase values (inverse Clarke). It runs on the F3 (HV board) as &lt;code>idq0&lt;/code>, loaded by &lt;code>stm32f303/src/main.c&lt;/code> (rt_prio 4): &lt;code>idq0.d/q = curpid0.ud/uq&lt;/code>, &lt;code>idq0.pos = ls0.pos_v&lt;/code> (the voltage angle), &lt;code>idq0.mode = ls0.phase_mode&lt;/code>, &lt;code>ext_sc&lt;/code> = 0, &lt;code>u&lt;/code>/&lt;code>v&lt;/code>/&lt;code>w&lt;/code> go to &lt;code>hv0.u/v/w&lt;/code> and &lt;code>si_out&lt;/code>/&lt;code>co_out&lt;/code> to &lt;code>hv0.si/co&lt;/code>. The old &lt;code>conf/template/linkv3.txt&lt;/code> also loads it on the F4.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/ids/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/ids/</guid><description>&lt;h1 id="ids">
 IDS
 &lt;a class="anchor" href="#ids">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>ids&lt;/code> tunes the gains of the &lt;code>pid&lt;/code> position/velocity loop (&lt;code>pos_bw&lt;/code>, &lt;code>vel_bw&lt;/code>, &lt;code>vel_d&lt;/code>) by moving the axis back and forth on a trapezoid profile between &lt;code>min_pos&lt;/code> and &lt;code>max_pos&lt;/code> and raising one gain at a time while each raise still cuts the tracking-error cost. In speed mode (&lt;code>pos_en = 0&lt;/code>, a spindle) it instead tunes only &lt;code>vel_bw&lt;/code>, from the speed dip under a load torque step at +-&lt;code>max_vel&lt;/code>. It runs on the F4 board and is loaded by the &lt;code>id_pid&lt;/code> template, normally as the last identification step after &lt;code>id_mot&lt;/code> (and &lt;code>id_sys&lt;/code> if a load is coupled). With &lt;code>lpf = 1&lt;/code> (template &lt;code>id_lpf&lt;/code>) it instead measures the coupling resonance and computes &lt;code>conf0.j_lpf&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/idtune/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/idtune/</guid><description>&lt;h1 id="idtune">
 IDTUNE
 &lt;a class="anchor" href="#idtune">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>idtune&lt;/code> tunes the running compensations that &lt;code>idpmsm&lt;/code> does not: &lt;code>hv0.adv&lt;/code>, the commutation advance in seconds (hv sends &lt;code>pos + vel * adv&lt;/code>), and, for the latched dead time sign (&lt;code>hv0.drop_knee = 0&lt;/code>), &lt;code>hv0.drop_k&lt;/code>, the dead time (drop) compensation. With &lt;code>drop_knee &amp;gt; 0&lt;/code> the config&amp;rsquo;s &lt;code>drop_k&lt;/code> from &lt;code>idpmsm&lt;/code>&amp;rsquo;s curve fit is kept. It runs on the F4 board, is loaded by the &lt;code>id_tune&lt;/code> config template and prints &lt;code>hv0.drop_k&lt;/code> and &lt;code>hv0.adv&lt;/code> lines to append to the config.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/idx_home/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/idx_home/</guid><description>&lt;h1 id="idx_home">
 IDX_HOME
 &lt;a class="anchor" href="#idx_home">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>idx_home&lt;/code> implements index homing for LinuxCNC via smart serial: when LinuxCNC requests an index, it switches the feedback from the incremental motor position to the absolute motor position at the next zero crossing. F4 component, loaded by &lt;code>conf/template/sserial.txt&lt;/code>: &lt;code>idx_home0.fb = fb_switch0.mot_fb_no_offset&lt;/code>, &lt;code>idx_home0.fb_abs = fb_switch0.mot_abs_fb_no_offset&lt;/code>, &lt;code>idx_home0.index_en = sserial0.index_out&lt;/code>, &lt;code>sserial0.index_clear = idx_home0.index_clear&lt;/code>, &lt;code>linrev0.fb_in = idx_home0.pos_out&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;p>All work is done in &lt;code>rt&lt;/code>. There is no &lt;code>nrt_init&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/iit/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/iit/</guid><description>&lt;h1 id="iit">
 IIT
 &lt;a class="anchor" href="#iit">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>iit&lt;/code> is an I2t thermal model of the motor: it estimates the motor temperature from the phase current, for motors without a temperature sensor. It runs on the F4 board and is loaded by &lt;code>conf/template/pid.txt&lt;/code>, &lt;code>mpid.txt&lt;/code> and &lt;code>uf.txt&lt;/code> with &lt;code>iit0.cur = hv0.abs_cur&lt;/code>, &lt;code>iit0.max_cur = conf0.max_ac_cur&lt;/code>, &lt;code>iit0.high_temp = conf0.high_mot_temp&lt;/code>, &lt;code>iit0.max_temp = conf0.max_mot_temp&lt;/code>, and &lt;code>fault0.mot_temp = iit0.temp&lt;/code>, so the model derates the current (&lt;code>fault0.scale&lt;/code>) and finally trips a motor over temperature fault.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/io/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/io/</guid><description>&lt;h1 id="io">
 IO
 &lt;a class="anchor" href="#io">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>io&lt;/code> is the hardware I/O of the F3 (HV board). It reads the phase currents, phase voltages, DC link voltage and temperatures from the ADCs, calibrates the current offsets at boot, rebuilds a phase current the ADC could not sample, switches the power stage on and off, raises the HV fault codes (overcurrent, overvoltage, overtemperature, driver fault) and runs the short-circuit brake. It also drives the status LED, the brake output and the DAC reference of the overcurrent comparators. It is loaded by &lt;code>stm32f303/src/main.c&lt;/code> as &lt;code>io0&lt;/code> (rt_prio 1, so it runs right after &lt;code>ls0&lt;/code> and &lt;code>angle0&lt;/code>). The F3 rt runs once per PWM period, at &lt;code>PWM_FREQ&lt;/code>, a build option (10, 15 or 20 kHz, default 15 kHz); tick counts below scale with it where noted.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/io4/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/io4/</guid><description>&lt;h1 id="io4">
 IO4
 &lt;a class="anchor" href="#io4">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>io&lt;/code> (file src/comps/hw/io4.c) is the board I/O driver of the F4 logic board, hardware version 4: status LEDs, fan, digital output &lt;code>out0&lt;/code>, PWM outputs &lt;code>out1&lt;/code>/&lt;code>out2&lt;/code>, the two 24 V inputs, analog reads of the feedback connectors, the raw logic levels of the command and feedback connector lines and the RJ45 LEDs. Templates load it as &lt;code>io0&lt;/code> and typically wire &lt;code>io0.state = fault0.state&lt;/code>, &lt;code>io0.fault = fault0.fault&lt;/code>, &lt;code>io0.fan = fault0.hv_fan&lt;/code>, &lt;code>io0.out0 = fault0.mot_brake&lt;/code> (brake) and the feedback templates drive &lt;code>io0.fb0g&lt;/code>/&lt;code>io0.fb0y&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/ipm/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/ipm/</guid><description>&lt;h1 id="ipm">
 IPM
 &lt;a class="anchor" href="#ipm">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>ipm&lt;/code> estimates the junction temperatures of the power module (IPM) on the F4 board, so the drive can derate and trip on die temperature between the fast overcurrent trips and the slow module NTC. It adds a modelled temperature rise of each of the twelve dies (per leg: high and low IGBT, high and low diode) to the NTC reading. Loaded by conf/template/ipm.txt, which the motor templates (pid, mpid, uf and vf) link at their end, so a config does not link it again (a second &lt;code>link ipm&lt;/code> loads an &lt;code>ipm1&lt;/code> nothing reads): its inputs come from &lt;code>hv0&lt;/code> (&lt;code>ipm0.id = hv0.id_fb&lt;/code>, &amp;hellip;, &lt;code>ipm0.case_temp = hv0.hv_temp&lt;/code>, &lt;code>ipm0.pos = hv0.pos&lt;/code>) and &lt;code>fault0.ipm_temp = ipm0.temp&lt;/code> feeds the derate (&lt;code>conf0.high_ipm_temp&lt;/code>) and the IPM_TEMP_ERROR trip (&lt;code>conf0.max_ipm_temp&lt;/code>) in &lt;code>fault&lt;/code>. The defaults are for the IKCM30F60GD fitted to v5.0 (conf/template/ipm_ikcm30f60gd.txt repeats them); link conf/template/ipm_im06b50gc1.txt after the motor template for the IM06B50GC1.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/jog/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/jog/</guid><description>&lt;h1 id="jog">
 JOG
 &lt;a class="anchor" href="#jog">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>jog&lt;/code> provides terminal commands to jog an axis. F4 component, used in &lt;code>conf/template/jog_cmd.txt&lt;/code> together with &lt;code>stp&lt;/code> (&lt;code>stp0.jog = jog0.jog&lt;/code>).&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Commands&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>jogl&lt;/code> sets &lt;code>jog&lt;/code> to -1, &lt;code>jogr&lt;/code> to 1, &lt;code>jogx&lt;/code> to 0.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Timeout&lt;/strong> (&lt;code>rt&lt;/code>):&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>If no command is received for 0.75 s, &lt;code>jog&lt;/code> returns to 0, so the command has to be repeated (e.g. by holding the key in the terminal) to keep moving.&lt;/li>
&lt;li>The jog state is a global variable, all instances share it.&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>jog&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, -1 = left, 0 = stop, 1 = right&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/jog.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/linrev/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/linrev/</guid><description>&lt;h1 id="linrev">
 LINREV
 &lt;a class="anchor" href="#linrev">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>linrev&lt;/code> converts between machine units (e.g. mm from LinuxCNC) and the motor angle, and counts motor revolutions to turn the wrapped motor angle back into an unwrapped machine position. With a multiturn absolute encoder it can take the revolution count from the encoder instead. F4 component, loaded by &lt;code>conf/template/sserial.txt&lt;/code>: &lt;code>linrev0.cmd_in = sserial0.pos_cmd&lt;/code>, &lt;code>linrev0.fb_in = idx_home0.pos_out&lt;/code>, &lt;code>sserial0.pos_fb = linrev0.fb_out&lt;/code>, &lt;code>linrev0.scale = sserial0.scale&lt;/code>, &lt;code>linrev0.rev_clear = sserial0.index_clear&lt;/code>, &lt;code>linrev0.abs_neg = conf0.mot_fb_rev&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/ls/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/ls/</guid><description>&lt;h1 id="ls">
 LS
 &lt;a class="anchor" href="#ls">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>ls&lt;/code> is the F3 (HV board) end of the serial link to the F4 (3 Mbaud UART, USART3 with DMA, CRC checked packets). It receives the current or voltage command, rotor angle, velocity, enable, mode and braking flags, plus one word of configuration per packet, and puts them on pins for the current loop, ramping the d/q command between packets. It answers with the measured d/q currents, output voltages, the fault code and one word of state per packet. It also locks the F3&amp;rsquo;s PWM period to the F4&amp;rsquo;s packet timing (trimming one period per packet), carries the F3 terminal (one byte each way per packet), holds the enable off until the whole configuration has arrived, disables the bridge when packets stop and can then ask &lt;code>io0&lt;/code> for a short-circuit brake. It is loaded by &lt;code>stm32f303/src/main.c&lt;/code> as &lt;code>ls0&lt;/code> (rt_prio 0.6, the first in the chain). The F4 end of the link is the &lt;code>hv&lt;/code> component.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/mad/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/mad/</guid><description>&lt;h1 id="mad">
 MAD
 &lt;a class="anchor" href="#mad">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>mad&lt;/code> (multiply add) computes &lt;code>out = in * mult + add&lt;/code>. F4 component, used e.g. in &lt;code>conf/spindle_slip_uf.txt&lt;/code> to scale an analog input into a velocity command (&lt;code>mad0.in = io0.in1&lt;/code>, &lt;code>ramp0.vel_ext_cmd = mad0.out&lt;/code>).&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Output&lt;/strong> (&lt;code>rt&lt;/code>):&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>out = in * mult + add&lt;/code>. All pins default to 0.&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Signal&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>mult&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Multiplier&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>add&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Offset&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, in * mult + add&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/mad.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/melody/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/melody/</guid><description>&lt;h1 id="melody">
 MELODY
 &lt;a class="anchor" href="#melody">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>melody&lt;/code> plays a tune through the motor: an audio rate current added to the d-axis command makes the stator hum the notes without torque (with the commutation offset right). It also plays a ready chime after power-up and beeps on &lt;code>identify&lt;/code>, to find which drive is which. F4 component, loaded by &lt;code>conf/template/melody.txt&lt;/code> (&lt;code>link melody&lt;/code> after &lt;code>link pmsm&lt;/code>), which inserts it between the d-axis source and hv:&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/motsim/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/motsim/</guid><description>&lt;h1 id="motsim">
 MOTSIM
 &lt;a class="anchor" href="#motsim">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>motsim&lt;/code> is a simple software model of a PMSM with its own d/q current controller, for testing control components without hardware. It is built into the F4 firmware but no config template loads it; use &lt;code>load motsim&lt;/code> and wire it by hand in place of &lt;code>hv0&lt;/code>: it takes the same &lt;code>d_cmd&lt;/code>/&lt;code>q_cmd&lt;/code>/&lt;code>cmd_mode&lt;/code>/&lt;code>en&lt;/code> and commutation angle, and returns &lt;code>id_fb&lt;/code>, &lt;code>iq_fb&lt;/code>, &lt;code>ud_fb&lt;/code>, &lt;code>uq_fb&lt;/code> and a quantised rotor position &lt;code>pos_fb&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/move/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/move/</guid><description>&lt;h1 id="move">
 MOVE
 &lt;a class="anchor" href="#move">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>move&lt;/code> turns two direction bits into a signed value: &lt;code>out = scale * (fwd - rev)&lt;/code>. F4 component, used in &lt;code>conf/dual_dc_sserial.txt&lt;/code> to drive a DC motor from smart serial outputs (&lt;code>move0.fwd = sserial0.out0&lt;/code>, &lt;code>move0.rev = sserial0.out1&lt;/code>, &lt;code>hv0.d_cmd = move0.out&lt;/code>).&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Output&lt;/strong> (&lt;code>rt&lt;/code>):&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>With both bits set the output is 0.&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>fwd&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Forward, typically 0 or 1&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>rev&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Reverse, typically 0 or 1&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>scale&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Output magnitude&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, scale * (fwd - rev)&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/move.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/mpid/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/mpid/</guid><description>&lt;h1 id="mpid">
 MPID
 &lt;a class="anchor" href="#mpid">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>mpid&lt;/code> is an alternative cascaded position / velocity controller for the F4 board that tracks the position error incrementally, so the error is not limited to +-pi. It outputs a torque command (Nm). It is loaded by &lt;code>conf/template/mpid.txt&lt;/code> with &lt;code>mpid0.pos_ext_cmd = reslimit0.pos_out&lt;/code>, &lt;code>mpid0.vel_ext_cmd = veltime0.vel_lp&lt;/code>, &lt;code>mpid0.pos_fb = fb_switch0.pos_fb&lt;/code>, &lt;code>mpid0.vel_fb = veltime1.vel_lp&lt;/code>, &lt;code>mpid0.en = fault0.en_pid&lt;/code>, and gains / limits from &lt;code>conf0&lt;/code> (&lt;code>pos_p&lt;/code>, &lt;code>vel_p&lt;/code>, &lt;code>vel_i&lt;/code>, &lt;code>j&lt;/code>, &lt;code>max_vel&lt;/code>, &lt;code>max_acc&lt;/code>, &lt;code>max_force&lt;/code>).&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/mux/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/mux/</guid><description>&lt;h1 id="mux">
 MUX
 &lt;a class="anchor" href="#mux">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>mux&lt;/code> selects one of eight banks of ten inputs and copies it to the ten outputs. F4 component, used in &lt;code>conf/spindle_slip_uf.txt&lt;/code> to switch between parameter sets with an input (&lt;code>mux0.mux = io0.ind0&lt;/code>).&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Selection&lt;/strong> (&lt;code>rt&lt;/code>):&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The bank is &lt;code>mux&lt;/code> clamped to 0..7 and truncated to an integer.&lt;/li>
&lt;li>&lt;code>out&amp;lt;i&amp;gt; = in&amp;lt;bank * 10 + i&amp;gt;&lt;/code> for &lt;code>i&lt;/code> = 0..9, e.g. &lt;code>mux&lt;/code> = 1 copies &lt;code>in10&lt;/code>..&lt;code>in19&lt;/code>.&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in0&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in1&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in2&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in3&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in4&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in5&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in6&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in7&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in8&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in9&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in10&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in11&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in12&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in13&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in14&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in15&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in16&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in17&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in18&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in19&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in20&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in21&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in22&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in23&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in24&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in25&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in26&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in27&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in28&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in29&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in30&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in31&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in32&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in33&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in34&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in35&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in36&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in37&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in38&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in39&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in40&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in41&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in42&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in43&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in44&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in45&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in46&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in47&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in48&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in49&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in50&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in51&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in52&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in53&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in54&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in55&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in56&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in57&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in58&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in59&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in60&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in61&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in62&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in63&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in64&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in65&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in66&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in67&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in68&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in69&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in70&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in71&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in72&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in73&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in74&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in75&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in76&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in77&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in78&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in79&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, 8 banks of 10 inputs, bank n is in(10n)..in(10n+9)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out0&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Outputs of the selected bank&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out1&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Outputs of the selected bank&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out2&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Outputs of the selected bank&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out3&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Outputs of the selected bank&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out4&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Outputs of the selected bank&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out5&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Outputs of the selected bank&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out6&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Outputs of the selected bank&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out7&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Outputs of the selected bank&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out8&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Outputs of the selected bank&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out9&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Outputs of the selected bank&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>mux&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Bank select 0..7&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/mux.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/not/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/not/</guid><description>&lt;h1 id="not">
 NOT
 &lt;a class="anchor" href="#not">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>not&lt;/code> is a logic inverter. F4 component, e.g. used to invert an enable input (&lt;code>not0.in = io0.C12&lt;/code>, &lt;code>fault0.en = not0.out&lt;/code>).&lt;/p>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Logic input, true if &amp;gt; 0&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, 1 if in &amp;lt;= 0, else 0&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/not.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/o_fb/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/o_fb/</guid><description>&lt;h1 id="o_fb">
 O_FB
 &lt;a class="anchor" href="#o_fb">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>o_fb&lt;/code> (F4 logic board, hardware v4) turns the A and B lines of the fb0 feedback connector into digital outputs, e.g. to send an encoder or step/dir style signal to another device. No template loads it.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Setup (hw_init)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>Enables the fb0 A and B RS485 transmitters (FB0_A_EN, FB0_B_EN high) and configures the A and B pins as push-pull outputs. The fb0 connector can then no longer be used as a feedback input.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Output (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>Once per rt period, the A line is driven from &lt;code>a&lt;/code> and the B line from &lt;code>b&lt;/code>. The output rate is therefore limited to the rt frequency.&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>a&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, fb0 line A output, &amp;gt; 0 = high&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>b&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, fb0 line B output, &amp;gt; 0 = high&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/src/comps/o_fb.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/obs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/obs/</guid><description>&lt;h1 id="obs">
 OBS
 &lt;a class="anchor" href="#obs">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>obs&lt;/code> component estimates the flux angle and speed from voltage and
current, for a PMSM and an induction motor alike. It generalises
&lt;code>sensorless&lt;/code> (which stays for old configs) and fixes its undamped loop.&lt;/p>
&lt;h2 id="model">
 Model
 &lt;a class="anchor" href="#model">#&lt;/a>
&lt;/h2>
&lt;p>In a frame at angle pos turning at vel, the back emf is&lt;/p>
&lt;p>ed = ud - r id - ld d(id)/dt + vel lq iq
eq = uq - r iq - lq d(iq)/dt - vel ld id&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/ocdac/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/ocdac/</guid><description>&lt;h1 id="ocdac">
 OCDAC
 &lt;a class="anchor" href="#ocdac">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>ocdac&lt;/code> sets the F3 hardware overcurrent comparator threshold &lt;code>hv0.dac&lt;/code> from a trip current in A peak, using a linear map fitted per board. It runs on the F4 board and is loaded by &lt;code>conf/template/ocdac.txt&lt;/code> with &lt;code>hv0.dac = ocdac0.dac&lt;/code> and &lt;code>ocdac0.cur = 20&lt;/code>. Use &lt;code>iddac&lt;/code> (&lt;code>id_dac&lt;/code> template) to find the dac for one current on a given board.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Dac map (nrt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>k &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">MAX&lt;/span>(k, &lt;span style="color:#ae81ff">0.1&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>dac &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">CLAMP&lt;/span>(&lt;span style="color:#a6e22e">roundf&lt;/span>(dac0 &lt;span style="color:#f92672">+&lt;/span> k &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#a6e22e">MAX&lt;/span>(cur, &lt;span style="color:#ae81ff">0&lt;/span>)), dac_min, dac_max);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cur_out &lt;span style="color:#f92672">=&lt;/span> (dac &lt;span style="color:#f92672">-&lt;/span> dac0) &lt;span style="color:#f92672">/&lt;/span> k;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;code>cur_out&lt;/code> shows when &lt;code>dac_min&lt;/code> or &lt;code>dac_max&lt;/code> limited the result.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Calibration&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The comparators see the raw shunt node (2.9 mV/A, about 3.6 counts/A in theory); the measured slope and offset depend on the TIM8 break filter, because the shorter filters trip on switching ringing on top of the current.&lt;/li>
&lt;li>Measured with filter 0xC (the default, periph.c), highest trip of the 60/180/300 deg angles:&lt;/li>
&lt;/ul>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Board&lt;/th>
 &lt;th style="text-align: left">Map&lt;/th>
 &lt;th style="text-align: left">Range&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">X, IKCM30F60GD, 1 Oct 2026&lt;/td>
 &lt;td style="text-align: left">&lt;code>dac0&lt;/code> 115, &lt;code>k&lt;/code> 6.7&lt;/td>
 &lt;td style="text-align: left">dac 215..255, 15..21 A&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">spindle, IM06B50GC1, 6 Oct 2026&lt;/td>
 &lt;td style="text-align: left">&lt;code>dac0&lt;/code> 128, &lt;code>k&lt;/code> 6.48&lt;/td>
 &lt;td style="text-align: left">dac 200..340, 11.3..32.3 A measured id, 0.12 s d pulses&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">Y, IKCM30F60GD, filter 0xF only&lt;/td>
 &lt;td style="text-align: left">&lt;code>dac0&lt;/code> 140, &lt;code>k&lt;/code> 3.5&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;ul>
&lt;li>The defaults are X&amp;rsquo;s. Fit &lt;code>dac0&lt;/code> and &lt;code>k&lt;/code> per board from a few trips (&lt;code>iddac&lt;/code> finds the dac for one current directly) and save them in the config.&lt;/li>
&lt;/ul>
&lt;blockquote class="book-hint warning">
&lt;p>The map is a bench fit for one board and break filter setting; check it on your hardware before relying on it as overcurrent protection.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/or/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/or/</guid><description>&lt;h1 id="or">
 OR
 &lt;a class="anchor" href="#or">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>or&lt;/code> is a four input logic OR. F4 component.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Output&lt;/strong> (&lt;code>rt&lt;/code>):&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>out&lt;/code> = 1 if any of &lt;code>in0&lt;/code>..&lt;code>in3&lt;/code> is &amp;gt; 0, otherwise 0. Unused inputs can stay at their default 0.&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in0&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Logic input, true if &amp;gt; 0&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in1&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Logic input, true if &amp;gt; 0&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in2&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Logic input, true if &amp;gt; 0&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in3&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Logic input, true if &amp;gt; 0&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, 1 if any input is &amp;gt; 0&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/or.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/pe/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/pe/</guid><description>&lt;h1 id="pe">
 PE
 &lt;a class="anchor" href="#pe">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>pe&lt;/code> (power and energy) computes power and energy values of the drive for display on the scope. It runs on the F4 board and is loaded by &lt;code>conf/template/pid.txt&lt;/code> and &lt;code>mpid.txt&lt;/code> with &lt;code>pe0.udc = hv0.dc_volt&lt;/code>, &lt;code>pe0.id/iq = hv0.id_fb/iq_fb&lt;/code>, &lt;code>pe0.torque = pid0.torque_cmd&lt;/code>, &lt;code>pe0.vel = vel1.vel&lt;/code>, &lt;code>pe0.r = conf0.r&lt;/code>, &lt;code>pe0.j = conf0.j&lt;/code>, &lt;code>pe0.cap = 0.00054&lt;/code>. The templates set &lt;code>idc&lt;/code>, &lt;code>ud&lt;/code> and &lt;code>uq&lt;/code> to 0. No component uses the outputs.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/pid/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/pid/</guid><description>&lt;h1 id="pid">
 PID
 &lt;a class="anchor" href="#pid">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>pid&lt;/code> is the standard cascaded position / velocity controller of the F4 board. It turns a position command into a torque command (Nm) using a proportional position loop, a PI velocity loop with inertia scaling, and friction / damping / inertia feedforward. It is loaded by &lt;code>conf/template/pid.txt&lt;/code> (and most machine configs), where &lt;code>pid0.pos_ext_cmd = reslimit0.pos_out&lt;/code>, &lt;code>pid0.vel_ext_cmd = vel0.vel&lt;/code>, &lt;code>pid0.pos_fb = fb_switch0.pos_fb&lt;/code>, &lt;code>pid0.vel_fb = vel1.vel&lt;/code>, &lt;code>pid0.en = fault0.en_pid&lt;/code>, &lt;code>pid0.stop = fault0.rstop&lt;/code>, and &lt;code>pid0.torque_cmd&lt;/code> feeds the torque-to-current component (&lt;code>pmsm_ttc&lt;/code>, &lt;code>dc_ttc&lt;/code>, &amp;hellip;). Gains and limits are linked from &lt;code>conf0&lt;/code> (&lt;code>pos_bw&lt;/code>, &lt;code>vel_bw&lt;/code>, &lt;code>vel_d&lt;/code>, &lt;code>j&lt;/code>, &lt;code>max_vel&lt;/code>, &lt;code>max_force&lt;/code>, &amp;hellip;).&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/pmsm_limits/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/pmsm_limits/</guid><description>&lt;h1 id="pmsm_limits">
 PMSM_LIMITS
 &lt;a class="anchor" href="#pmsm_limits">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>pmsm_limits&lt;/code> estimates the current and torque a PMSM can reach with the available AC voltage: absolute limits, limits at the present operating point, and the limits reachable within the next control period. It is compiled into the F4 firmware; the outputs were meant to feed the torque limits of &lt;code>pid&lt;/code> and the current controller.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;p>All work is done in &lt;code>rt&lt;/code>. Defaults (&lt;code>nrt_init&lt;/code>): &lt;code>ld = 0.001&lt;/code>. The inputs are clamped to &lt;code>lq &amp;gt;= 0.0001&lt;/code>, &lt;code>psi &amp;gt;= 0.01&lt;/code>, &lt;code>r &amp;gt;= 0.001&lt;/code>, and &lt;code>polecount&lt;/code> is truncated to an integer &amp;gt;= 1. With &lt;code>volt = ac_volt&lt;/code>:&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/pmsm_ttc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/pmsm_ttc/</guid><description>&lt;h1 id="pmsm_ttc">
 PMSM_TTC
 &lt;a class="anchor" href="#pmsm_ttc">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>pmsm_ttc&lt;/code> (torque to current) converts a torque command (Nm) into a q-axis current command (peak A) for a permanent magnet synchronous motor, with optional cogging / torque ripple compensation and an experimental block commutation mode. It runs on the F4 board and is loaded by &lt;code>conf/template/pmsm.txt&lt;/code>: &lt;code>pmsm_ttc0.torque = pid0.torque_cmd&lt;/code>, &lt;code>pmsm_ttc0.pos_in = vel2.pos_out&lt;/code>, &lt;code>hv0.q_cmd = pmsm_ttc0.cur&lt;/code>, &lt;code>hv0.d_cmd = pmsm_ttc0.id&lt;/code>, &lt;code>angle0.pos_fb = pmsm_ttc0.pos_out&lt;/code>, with &lt;code>psi&lt;/code> and &lt;code>polecount&lt;/code> from &lt;code>conf0&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/pos_filter/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/pos_filter/</guid><description>&lt;h1 id="pos_filter">
 POS_FILTER
 &lt;a class="anchor" href="#pos_filter">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>pos_filter&lt;/code> smooths a position command with a critically damped second order tracking filter and outputs filtered position, velocity and acceleration. F4 component, see &lt;code>conf/template/pos_filter.txt&lt;/code>: &lt;code>pos_in = rev0.out&lt;/code>, &lt;code>vel_in = rev0.out_d&lt;/code>, &lt;code>reslimit0.pos_in = pos_out&lt;/code>, &lt;code>pid0.vel_ext_cmd = vel_out&lt;/code>, &lt;code>pid0.acc_ext_cmd = acc_out&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;p>All work is done in &lt;code>rt&lt;/code>. &lt;code>bandwidth&lt;/code> must be set (the template uses 1000).&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Filter&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>ki &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#a6e22e">MIN&lt;/span>(bandwidth, &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#f92672">/&lt;/span> period &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kp &lt;span style="color:#f92672">=&lt;/span> ki &lt;span style="color:#f92672">*&lt;/span> ki &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">4&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>acc_out &lt;span style="color:#f92672">=&lt;/span> kp &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#a6e22e">minus&lt;/span>(pos_in, pos_out) &lt;span style="color:#f92672">+&lt;/span> ki &lt;span style="color:#f92672">*&lt;/span> (vel_in &lt;span style="color:#f92672">-&lt;/span> vel_out);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>vel_out &lt;span style="color:#f92672">+=&lt;/span> acc_out &lt;span style="color:#f92672">*&lt;/span> period;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pos_out &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">mod&lt;/span>(pos_out &lt;span style="color:#f92672">+&lt;/span> vel_out &lt;span style="color:#f92672">*&lt;/span> period);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Both poles are at &lt;code>bandwidth&lt;/code> (rad/s). &lt;code>bandwidth&lt;/code> is limited to &lt;code>1 / (2 * period)&lt;/code>.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Enable&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>With &lt;code>en&lt;/code> &amp;lt;= 0 &lt;code>acc_out&lt;/code> is 0.&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>pos_in&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Position (rad)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>vel_in&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Velocity (rad/s)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>pos_out&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Filtered position (rad, +-pi)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>vel_out&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Filtered velocity (rad/s)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>acc_out&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Filtered acceleration (rad/s^2)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>bandwidth&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Filter bandwidth (rad/s), no default&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>en&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Enable filter, pass through if &amp;lt;= 0&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/pos_filter.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/psi/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/psi/</guid><description>&lt;h1 id="psi">
 PSI
 &lt;a class="anchor" href="#psi">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>psi&lt;/code> measures the flux linkage (back EMF constant) of a motor that is turned from outside while the power stage is not driving it. It runs on the F4 board. The working wiring is in &lt;code>conf/experimental/psi.txt&lt;/code>: &lt;code>psi0.u/v/w = hv0.u_fb/v_fb/w_fb&lt;/code>, &lt;code>psi0.dc_volt = hv0.dc_volt&lt;/code>, &lt;code>psi0.vel = vel1.vel&lt;/code>, &lt;code>psi0.polecount = conf0.polecount&lt;/code>, with &lt;code>psi0.psi&lt;/code> and &lt;code>psi0.max_psi&lt;/code> shown on the scope.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;p>All work is done in &lt;code>rt&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/ramp/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/ramp/</guid><description>&lt;h1 id="ramp">
 RAMP
 &lt;a class="anchor" href="#ramp">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>ramp&lt;/code> is a velocity ramp generator with separate acceleration and deceleration limits and an automatic enable output, mainly for spindles in V/f mode. F4 component, used e.g. in &lt;code>conf/haas_spindle*.txt&lt;/code>: &lt;code>ramp0.vel_ext_cmd = avg0.out&lt;/code>, &lt;code>uf0.vel_cmd = ramp0.vel_cmd&lt;/code>, &lt;code>ramp0.max_acc = conf0.max_acc&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;p>All work is done in &lt;code>rt&lt;/code>. &lt;code>max_vel&lt;/code> and &lt;code>max_acc&lt;/code> default to 0 and must be set. &lt;code>max_dec&lt;/code> &amp;lt;= 0 uses &lt;code>max_acc&lt;/code>, so the ramp always decelerates.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/res/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/res/</guid><description>&lt;h1 id="res">
 RES
 &lt;a class="anchor" href="#res">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>res&lt;/code> generates the resolver excitation (reference) signal on the FB0 connector of the F4 board and computes the rotor angle from the demodulated sin/cos signals delivered by the &lt;code>adc&lt;/code> component. It is loaded by &lt;code>conf/template/res_fb0.txt&lt;/code>, which links &lt;code>res0.sin&lt;/code>/&lt;code>cos&lt;/code>/&lt;code>quad&lt;/code> to &lt;code>adc0.sin0&lt;/code>/&lt;code>cos0&lt;/code>/&lt;code>quad&lt;/code>, &lt;code>adc0.res_mode = res0.res_mode&lt;/code>, &lt;code>res0.poles = conf0.mot_fb_polecount&lt;/code>, &lt;code>res0.vel = fb_switch0.mot_vel&lt;/code> and &lt;code>res0.pos&lt;/code> to &lt;code>fb_switch0.mot_pos&lt;/code>/&lt;code>mot_abs_pos&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Reference signal (hw_init and rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>V4 board: TIM4 is clocked by the ADC master timer trigger (TIM3, &lt;code>ADC_TRIGGER_FREQ&lt;/code> = 1.2 MHz). TIM4 channel 3 toggles the reference output on FB0 Z/RES_REF (PD14); the FB0 line driver enable (PD15) is switched on.&lt;/li>
&lt;li>Every rt cycle &lt;code>freq&lt;/code> is rounded to a multiple of the rt frequency (5 kHz) and clamped to 5..20 kHz (the shipped configs use 5 kHz); the rounded value is written back to &lt;code>freq&lt;/code>.&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>mult &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">CLAMP&lt;/span>(freq &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">5000&lt;/span> &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">0.5&lt;/span>, &lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">4&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ARR &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1.2e6&lt;/span> &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#f92672">/&lt;/span> (&lt;span style="color:#ae81ff">5000&lt;/span> &lt;span style="color:#f92672">*&lt;/span> mult) &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>CCR3 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">CLAMP&lt;/span>(phase &lt;span style="color:#f92672">*&lt;/span> ARR, &lt;span style="color:#ae81ff">0&lt;/span>, ARR &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>res_mode &lt;span style="color:#f92672">=&lt;/span> ADC_GROUPS &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#f92672">/&lt;/span> mult; &lt;span style="color:#75715e">// = 12 / mult, ADC sample groups per half wave
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;code>phase&lt;/code> must be tuned so that &lt;code>amp&lt;/code> is maximal (the configs use 0.89..0.9).&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Signal check (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>amp = sqrt(sin^2 + cos^2)&lt;/code>. If &lt;code>amp &amp;lt; min_amp&lt;/code>: &lt;code>error = 1&lt;/code>, &lt;code>state = 0&lt;/code>, &lt;code>pos&lt;/code> is not updated. Otherwise &lt;code>error = 0&lt;/code>, &lt;code>state = 3&lt;/code>.&lt;/li>
&lt;/ul>
&lt;ol start="3">
&lt;li>&lt;strong>Angle (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>pos_e = atan2(sin, cos)&lt;/code> (computed with &lt;code>atan2_fast()&lt;/code>, a polynomial approximation with about 3e-7 rad maximum error), plus a delay compensation of half an rt period: &lt;code>dpos = vel * period / 2&lt;/code>.&lt;/li>
&lt;li>&lt;code>poles = 1&lt;/code>: &lt;code>pos = mod(pos_e + dpos)&lt;/code>.&lt;/li>
&lt;li>&lt;code>poles &amp;gt; 1&lt;/code> (multi-speed resolver): the electrical cycle is counted by watching &lt;code>quad&lt;/code> (quadrant from &lt;code>adc&lt;/code>) change 2 -&amp;gt; 3 (+1) or 3 -&amp;gt; 2 (-1), wrapped to 0..poles-1, and&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>pos &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">mod&lt;/span>((pos_e &lt;span style="color:#f92672">+&lt;/span> cycle &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#f92672">*&lt;/span> pi) &lt;span style="color:#f92672">/&lt;/span> poles &lt;span style="color:#f92672">+&lt;/span> dpos); &lt;span style="color:#75715e">// rad, +-pi
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote class="book-hint warning">
&lt;p>With &lt;code>poles &amp;gt; 1&lt;/code> the cycle counter starts at 0 at power up, so the mechanical position is only relative (not absolute) and a missed quadrant change shifts it by one electrical cycle. The rt code uses the V4 macros &lt;code>RT_FREQ&lt;/code>, &lt;code>ADC_TRIGGER_FREQ&lt;/code> and &lt;code>ADC_GROUPS&lt;/code>, so the component only builds for V4 (the source comment &amp;ldquo;clk = TIM_MASTER(TIM2)&amp;rdquo; is stale, TIM_MASTER is TIM3 on V4).&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/reslimit/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/reslimit/</guid><description>&lt;h1 id="reslimit">
 RESLIMIT
 &lt;a class="anchor" href="#reslimit">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>reslimit&lt;/code> quantizes a position to a given number of steps per turn. In &lt;code>conf/template/pid.txt&lt;/code> and &lt;code>mpid.txt&lt;/code> it sits between the position command and the controller (&lt;code>reslimit0.pos_in = rev0.out&lt;/code>, &lt;code>pid0.pos_ext_cmd = reslimit0.pos_out&lt;/code>) with &lt;code>reslimit0.res = conf0.mot_fb_res&lt;/code>, so the command is limited to the resolution of the motor feedback. It runs on the F4 board.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Quantization&lt;/strong> (in &lt;code>rt&lt;/code>):&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>pos_out &lt;span style="color:#f92672">=&lt;/span> (&lt;span style="color:#66d9ef">int&lt;/span>)(pos_in &lt;span style="color:#f92672">*&lt;/span> res &lt;span style="color:#f92672">/&lt;/span> (&lt;span style="color:#ae81ff">2&lt;/span> pi) &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">0.5&lt;/span>) &lt;span style="color:#f92672">/&lt;/span> res &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> pi;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote class="book-hint warning">
&lt;p>&lt;code>res&lt;/code> must not be 0 (division by zero, TODO in the code). The &lt;code>(int)&lt;/code> cast truncates towards zero, so rounding is wrong for negative positions and the step around 0 is twice as wide (the &amp;ldquo;offset at zerocross&amp;rdquo; TODO).&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/rev/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/rev/</guid><description>&lt;h1 id="rev">
 REV
 &lt;a class="anchor" href="#rev">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>rev&lt;/code> optionally reverses the direction of a position and its derivative. F4 component, normally used on the command path: e.g. &lt;code>rev0.in = vel_int0.pos_out&lt;/code>, &lt;code>rev0.rev = conf0.cmd_rev&lt;/code>, &lt;code>reslimit0.pos_in = rev0.out&lt;/code>, &lt;code>pid0.vel_ext_cmd = rev0.out_d&lt;/code>, and in the sserial templates &lt;code>rev0.in_dd = vel_int0.acc_out&lt;/code>, &lt;code>pid0.acc_ext_cmd = rev0.out_dd&lt;/code> (acceleration feedforward from the host frames).&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Reversal&lt;/strong> (&lt;code>rt&lt;/code>):&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>If &lt;code>rev&lt;/code> &amp;gt; 0: &lt;code>out = minus(0, in)&lt;/code> (negated and wrapped to +-pi), &lt;code>out_d = -in_d&lt;/code> and &lt;code>out_dd = -in_dd&lt;/code>.&lt;/li>
&lt;li>Otherwise the inputs are passed through unchanged.&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Position (rad)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Position, negated if rev &amp;gt; 0 (rad, +-pi)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in_d&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Derivative of the position (rad/s)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out_d&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Derivative, negated if rev &amp;gt; 0 (rad/s)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in_dd&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Second derivative of the position (rad/s^2)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out_dd&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Second derivative, negated if rev &amp;gt; 0 (rad/s^2)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>rev&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Reverse direction if &amp;gt; 0&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/rev.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/rl/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/rl/</guid><description>&lt;h1 id="rl">
 RL
 &lt;a class="anchor" href="#rl">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>rl&lt;/code> is a minimal resistance / inductance measurement that drives &lt;code>hv0&lt;/code> in voltage mode on the d axis. It runs on the F4 board and is loaded by the &lt;code>rl&lt;/code> template. It has no nrt function and prints nothing: the results are read from the &lt;code>r&lt;/code>, &lt;code>ld&lt;/code> and &lt;code>et&lt;/code> pins (the template puts &lt;code>ud_cmd&lt;/code>, &lt;code>hv0.id_fb&lt;/code>, &lt;code>r&lt;/code> and &lt;code>ld&lt;/code> on the scope waves). For a full motor identification use &lt;code>id_pmsm&lt;/code> / &lt;code>idpmsm&lt;/code> instead.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/rlpsij/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/rlpsij/</guid><description>&lt;h1 id="rlpsij">
 RLPSIJ
 &lt;a class="anchor" href="#rlpsij">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>rlpsij&lt;/code> is an experimental all-in-one PMSM identification: resistance, feedback offset, pole pairs, flux &lt;code>psi&lt;/code>, load torque, friction, damping and inertia &lt;code>j&lt;/code> in one automatic sequence. It is built into the F4 firmware but no template in &lt;code>conf/template&lt;/code> loads it, so it has to be loaded and wired by hand (&lt;code>load rlpsij&lt;/code>, then connect &lt;code>cmd_mode&lt;/code>, &lt;code>d_cmd&lt;/code>, &lt;code>q_cmd&lt;/code>, &lt;code>com_pos&lt;/code>, &lt;code>en_out&lt;/code> to &lt;code>hv0&lt;/code>, the &lt;code>hv0&lt;/code> d/q current and voltage feedback back in, and an absolute motor position to &lt;code>abs_pos_fb&lt;/code>). It prints nothing; results are read from the pins. The maintained path is &lt;code>id_pmsm&lt;/code> followed by &lt;code>id_mot&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/scale/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/scale/</guid><description>&lt;h1 id="scale">
 SCALE
 &lt;a class="anchor" href="#scale">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>scale&lt;/code> multiplies one signal by &lt;code>scale&lt;/code> and divides another one by it. F4 component; not used by any config in &lt;code>conf/&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Output&lt;/strong> (&lt;code>rt&lt;/code>):&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>out0 = in0 * scale&lt;/code>, &lt;code>out1 = in1 / MAX(scale, 0.001)&lt;/code>.&lt;/li>
&lt;li>There is no default, so &lt;code>scale&lt;/code> is 0 until set.&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in0&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Signal to multiply&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out0&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, in0 * scale&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>in1&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Signal to divide&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>out1&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, in1 / scale (scale clamped to &amp;gt;= 0.001)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>scale&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Scale factor&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/scale.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/sensorless/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/sensorless/</guid><description>&lt;h1 id="sensorless">
 SENSORLESS
 &lt;a class="anchor" href="#sensorless">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>sensorless&lt;/code> component is responsible for estimating the motor&amp;rsquo;s velocity and position in real-time using electrical measurements. It applies low-pass filtering, back EMF calculation, velocity compensation, and position integration to achieve this.&lt;/p>
&lt;h2 id="description">
 Description
 &lt;a class="anchor" href="#description">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Input Reading and Initialization&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>l&lt;/code> and &lt;code>r&lt;/code> are ensured to be positive.&lt;/li>
&lt;li>The voltage measurements &lt;code>ud&lt;/code> and &lt;code>uq&lt;/code> are updated using a delay line (&lt;code>ud2&lt;/code>, &lt;code>uq2&lt;/code>, &lt;code>ud1&lt;/code>, &lt;code>uq1&lt;/code>, &lt;code>ud&lt;/code>, &lt;code>uq&lt;/code>).&lt;/li>
&lt;li>The current measurements &lt;code>id&lt;/code> and &lt;code>iq&lt;/code> are read from the input pins.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Gain Clamping&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The gains &lt;code>kb&lt;/code>, &lt;code>ki&lt;/code>, and &lt;code>kl&lt;/code> are clamped to ensure they stay within valid ranges.&lt;/li>
&lt;/ul>
&lt;ol start="3">
&lt;li>&lt;strong>Low-Pass Filtering of Current Changes&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The changes in currents &lt;code>delta_id&lt;/code> and &lt;code>delta_iq&lt;/code> are calculated using a low-pass filter. This helps to smooth out noise in the current measurements.&lt;/li>
&lt;li>The previous current values &lt;code>old_id&lt;/code> and &lt;code>old_iq&lt;/code> are updated to the current measurements.&lt;/li>
&lt;/ul>
&lt;ol start="4">
&lt;li>&lt;strong>Back EMF Calculation&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The back EMF (&lt;code>ed&lt;/code> and &lt;code>eq&lt;/code>) is estimated using the motor&amp;rsquo;s electrical equations. The back EMF is the voltage generated by the motor due to its rotation.&lt;/li>
&lt;li>The equations used are:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>ed &lt;span style="color:#f92672">=&lt;/span> ud &lt;span style="color:#f92672">-&lt;/span> r &lt;span style="color:#f92672">*&lt;/span> id &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#a6e22e">PIN&lt;/span>(delta_id) &lt;span style="color:#f92672">*&lt;/span> l &lt;span style="color:#f92672">/&lt;/span> period &lt;span style="color:#f92672">+&lt;/span> vel &lt;span style="color:#f92672">*&lt;/span> l &lt;span style="color:#f92672">*&lt;/span> iq &lt;span style="color:#f92672">*&lt;/span> kb;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>eq &lt;span style="color:#f92672">=&lt;/span> uq &lt;span style="color:#f92672">-&lt;/span> r &lt;span style="color:#f92672">*&lt;/span> iq &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#a6e22e">PIN&lt;/span>(delta_iq) &lt;span style="color:#f92672">*&lt;/span> l &lt;span style="color:#f92672">/&lt;/span> period &lt;span style="color:#f92672">-&lt;/span> vel &lt;span style="color:#f92672">*&lt;/span> l &lt;span style="color:#f92672">*&lt;/span> id &lt;span style="color:#f92672">*&lt;/span> kb;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="5">
&lt;li>&lt;strong>Velocity Compensation&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The estimated velocity &lt;code>vel&lt;/code> is adjusted to compensate for the back EMF. The goal is to make the d-axis back EMF (&lt;code>ed&lt;/code>) approach zero, which helps in stabilizing the control.&lt;/li>
&lt;li>The compensation is done using the following equation:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>vel &lt;span style="color:#f92672">-=&lt;/span> &lt;span style="color:#a6e22e">SIGN2&lt;/span>(eq, &lt;span style="color:#ae81ff">1.0&lt;/span>) &lt;span style="color:#f92672">*&lt;/span> ed &lt;span style="color:#f92672">*&lt;/span> ki &lt;span style="color:#f92672">*&lt;/span> period;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="6">
&lt;li>&lt;strong>Startup Boost&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>If the absolute value of the estimated velocity is below a minimum threshold (&lt;code>min_vel&lt;/code>), a boost is added to help the motor start up more reliably.&lt;/li>
&lt;li>The boost is applied using the following equation:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>vel &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#a6e22e">SIGN2&lt;/span>(id &lt;span style="color:#f92672">*&lt;/span> iq, &lt;span style="color:#ae81ff">0.1&lt;/span>) &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#a6e22e">PIN&lt;/span>(vel_boost);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="7">
&lt;li>&lt;strong>Velocity Limiting&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The estimated velocity is limited to ensure it does not exceed the maximum allowed value (&lt;code>max_vel&lt;/code>).&lt;/li>
&lt;/ul>
&lt;ol start="8">
&lt;li>&lt;strong>Position Update&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The estimated position &lt;code>pos&lt;/code> is updated by integrating the estimated velocity over time.&lt;/li>
&lt;li>The position is wrapped using the &lt;code>mod&lt;/code> function to ensure it stays within a valid range (e.g., 0 to 2π for angular position).&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>r&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Resistance of the motor (R)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>l&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Inductance of the motor (L)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>ki&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Integral gain for velocity compensation&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>kb&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Back EMF gain&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>kl&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Low-pass filter gain for current changes&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>min_vel&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Minimum velocity threshold for startup boost&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>vel_boost&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Velocity boost factor for startup&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>max_vel&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Maximum allowed velocity&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>id&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, D-axis current&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>iq&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Q-axis current&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>ud&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, D-axis voltage (current measurement)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>uq&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Q-axis voltage (current measurement)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>ud1&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>internal&lt;/em>, Delayed D-axis voltage (one sample delay)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>uq1&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>internal&lt;/em>, Delayed Q-axis voltage (one sample delay)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>ud2&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>internal&lt;/em>, Delayed D-axis voltage (two sample delays)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>uq2&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>internal&lt;/em>, Delayed Q-axis voltage (two sample delays)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>vel&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Estimated velocity of the motor&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>pos&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Estimated position of the motor&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>ed&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, D-axis back EMF&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>eq&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Q-axis back EMF&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>old_id&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">Previous D-axis current&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>old_iq&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">Previous Q-axis current&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>delta_id&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Change in D-axis current&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>delta_iq&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Change in Q-axis current&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/sensorless.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/sim/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/sim/</guid><description>&lt;h1 id="sim">
 SIM
 &lt;a class="anchor" href="#sim">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>sim&lt;/code> is a test signal generator. It outputs a sine wave, its first and second integral, a square wave and a ramp, with adjustable amplitude, frequency and offset. It is used to drive a motor or feedback test without a real command, for example &lt;code>conf/template/com_test.txt&lt;/code> links &lt;code>hv0.pos = sim0.vel&lt;/code> to turn the field at a fixed speed, and the &lt;code>pid&lt;/code>, &lt;code>mpid&lt;/code> and &lt;code>uf&lt;/code> templates load it. It runs in the rt.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/siserial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/siserial/</guid><description>&lt;h1 id="siserial">
 SISERIAL
 &lt;a class="anchor" href="#siserial">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>siserial&lt;/code> component is a simple UART link that lets an external controller (for example a microcontroller or PC) send an enable word and two float values to the drive, and receive two float values back. It was adapted from the spietari/stmbl fork and is not used by any config or template in this repository.&lt;/p>
&lt;blockquote class="book-hint danger">
&lt;p>Experimental and F4-only. It uses the same hardware as &lt;code>sserial&lt;/code> and &lt;code>smart_torque&lt;/code> (UART4 TX on PA0, USART1 RX on PA10, TX enable PB7 driven high, &lt;code>DMA1_Stream4&lt;/code> TX, &lt;code>DMA2_Stream5&lt;/code> RX), so only one of these components can be loaded. The link runs at 115200 baud, 8N1.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/sl_seq/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/sl_seq/</guid><description>&lt;h1 id="sl_seq">
 SL_SEQ
 &lt;a class="anchor" href="#sl_seq">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>sl_seq&lt;/code> component starts a motor without an encoder and hands it to
the observer (obs), for a PMSM and an induction motor alike.&lt;/p>
&lt;h2 id="states">
 States
 &lt;a class="anchor" href="#states">#&lt;/a>
&lt;/h2>
&lt;ol start="0">
&lt;li>off: &lt;code>en&lt;/code> = 0. Everything reset, obs tracks.&lt;/li>
&lt;li>align: current &lt;code>i_f&lt;/code> on d at a standing frame for &lt;code>align_time&lt;/code>. PMSM:
the rotor turns onto the d axis. Induction motor: the flux builds (about
3 tr, what align_time 0 uses).&lt;/li>
&lt;li>I/f: the frame turns at &lt;code>f&lt;/code>, which ramps toward &lt;code>vel_cmd&lt;/code> at &lt;code>acc&lt;/code>, with
&lt;code>i_f&lt;/code> on d. The rotor follows the rotating current. obs tracks the frame
below &lt;code>w_hand&lt;/code> / 2, so it starts with the right direction, then runs free.&lt;/li>
&lt;li>observer: angle0 from obs (src 2), d and q from the drive (&lt;code>d_in&lt;/code>, &lt;code>q_in&lt;/code>,
pmsm_ttc0 or acim_foc0), &lt;code>pid_en&lt;/code> = 1, pid closes the speed loop on
obs0.vel_m, while d goes from i_f to d_in over &lt;code>fade_time&lt;/code> so the current
does not step. Entered once obs is ok, |f| &amp;gt;= w_hand and obs ran free
&lt;code>lock_time&lt;/code>. Back to 2 when obs drops ok or |obs0.vel_m| &amp;lt; w_hand - hyst,
with f seeded from obs0.vel_m.&lt;/li>
&lt;/ol>
&lt;p>&lt;code>vel_ref&lt;/code> and &lt;code>acc_ref&lt;/code> replace the command into pid: they follow f in I/f
and, from the handover, ramp from the observed speed to vel_cmd at &lt;code>acc&lt;/code>,
so the handover is bumpless and pid gets acceleration feedforward.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/smart_torque/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/smart_torque/</guid><description>&lt;h1 id="smart_torque">
 SMART_TORQUE
 &lt;a class="anchor" href="#smart_torque">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>smart_torque&lt;/code> component receives an enable word and a torque limit from an external controller over a UART link and sends one float value back. It was adapted from the spietari/stmbl fork. &lt;code>conf/festo.txt&lt;/code> uses it: &lt;code>fault0.en = smart_torque0.enable&lt;/code>, &lt;code>pid0.max_torque = smart_torque0.torque_pos&lt;/code>, &lt;code>pid0.min_torque = smart_torque0.torque_neg&lt;/code> and &lt;code>smart_torque0.out0 = enc_fb0.pos&lt;/code>, so the external controller sets a symmetric torque limit and reads back the position.&lt;/p>
&lt;blockquote class="book-hint danger">
&lt;p>Experimental and F4-only. It uses the same hardware as &lt;code>sserial&lt;/code> and &lt;code>siserial&lt;/code> (UART4 TX on PA0, USART1 RX on PA10, TX enable PB7 driven high, &lt;code>DMA1_Stream4&lt;/code> TX, &lt;code>DMA2_Stream5&lt;/code> RX), so only one of them can be loaded. The link runs at 115200 baud, 8N1.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/smartabs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/smartabs/</guid><description>&lt;h1 id="smartabs">
 SMARTABS
 &lt;a class="anchor" href="#smartabs">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>smartabs&lt;/code> component reads the single-turn position of a Tamagawa SmartABS style serial absolute encoder (2.5 Mbit/s half-duplex RS485). It is used on the F4 board through &lt;code>conf/template/smartabs_fb0.txt&lt;/code>, which links &lt;code>smartabs0.pos&lt;/code> to &lt;code>fb_switch0.mot_pos&lt;/code> / &lt;code>mot_abs_pos&lt;/code>, &lt;code>smartabs0.state&lt;/code> to &lt;code>fb_switch0.mot_state&lt;/code> and &lt;code>smartabs0.error&lt;/code> to &lt;code>fault0.mot_fb_error&lt;/code>.&lt;/p>
&lt;blockquote class="book-hint warning">
&lt;p>Hardware-specific: it uses &lt;code>USART6&lt;/code> TX on PC6 in half-duplex mode, a TX enable on PD15 and &lt;code>DMA2_Stream1&lt;/code>, all hard coded rather than taken from the board&amp;rsquo;s feedback definitions.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/spid/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/spid/</guid><description>&lt;h1 id="spid">
 SPID
 &lt;a class="anchor" href="#spid">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>spid&lt;/code> is a generic single loop PID controller with feedforward, output limits, dynamic anti windup and an output offset. It works on any unit. It is compiled into the F4 firmware but not loaded by any template or config in &lt;code>conf/&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;p>All work is done in &lt;code>rt&lt;/code>. There is no &lt;code>nrt_init&lt;/code>, so all gains and limits start at 0.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Error&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>error = cmd - fb&lt;/code> (not wrapped), limited to +-&lt;code>max_error&lt;/code> when &lt;code>max_error &amp;gt; 0&lt;/code>.&lt;/li>
&lt;li>&lt;code>cmd_d&lt;/code> and &lt;code>error_d&lt;/code> are the derivatives of &lt;code>cmd&lt;/code> and &lt;code>error&lt;/code> over one &lt;code>period&lt;/code>.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Proportional / feedforward part&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>output &lt;span style="color:#f92672">=&lt;/span> cmd &lt;span style="color:#f92672">*&lt;/span> kff0 &lt;span style="color:#f92672">+&lt;/span> cmd_d &lt;span style="color:#f92672">*&lt;/span> kff1 &lt;span style="color:#f92672">+&lt;/span> error &lt;span style="color:#f92672">*&lt;/span> kp &lt;span style="color:#f92672">+&lt;/span> error_d &lt;span style="color:#f92672">*&lt;/span> kd;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>output &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">CLAMP&lt;/span>(output, min_output &lt;span style="color:#f92672">-&lt;/span> offset, max_output &lt;span style="color:#f92672">-&lt;/span> offset);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="3">
&lt;li>&lt;strong>Integrator&lt;/strong> (&lt;code>error_sum&lt;/code>, internal):&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>error_sum += error * ki * period + error_d * kdi * period&lt;/code>.&lt;/li>
&lt;li>&lt;code>ksdi&lt;/code> adds &lt;code>error_d / abs(error) * ksdi * period&lt;/code>, only while the error is larger than 0.1 % of the output range divided by &lt;code>ksdi&lt;/code>.&lt;/li>
&lt;li>The integrator is clamped to the headroom left by the P output (dynamic anti windup) and then added to the output.&lt;/li>
&lt;/ul>
&lt;ol start="4">
&lt;li>&lt;strong>Enable, saturation and offset&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>With &lt;code>en &amp;lt;= 0&lt;/code> the output and integrator are 0, but &lt;code>offset&lt;/code> is still added, so the output is &lt;code>offset&lt;/code> while disabled.&lt;/li>
&lt;li>&lt;code>sat&lt;/code> counts up by &lt;code>period&lt;/code> while the output is at 99 % of &lt;code>min_output&lt;/code> or &lt;code>max_output&lt;/code>, and is reset to 0 immediately otherwise.&lt;/li>
&lt;li>&lt;code>output = output + offset&lt;/code>.&lt;/li>
&lt;/ul>
&lt;blockquote class="book-hint warning">
&lt;p>The &amp;ldquo;scaled differential&amp;rdquo; &lt;code>ksd&lt;/code> term (&lt;code>error_d / abs(error) * ksd&lt;/code>) is added to the integrator, not to the output, and without &lt;code>period&lt;/code>, so it does not behave like a differential term. The 99 % saturation test assumes &lt;code>min_output &amp;lt; 0 &amp;lt; max_output&lt;/code>. Treat &lt;code>ksd&lt;/code>/&lt;code>ksdi&lt;/code> as experimental.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/sserial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/sserial/</guid><description>&lt;h1 id="sserial">
 SSERIAL
 &lt;a class="anchor" href="#sserial">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>sserial&lt;/code> component makes the drive a Mesa smart serial (sserial / LBP) remote, so LinuxCNC&amp;rsquo;s hostmot2 driver can talk to it like a Mesa daughter card (card name &lt;code>stbl&lt;/code>). LinuxCNC sends position and velocity commands, 4 digital outputs, enable, index enable and the &lt;code>linrev&lt;/code> scale; the drive answers with position and velocity feedback, current, 4 digital inputs, fault, index enable and a fault code. On the F4 board it is loaded by &lt;code>conf/template/sserial.txt&lt;/code> (and &lt;code>sserial_dummy.txt&lt;/code>), which feeds &lt;code>sserial0.pos_cmd&lt;/code> / &lt;code>pos_cmd_d&lt;/code> through &lt;code>linrev0&lt;/code> and &lt;code>vel_int0&lt;/code> into the controller, links &lt;code>fault0.en = sserial0.enable&lt;/code>, &lt;code>sserial0.fault_code = fault0.last_fault&lt;/code>, &lt;code>linrev0.scale = sserial0.scale&lt;/code>, &lt;code>sserial0.pos_fb = linrev0.fb_out&lt;/code>, sets &lt;code>sserial0.pos_advance = 0.0003&lt;/code>, &lt;code>sserial0.current = hv0.iq_fb&lt;/code> and &lt;code>io0.clock_scale = sserial0.clock_scale&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/stp/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/stp/</guid><description>&lt;h1 id="stp">
 STP
 &lt;a class="anchor" href="#stp">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>stp&lt;/code> is a simple point to point trajectory planner with velocity and acceleration limits, soft limits and a jog input. F4 component, used in &lt;code>conf/template/jog_cmd.txt&lt;/code> (&lt;code>stp0.jog = jog0.jog&lt;/code>, &lt;code>rev0.in = stp0.mpos&lt;/code>) and &lt;code>conf/festo.txt&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;p>All work is done in &lt;code>rt&lt;/code>. Positions are not wrapped, only &lt;code>mpos&lt;/code> is.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Target generation&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>target&lt;/code> is moved by &lt;code>vel_ext_cmd + jog * max_vel&lt;/code> (limited to 0.99 * &lt;code>max_vel&lt;/code>) and &lt;code>acc_ext_cmd&lt;/code> (limited to 0.99 * &lt;code>max_acc&lt;/code>). &lt;code>vel_ext_cmd&lt;/code> itself is integrated with &lt;code>acc_ext_cmd&lt;/code> and written back.&lt;/li>
&lt;li>&lt;code>target&lt;/code> is clamped to &lt;code>min_pos&lt;/code>..&lt;code>max_pos&lt;/code>.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Planning&lt;/strong> (every period):&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>dtg = target - pos&lt;/code>. The time to stop at the target from standstill with &lt;code>max_acc&lt;/code> is &lt;code>sqrt(2 |dtg| / max_acc)&lt;/code>, rounded up to whole periods (&lt;code>ttg&lt;/code>).&lt;/li>
&lt;li>The velocity for that time is limited to &lt;code>max_vel&lt;/code>; the acceleration needed to reach it in one period is limited to &lt;code>max_acc&lt;/code> and output as &lt;code>acc_cmd&lt;/code>.&lt;/li>
&lt;li>&lt;code>pos&lt;/code> and &lt;code>vel_cmd&lt;/code> are integrated with &lt;code>acc_cmd&lt;/code>.&lt;/li>
&lt;/ul>
&lt;ol start="3">
&lt;li>&lt;strong>Target reached&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>When less than one period to go and &lt;code>|vel_cmd|&lt;/code> &amp;lt; &lt;code>max_acc * period&lt;/code>, &lt;code>pos&lt;/code> is set to &lt;code>target&lt;/code> and &lt;code>vel_cmd&lt;/code> to 0.&lt;/li>
&lt;li>&lt;code>at_target&lt;/code> = 1 when at most one period to go and &lt;code>|vel_cmd|&lt;/code> &amp;lt; &lt;code>max_vel / 10000&lt;/code>.&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>target&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input/output&lt;/em>, Target position, clamped and moved by jog (rad)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>vel_ext_cmd&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input/output&lt;/em>, External velocity, integrated from acc_ext_cmd (rad/s)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>acc_ext_cmd&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, External acceleration (rad/s^2)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>jog&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Jog -1..1, multiplied with max_vel&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>pos&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Planned position, not wrapped (rad)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>mpos&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Planned position, wrapped (rad, +-pi)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>vel_cmd&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Planned velocity (rad/s)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>acc_cmd&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Planned acceleration (rad/s^2)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>max_pos&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Upper soft limit (rad), default 20pi&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>min_pos&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Lower soft limit (rad), default -20pi&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>max_vel&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Maximum velocity (rad/s), default 2pi&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>max_acc&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Maximum acceleration (rad/s^2), default 20pi&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>dtg&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Distance to go (rad)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>ttg&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Time to go (s)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>at_target&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, 1 = target reached&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/stp.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/svm/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/svm/</guid><description>&lt;h1 id="svm">
 SVM
 &lt;a class="anchor" href="#svm">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>svm&lt;/code> adds a common mode offset to three phase voltages centred on 0, so that they fit into the 0..&lt;code>udc&lt;/code> range of the half bridges. The choice of offset sets the modulation: sine, space vector (the default), flat bottom or flat top. It is built into both the F3 (HV board) and the F4 firmware, but &lt;code>stm32f303/src/main.c&lt;/code> no longer loads it: on the F3, &lt;code>hv0&lt;/code> now takes &lt;code>idq0&lt;/code>&amp;rsquo;s phase voltages directly, adds the dead time compensation and then applies the same space vector (midpoint) offset itself, so the offset sees the compensated phases. No template in &lt;code>conf/&lt;/code> loads &lt;code>svm&lt;/code> either, so it is only there to be loaded by hand.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/term/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/term/</guid><description>&lt;h1 id="term">
 TERM
 &lt;a class="anchor" href="#term">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>term&lt;/code> is the serial terminal of a board. It runs the command line (every received line goes to &lt;code>hal_parse&lt;/code>, so HAL commands and pin settings can be typed) and streams the 8 &lt;code>wave&lt;/code> pins as scope samples to the host (the Servoterm oscilloscope). On the F4 it can also take a triggered capture of 1024 samples and upload it. It is loaded by default as &lt;code>term0&lt;/code> on both the F4 and the F3. On the F4 it talks over USB. On the F3 (HV board) there is no USB: its terminal bytes travel one per packet over the link to the F4 (&lt;code>ls&lt;/code> on the F3, &lt;code>hv&lt;/code> on the F4), and main.c sets &lt;code>term0.send_step = 0&lt;/code> there, so no wave data is sent. Typical use on the F4 is a config line like &lt;code>term0.wave0 = pid0.pos_error&lt;/code> with &lt;code>term0.gain0&lt;/code> to scale it (see conf/template/obs_check.txt).&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/th/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/th/</guid><description>&lt;h1 id="th">
 TH
 &lt;a class="anchor" href="#th">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>th&lt;/code> is a window comparator with an input low pass: &lt;code>out&lt;/code> is 1 while the filtered input is between &lt;code>min&lt;/code> and &lt;code>max&lt;/code>. It runs on the F4 board. In &lt;code>conf/move.txt&lt;/code> it detects a hard stop for homing: &lt;code>th0.in = pid0.torque_cmd&lt;/code>, &lt;code>min = -1&lt;/code>, &lt;code>max = 1&lt;/code>, &lt;code>in_lpf = 0.25&lt;/code>, &lt;code>home0.home_in = th0.out_not&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Filter&lt;/strong> (in &lt;code>rt&lt;/code>): &lt;code>in_lp += (in - in_lp) * in_lpf&lt;/code> every rt cycle. &lt;code>in_lpf&lt;/code> is a factor per cycle (0..1), not a frequency.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/uf2/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/uf2/</guid><description>&lt;h1 id="uf2">
 UF2
 &lt;a class="anchor" href="#uf2">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;strong>Deprecated&lt;/strong>: use 
 &lt;a href="https://freakontrol.github.io/stmbl/stmbl/docs/hal_components/vf/">vf&lt;/a> instead (templates &lt;code>vf&lt;/code> and &lt;code>vf_enc&lt;/code>), whose slip compensation is signed and which has damping, stall prevention and an encoder path. &lt;code>uf&lt;/code> is kept for old configs and is not being fixed; its known faults are listed below.&lt;/p>
&lt;p>Open loop V/f (voltage over frequency) control for induction motors, with slip compensation. Note that this file registers the component as &lt;strong>&lt;code>uf&lt;/code>&lt;/strong> (&lt;code>HAL_COMP(uf)&lt;/code>), so it is loaded with &lt;code>load uf&lt;/code> and its pins are &lt;code>uf0.*&lt;/code>; the older &lt;code>uf.c&lt;/code> is no longer built. It runs on the F4 board and is loaded by &lt;code>conf/template/uf.txt&lt;/code>: &lt;code>uf0.u_cmd -&amp;gt; hv0.d_cmd&lt;/code> (with &lt;code>hv0.cmd_mode = 0&lt;/code>, voltage mode), &lt;code>uf0.com_pos -&amp;gt; hv0.pos&lt;/code>, &lt;code>uf0.cur = hv0.abs_cur&lt;/code>, &lt;code>uf0.scale = fault0.scale&lt;/code>, &lt;code>uf0.polecount = conf0.polecount&lt;/code>. The speed command is set by the user, e.g. &lt;code>uf0.vel_cmd = ramp0.vel_cmd&lt;/code> in &lt;code>conf/bene_uf_2kw.txt&lt;/code>.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/usart/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/usart/</guid><description>&lt;h1 id="usart">
 USART
 &lt;a class="anchor" href="#usart">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>usart&lt;/code> is an experimental test component for half-duplex serial absolute encoders on the fb0 connector of the F4 logic board: every rt period it sends a request byte and receives the answer by DMA, extracts a position from the answer and can print the raw bytes. No template loads it.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Hardware (hw_init)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>USART6 in half-duplex mode on PC6 (the fb0 UART TX line), PD15 switches the fb0 RS485 transmitter (FB0_Z_TXEN), DMA2 stream 1 receives up to 16 bytes.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Request (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>Each rt period the USART is re-initialised with baud rate &lt;code>freq&lt;/code>, the transmitter is enabled, the byte &lt;code>req&lt;/code> is sent, &lt;code>rt&lt;/code> busy-waits until it is out, the transmitter is disabled and the RX DMA restarted. The answer is evaluated in the next rt period.&lt;/li>
&lt;/ul>
&lt;ol start="3">
&lt;li>&lt;strong>Position (rt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>Received bytes starting at byte &lt;code>pos_offset&lt;/code> are copied into a 64 bit little endian integer, masked and scaled to &lt;code>pos&lt;/code>:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>pos &lt;span style="color:#f92672">=&lt;/span> raw &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#f92672">*&lt;/span> pi &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>&lt;span style="color:#f92672">^&lt;/span>pos_len &lt;span style="color:#f92672">-&lt;/span> pi;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="4">
&lt;li>&lt;strong>Debug print (rt/nrt)&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>Setting &lt;code>print&lt;/code> &amp;gt; 0 captures the 16 receive bytes (and clears the buffer) and makes &lt;code>nrt&lt;/code> print the request byte, the DMA count and all bytes in binary, LSB first. The next capture is possible once the print is done.&lt;/li>
&lt;/ul>
&lt;blockquote class="book-hint danger">
&lt;p>Experimental and broken as it is: &lt;code>pos_len&lt;/code> is used as a byte count for the copy loop but as a bit count for the mask. With the default the loop writes 20 bytes into an 8 byte variable and reads past the 16 byte receive buffer (stack corruption), and the mask &lt;code>(2 &amp;lt;&amp;lt; pos_len) - 1&lt;/code> keeps one bit more than &lt;code>pos_len&lt;/code>. It only runs without memory corruption for &lt;code>pos_len&lt;/code> &amp;lt;= 8, and then the position has at most 9 bits.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/uvw/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/uvw/</guid><description>&lt;h1 id="uvw">
 UVW
 &lt;a class="anchor" href="#uvw">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>uvw&lt;/code> component turns the three digital hall / commutation signals &lt;code>u&lt;/code>, &lt;code>v&lt;/code>, &lt;code>w&lt;/code> of a motor into a commutation angle with 60 deg resolution. On the F4 board &lt;code>conf/template/uvw_fb0.txt&lt;/code> (or &lt;code>uvw_fb1.txt&lt;/code>) reads the signals from &lt;code>io0.fb0a&lt;/code>, &lt;code>io0.fb0b&lt;/code>, &lt;code>io0.fb0z&lt;/code>, links &lt;code>uvw0.amp = adc0.amp0&lt;/code> and feeds &lt;code>fb_switch0.com_pos&lt;/code>, &lt;code>com_abs_pos&lt;/code> and &lt;code>com_state&lt;/code>. &lt;code>conf/template/encws_fb0.txt&lt;/code> combines it with &lt;code>enc_fb0&lt;/code> in line saving mode (&lt;code>uvw0.mode = 1&lt;/code>).&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Hall code&lt;/strong> (&lt;code>rt&lt;/code>):&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The code is &lt;code>rpos = u + 2 * v + 4 * w&lt;/code> (0..7) and is always written to &lt;code>rpos&lt;/code>, which helps to find the table values while turning the motor by hand.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Code to sector table&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The angle from the sector table &lt;code>p0&lt;/code>..&lt;code>p7&lt;/code> is&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>pos &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">mod&lt;/span>(p[rpos] &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">6.0&lt;/span> &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">2.0&lt;/span> &lt;span style="color:#f92672">*&lt;/span> M_PI);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Defaults set in &lt;code>nrt_init&lt;/code>: &lt;code>p0 = -1&lt;/code>, &lt;code>p1 = 0&lt;/code>, &lt;code>p2 = 2&lt;/code>, &lt;code>p3 = 1&lt;/code>, &lt;code>p4 = 4&lt;/code>, &lt;code>p5 = 5&lt;/code>, &lt;code>p6 = 3&lt;/code>, &lt;code>p7 = -1&lt;/code> (codes 0 and 7 are faults). The table values are truncated to integers.&lt;/li>
&lt;/ul>
&lt;ol start="3">
&lt;li>&lt;strong>Signal check&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>If &lt;code>amp &amp;lt; 0.75&lt;/code>, the component sets &lt;code>error = 1&lt;/code>, &lt;code>state = 0&lt;/code> and resets &lt;code>timer&lt;/code>; &lt;code>pos&lt;/code> is not updated. &lt;code>amp&lt;/code> is meant to carry the feedback signal amplitude (&lt;code>adc0.amp0&lt;/code>); if it is left unlinked it stays 0 and the component is always in error, so link it or set it to 1.&lt;/li>
&lt;/ul>
&lt;ol start="4">
&lt;li>&lt;strong>Mode 0, plain UVW&lt;/strong> (&lt;code>mode = 0&lt;/code>):&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>Valid code (table value &lt;code>&amp;gt;= 0&lt;/code>): &lt;code>state = 3&lt;/code> (absolute), &lt;code>error = 0&lt;/code>, &lt;code>pos&lt;/code> updated.&lt;/li>
&lt;li>Invalid code: &lt;code>error = 1&lt;/code>, &lt;code>state = 0&lt;/code>, &lt;code>pos&lt;/code> keeps its last value.&lt;/li>
&lt;/ul>
&lt;ol start="5">
&lt;li>&lt;strong>Mode 1, line saving&lt;/strong> (&lt;code>mode = 1&lt;/code>):&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>Used by encoders that send the UVW signals on the A/B/Z lines only right after power-up. For the first &lt;code>en_time / 2&lt;/code> seconds after &lt;code>amp&lt;/code> becomes valid, &lt;code>pos&lt;/code> is updated from the table and &lt;code>timer&lt;/code> counts up by the rt period. After that &lt;code>pos&lt;/code> is frozen, &lt;code>state = 2&lt;/code> (start absolute position) and &lt;code>error = 0&lt;/code>, so &lt;code>fb_switch&lt;/code> can take over with the incremental encoder.&lt;/li>
&lt;/ul>
&lt;blockquote class="book-hint warning">
&lt;p>In mode 1 the table value is not checked, so an invalid code (-1) during the startup window gives &lt;code>pos&lt;/code> = -60 deg instead of an error. &lt;code>state&lt;/code> and &lt;code>error&lt;/code> are not written during that window.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/vel/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/vel/</guid><description>&lt;h1 id="vel">
 VEL
 &lt;a class="anchor" href="#vel">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>vel&lt;/code> is a tracking observer (a second order PLL with optional torque feedforward) that estimates velocity and a filtered position from a position signal. It is an F4 component and is loaded several times in the templates: e.g. &lt;code>vel1.pos_in = fb_switch0.vel_fb&lt;/code> with &lt;code>pid0.vel_fb = vel1.vel&lt;/code> gives the velocity feedback, &lt;code>vel2.pos_in = fb_switch0.com_fb&lt;/code> gives a filtered commutation angle for &lt;code>hv0.pos&lt;/code>, and &lt;code>vel0.pos_in = rev0.out&lt;/code> differentiates the position command.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/vel_int/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/vel_int/</guid><description>&lt;h1 id="vel_int">
 VEL_INT
 &lt;a class="anchor" href="#vel_int">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>vel_int&lt;/code> interpolates a position command that arrives at a lower or irregular rate (e.g. from LinuxCNC via smart serial) by integrating the commanded velocity between updates. F4 component, loaded by &lt;code>conf/template/sserial.txt&lt;/code>: &lt;code>vel_int0.pos_in = linrev0.cmd_out&lt;/code>, &lt;code>vel_int0.vel_in = linrev0.cmd_d_out&lt;/code>, &lt;code>rev0.in = vel_int0.pos_out&lt;/code>, &lt;code>rev0.in_d = vel_int0.vel_out&lt;/code> (to &lt;code>pid0.vel_ext_cmd&lt;/code>) and &lt;code>rev0.in_dd = vel_int0.acc_out&lt;/code> (to &lt;code>pid0.acc_ext_cmd&lt;/code>), with &lt;code>vel_int0.max_acc = conf0.max_acc&lt;/code>. It also gives the acceleration feedforward on the sserial path, where &lt;code>vel0&lt;/code> is off and &lt;code>pid.txt&lt;/code>&amp;rsquo;s &lt;code>vel0.acc&lt;/code> link is 0.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/velbuf/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/velbuf/</guid><description>&lt;h1 id="velbuf">
 VELBUF
 &lt;a class="anchor" href="#velbuf">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>velbuf&lt;/code> computes a velocity from a position signal by taking the difference over an adaptive time window from a ring buffer. This gives usable velocities from coarse or slowly changing positions. F4 component, see &lt;code>conf/template/velbuf.txt&lt;/code> (velocity of the position command &lt;code>rev0.out&lt;/code>, used as &lt;code>pid0.vel_ext_cmd&lt;/code>). It needs both an &lt;code>rt_prio&lt;/code> and an &lt;code>frt_prio&lt;/code>: the frt part fills the buffer, without an &lt;code>frt_prio&lt;/code> it never runs.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/veltime/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/veltime/</guid><description>&lt;h1 id="veltime">
 VELTIME
 &lt;a class="anchor" href="#veltime">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>veltime&lt;/code> measures velocity by timing how long it takes until a position changes (period measurement instead of frequency measurement). Useful for low resolution or slowly updating positions. F4 component, runs in &lt;code>frt&lt;/code>. Used in &lt;code>conf/template/mpid.txt&lt;/code>: &lt;code>veltime0.pos = rev0.out&lt;/code>, &lt;code>mpid0.vel_ext_cmd = veltime0.vel_lp&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Measurement&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>timer&lt;/code> is incremented every frt period. When &lt;code>pos&lt;/code> differs from &lt;code>old_pos&lt;/code>, &lt;code>vel = minus(pos, old_pos) / timer&lt;/code>, &lt;code>old_pos&lt;/code> is updated and &lt;code>timer&lt;/code> is reset.&lt;/li>
&lt;li>The velocity is held until the next change.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Standstill&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>If no change happens within &lt;code>max_time&lt;/code>, &lt;code>vel&lt;/code> is set to 0 and &lt;code>timer&lt;/code> is clamped to &lt;code>max_time&lt;/code>. The lowest measurable velocity is therefore about one position step per &lt;code>max_time&lt;/code>.&lt;/li>
&lt;/ul>
&lt;h2 id="pins">
 Pins
 &lt;a class="anchor" href="#pins">#&lt;/a>
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">Name&lt;/th>
 &lt;th style="text-align: left">Description&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>pos&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>input&lt;/em>, Position (rad)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>old_pos&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Position at the last change (internal state, rad)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>timer&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Time since the last position change (internal state, s)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>vel&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Velocity (rad/s)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>vel_lp&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>output&lt;/em>, Low pass filtered velocity (rad/s)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>max_time&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Time without change after which vel is 0 (s), default 0.1&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">&lt;strong>lpf&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;em>parameter&lt;/em>, Cutoff of the vel_lp filter (Hz), default 100&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="references">
 References
 &lt;a class="anchor" href="#references">#&lt;/a>
&lt;/h2>
&lt;p>Source: 
 &lt;a href="https://github.com/freakontrol/stmbl/blob/main/shared/comps/veltime.c">.c File&lt;/a>&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/veltopos/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/veltopos/</guid><description>&lt;h1 id="veltopos">
 VELTOPOS
 &lt;a class="anchor" href="#veltopos">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>veltopos&lt;/code> integrates a velocity command into an electrical angle, with the velocity limited relative to the measured velocity. Intended for open loop / sensorless style commutation. F4 component; it is not used by any config in &lt;code>conf/&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;p>All work is done in &lt;code>rt&lt;/code>. There is no &lt;code>nrt_init&lt;/code>, all pins start at 0.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Acceleration and velocity limit&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>The velocity is clamped to &lt;code>vel_fb +- max_acc * period&lt;/code>, i.e. it may only be ahead of or behind the measured velocity by one period of &lt;code>max_acc&lt;/code>. With &lt;code>max_acc&lt;/code> = 0 the output follows &lt;code>vel_fb&lt;/code>.&lt;/li>
&lt;li>If &lt;code>max_vel&lt;/code> &amp;gt; 0, the result is then limited to +-&lt;code>max_vel&lt;/code>.&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>&lt;strong>Integration&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>pos += vel * polecount * period&lt;/code>, wrapped with &lt;code>mod()&lt;/code>.&lt;/li>
&lt;/ul>
&lt;blockquote class="book-hint warning">
&lt;p>Experimental.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/vf/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/vf/</guid><description>&lt;h1 id="vf">
 VF
 &lt;a class="anchor" href="#vf">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>vf&lt;/code> runs an induction motor open loop, V/f, and replaces uf (uf2.c) for new configs. It is loaded by &lt;code>conf/template/vf.txt&lt;/code>: its frequency &lt;code>vel_e&lt;/code> goes to &lt;code>angle0.vel_cmd&lt;/code> (&lt;code>angle0.src&lt;/code> 3) and its voltage &lt;code>u_cmd&lt;/code> to &lt;code>hv0.d_cmd&lt;/code> in volt mode (&lt;code>hv0.cmd_mode&lt;/code> 0, &lt;code>hv0.q_cmd&lt;/code> 0). &lt;code>en&lt;/code> and &lt;code>scale&lt;/code> come from fault0, the currents and voltages from hv0, &lt;code>dc_hold&lt;/code> from &lt;code>conf0.high_dc_volt&lt;/code>. &lt;code>conf/template/vf_enc.txt&lt;/code> links vf, adds fb_switch and vel and sets &lt;code>vf0.vel_fb = vel0.vel&lt;/code>, &lt;code>vf0.enc = 1&lt;/code> for slip frequency control on an encoder, and &lt;code>vel0.torque = vf0.torque&lt;/code>. The speed command is &lt;code>vf0.vel_cmd&lt;/code> (rad/s mech).&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/yaskawa/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/yaskawa/</guid><description>&lt;h1 id="yaskawa">
 YASKAWA
 &lt;a class="anchor" href="#yaskawa">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>yaskawa&lt;/code> component reads the absolute position of a Yaskawa Sigma serial encoder (as on SGMPH motors) over the F4 board&amp;rsquo;s feedback 0 Z line. It is loaded by &lt;code>conf/sgmph-*.txt&lt;/code> and &lt;code>conf/sda_b.txt&lt;/code>, which link &lt;code>yaskawa0.pos&lt;/code> to &lt;code>fb_switch0.mot_pos&lt;/code> / &lt;code>mot_abs_pos&lt;/code> and &lt;code>yaskawa0.error&lt;/code> to &lt;code>fault0.mot_fb_error&lt;/code>.&lt;/p>
&lt;blockquote class="book-hint danger">
&lt;p>Experimental, F4-only, bit-banged driver. The rt function busy-waits for the previous reply and for the end of the request, so it takes a large part of the rt period. Hardware used: the &lt;code>FB0_Z&lt;/code> pin and its TX enable, &lt;code>TIM8&lt;/code> (8 MHz DMA pacing for the request), the feedback timer channel 3 in input capture mode, &lt;code>DMA2_Stream1&lt;/code> (TX) and &lt;code>DMA1_Stream7&lt;/code> (RX).&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/ypid/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/ypid/</guid><description>&lt;h1 id="ypid">
 YPID
 &lt;a class="anchor" href="#ypid">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>ypid&lt;/code> is a simple cascaded position (P) / velocity (PI) controller whose output &lt;code>out&lt;/code> has no fixed unit (for example a current or torque command). It is compiled into the F4 firmware but not loaded by any template or config in &lt;code>conf/&lt;/code> (the F3 build has it commented out). For normal servo use see &lt;code>pid&lt;/code>.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;p>All work is done in &lt;code>rt&lt;/code>. There is no &lt;code>nrt_init&lt;/code>: all pins start at 0. Negative gains are treated as 0.&lt;/p></description></item><item><title/><link>https://freakontrol.github.io/stmbl/docs/hal_components/zv_ip/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://freakontrol.github.io/stmbl/docs/hal_components/zv_ip/</guid><description>&lt;h1 id="zv_ip">
 ZV_IP
 &lt;a class="anchor" href="#zv_ip">#&lt;/a>
&lt;/h1>
&lt;h2 id="brief">
 Brief
 &lt;a class="anchor" href="#brief">#&lt;/a>
&lt;/h2>
&lt;blockquote class="book-hint danger">
&lt;p>This is an experimental component, it&amp;rsquo;s not fully tested.&lt;/p>
&lt;/blockquote>
&lt;p>The &lt;code>zv_ip&lt;/code> component is responsible for applying a Zero Vibration (ZV) input shaper to the position and velocity commands of a motor. It reads the position and velocity commands, calculates the shaped commands, and outputs them for further processing.&lt;/p>
&lt;h2 id="component-explanation">
 Component Explanation
 &lt;a class="anchor" href="#component-explanation">#&lt;/a>
&lt;/h2>
&lt;p>The &lt;code>zv_ip&lt;/code> component applies a Zero Vibration (ZV) input shaper to the position and velocity commands of a motor. This component operates within a hardware abstraction layer (HAL) framework, providing real-time control and non-real-time initialization functions.&lt;/p></description></item></channel></rss>