Hv F3

HV_F3 #

Brief #

hv on the F3 (HV board) side: it turns the three phase voltages from idq0 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 ls0 sets to phase lock the board to the F4, and holds all low sides on while io0 short-circuit brakes. It is loaded by stm32f303/src/main.c as hv0 (rt_prio 6, after idq0) and is not configured by the user directly: its settings (drop_k, drop_knee, arr) come from the F4 through ls0. This page is the F3 component and is published as hv_f3. The F4-side counterpart, which configures the HV board and sends it the commands, is the hv component.

Component Explanation #

  1. Wiring on the F3 (fixed in main.c):
  • hv0.u/v/w = idq0.u/v/w (phase voltages centred on 0; svm0 is no longer loaded, hv takes the offset itself), hv0.udc = io0.udc_duty (the fast link voltage), hv0.arr = ls0.arr, hv0.drop_k = ls0.drop_k, hv0.drop_knee = ls0.drop_knee, hv0.sbrake = io0.sbrake_on, and ls0.duty_max = hv0.duty_max.
  • For the dead time compensation: hv0.d_cmd/q_cmd = ls0.d_cmd/q_cmd, hv0.si/co = idq0.si_out/co_out (sin/cos of the voltage angle angle0.pos_v), hv0.id_fb/iq_fb = dq0.d/q, hv0.cmd_mode = ls0.cmd_mode, hv0.phase_mode = ls0.phase_mode.
  • drop_band, drop_volt, drop_vlp, min_on and min_off are not wired and not F4 config words: they keep their nrt_init defaults unless changed from the F3 terminal.
  • All three half bridges always switch.
  1. PWM period (rt):
  • arr is written to the TIM8 auto reload register every tick. ls0 moves it by a few counts once per F4 packet to lock the PWM to the F4’s packets. nrt_init sets arr = PWM_RES.
  • TIM8 runs centre aligned at 144 MHz (PWM_TIM_CLK), so one PWM period is 2 * ARR ticks. The PWM (and F3 rt) frequency PWM_FREQ is a build option (stm32f303/Makefile, 10, 15 or 20 kHz, default 15 kHz; the F4 reads it back as hv0.pwm_freq), and PWM_RES = PWM_TIM_CLK / (2 * PWM_FREQ) is 7200, 4800 or 3600.
  1. Dead time compensation (rt):
  • While a phase current keeps its sign the bridge loses the dead time’s share of the PWM period times the link voltage. The size of the correction in volts (udc has a floor of 0.1 V):
dt_drop = drop_k * PWM_DEADTIME_TICKS / (2 * pwm_res) * udc;
  • PWM_DEADTIME is the BDTR.DTG code 196, which decodes to 288 ticks (2.0 us), so drop_k = 1 is 3 % of udc at 15 kHz (2 % at 10 kHz, 4 % at 20 kHz). A drop_k below 1 accounts for the part of the dead time the switches’ own delays eat. The result is clamped to 0..10 % of udc, so a mistyped drop_k distorts the waveform but cannot harm the bridge.
  • Its sign per phase comes from a reference current, never the instantaneous measured one (keyed on that, the compensation drives the current it reads and runs away). The reference phase currents iu, iv, iw are built from a d/q reference with si/co (inverse Park and 120 deg inverse Clarke), every tick, also when the compensation is off. si/co belong to the voltage angle, the angle at which this tick’s voltage is applied on average (see angle0.pos_v and ls0.v_lead).
  • Voltage mode (cmd_mode = 0, e.g. the spindle’s V/f): there is no current command, so the reference is the measured id_fb/iq_fb, low pass filtered in the d/q frame with the time constant drop_vlp (floor one period), so the sign follows the fundamental and not the ripple. The compensation is only applied here when drop_volt > 0 (only its sign is used).
  • drop_knee = 0 (default): latched sign. Per phase a Schmitt trigger flips to +1 above drop_band and to -1 below -drop_band and holds its value in between. The sign starts at 0, and rt_start resets it to 0, so nothing is added until a phase has carried current once. The price is a sign that is stale while a zero crossing passes through the band, and an axis that draws less than drop_band never flips it at all.
  • drop_knee > 0 (A): curve instead of latch. Each phase gets dt_drop * k(i) with the sign of its reference current, where
k(i) = 1 - 1 / (1 + |i| / drop_knee)^2;
  • This follows the real loss, which fades out at low current (where the ripple carries the phase through zero inside the PWM period) and settles above a couple of amps. It cannot stick like the latch. drop_knee has a floor of 0.02 A.
  1. Space vector offset (rt):
  • The compensation is added to u, v, w first, then the common mode is chosen on the compensated phases: off = (min + max) / 2 - udc / 2, subtracted from all three, so the midpoint of the highest and lowest phase sits at udc / 2. Because the offset sees the compensation, near full modulation the clamp below no longer cuts it.
  • Each phase is then converted to a compare value, CLAMP(x, 0, udc) / udc * pwm_res.
  1. Minimum on and off time (rt):
  • min_on and min_off are converted to compare units at PWM_TIM_CLK / 2 (one compare unit is 2 timer ticks in centre aligned mode, whatever ARR is), 216 units at 3 us. Both have a floor of the dead time plus 0.5 us (2.5 us): a shorter high side pulse never turns on through the driver interlock, and a shorter low side pulse leaves nothing for the current sample.
  • duty_max = (pwm_res - min_on - min_off) / pwm_res is output every tick (0.91 at the defaults and 15 kHz, 0.94 at 10 kHz, 0.88 at 20 kHz). ls0 scales pwm_volt by it, so curpid0’s voltage limit matches what this stage passes.
  • If the spread between the highest and lowest phase is larger than pwm_res - min_on - min_off, all three are scaled down around their centre (a float scale).
  • Then, judged on the values before any shift: if any phase is above 0 but below min_on, all three are moved up by what the lowest phase lacks (min_on - min); if the highest phase is above pwm_res - min_off, all three are moved down by its excess. The shift is only the deficit, so the neutral moves no more than needed; line to line voltages are unchanged.
  • Finally each phase between 0 and min_on is raised to min_on, and every phase is clamped to 0..pwm_res - min_off. A phase at exactly 0 (low side on for the whole period) is allowed.
  1. Short-circuit braking (rt):
  • While sbrake > 0 (io0.sbrake_on) all three compares are forced to 0, so the low side switches of all phases are on and the back EMF drives current round the windings. io0 switches the bridge on and off to chop that current; hv only provides the compare values.
  1. Output:
  • The values go to PWM_U/V/W (TIM8 CCR3/CCR2/CCR1), inverted when the board defines PWM_INVERT.
  • hv has no enable or fault handling of its own. The bridge is switched on and off by io0 (TIM8 MOE and the driver enable pin) and, on an overcurrent comparator break, by the hardware break plus the TIM8 break interrupt in main.c, so hv keeps writing compare values even while the bridge is off.
  • The voltage mode compensation (drop_volt) is new and off by default; it has not been tried on the spindle yet.
  • The compensation is added on top of the voltage curpid0 was limited to, so near full modulation the spread can exceed pwm_res - min_on - min_off again and the spread scaling cuts it by a few percent.
  • ls0.pwm_volt is computed from the slow io0.udc, while this component divides by the fast io0.udc_duty, so during a fast link voltage change the two limits differ briefly.

Pins #

NameDescription
drop_kinput, Dead time compensation as a fraction of the ideal dead time drop, 0 = off, from ls0.drop_k, default 0
drop_bandparameter, Latched sign flips outside +-drop_band (A), min 0.05, not wired, default 0.5
drop_kneeinput, > 0: knee of the compensation curve on the reference current (A), 0 = latched sign, from ls0.drop_knee
cmd_modeinput, Command mode from ls0, 0 = voltage (reference from id_fb/iq_fb), else current (reference from d_cmd/q_cmd)
phase_modeinput, Phase mode from ls0, the compensation runs only in 120 deg 3ph mode (2)
d_cmdinput, D-axis current command from the F4 (A), reference for the compensation in current mode
q_cmdinput, Q-axis current command from the F4 (A), reference for the compensation in current mode
siinput, Sine of the voltage angle, from idq0.si_out
coinput, Cosine of the voltage angle, from idq0.co_out
iuoutput, Reference U phase current for the compensation sign (A)
ivoutput, Reference V phase current for the compensation sign (A)
iwoutput, Reference W phase current for the compensation sign (A)
drop_voltparameter, > 0 turns the compensation on in voltage mode, not wired, default 0
drop_vlpparameter, Low pass time constant of the voltage mode reference current (s), not wired, default 0.003
id_fbinput, Measured d-axis current (A), from dq0.d, voltage mode reference
iq_fbinput, Measured q-axis current (A), from dq0.q, voltage mode reference
uinput, U phase voltage centred on 0 (V), from idq0.u
vinput, V phase voltage centred on 0 (V), from idq0.v
winput, W phase voltage centred on 0 (V), from idq0.w
udcinput, DC link voltage (V), from io0.udc_duty, scales the PWM, min 0.1
min_onparameter, Minimum on time (s), floored at dead time + 0.5 us, default 3 us
min_offparameter, Minimum off time (s), floored at dead time + 0.5 us, default 3 us
duty_maxoutput, Usable duty after min_on and min_off (0..1), to ls0.duty_max
arrinput, PWM timer reload value from ls0.arr, clamped to 90..110 % of PWM_RES (4800 at 15 kHz)
sbrakeinput, Short-circuit braking from io0.sbrake_on, > 0 forces all compares to 0 (all low sides on)

References #

Source: .c File