STM32
=====

Introduction
------------

The timer peripheral is the core part of the SV-PWM driver. It generates the PWM
signals that drive the inverter circuit and it also takes care of synchronizing
ADC measurements made by the current sampling driver.

The driver is designed to work using one of the *advanced control timers*,
usually ``TIM1`` and ``TIM8``. They include specific functionalities that are
crucial to have a performant and safe system :cite:`an4013`.
:numref:`stm32-timer-diagram` shows the diagram of an advanced control timer.

.. _stm32-timer-diagram:
.. figure:: images/stm32-timer-diagram.png

        Advanced control timer diagram :cite:`rm0365`.

PWM generation
--------------

The timer peripheral clock, :math:`\mathrm{f_{TIM}}`, is as fundamental variable
as it controls the timer counting rate. The timer clock is divided by the
prescaler, which is controlled by the ``PSC`` register (16-bit). The counting
rate, :math:`\mathrm{f_{CNT}}`, is defined as:

.. math::

        \mathrm{f_{CNT} = \frac{f_{TIM}}{PSC + 1}}

STM32 timers have multiple PWM modes. The most interesting mode when doing motor
control is the **center-aligned PWM mode**
(:numref:`stm32-timer-centeraligned`). In this mode the counting direction
(up/down) is automatically alternated by the timer. This mode provides an
interesting feature when multiple PWM waveforms are generated such as in a
3-phase inverter. Contrary to edge-aligned modes, in this mode the rising and
falling edges of the PWM signals are not synchronized with the counter
roll-over. Therefore, switching time varies with the duty cycle value and
switching noise is spread. This is a key feature for electric motor drives,
since it allows to double the frequency of the current ripple for a given
switching frequency. For instance, a 10 kHz PWM will generate inaudible 20 kHz
current ripple. This feature also minimizes the switching losses due to the PWM
frequency while guaranteeing a silent operation.

.. _stm32-timer-centeraligned:
.. figure:: images/stm32-timer-centeraligned.svg

        Timing diagram for a timer in center-aligned PWM mode.

Using the above diagram, we can see that the PWM frequency
(:math:`\mathrm{f_{PWM}}`) is given by:

.. math::

        \mathrm{f_{PWM} = \frac{f_{TIM}}{2 \cdot (ARR + 1) \cdot (PSC + 1)}}

where ``ARR`` is the auto-reload register, a 16-bit value. In order to maximize
PWM resolution ``PSC`` should be chosen so that ``ARR`` is maximized while
fitting into its 16-bit register.

.. topic:: ARR calculation example

        Given :math:`\mathrm{f_{TIM} = 72~MHz}` and :math:`\mathrm{f_{PWM} = 30~KHz}`,
        we start with :math:`\mathrm{PSC = 0}`, which leads to:

        .. math::

                \mathrm{ARR = \frac{72~MHz}{2 \cdot 30~KHz \cdot (0 + 1)} - 1 = 1199}.

        As 1199 fits into a 16-bit register, we stick to :math:`\mathrm{PSC = 0}`.

The PWM duty cycle is controlled via the ``CCRx`` registers (``x = 1, 2, ...``).
``CCRx`` value is compared against ``CNT`` so that the PWM signal is active when
``CNT < CCRx``. In case ``CCRx`` is set to zero, the PWM signal is always kept
inactive.

There is an important feature that has to be enabled for ``CCRx`` registers:
pre-load. When pre-load is enabled, the register value is only updated when the
timer update event occurs. This is particular useful for real-time control, as
the new register values are applied synchronously. However in center aligned
mode, we have two update events: overflow (at the end of up cycle) and underflow
(at the end of down cycle). Update event happening on overflow should be avoided
since it is the time when current sampling is likely going to occur, and so the
regulation loop. Repetition counter feature comes to the rescue to solve this
problem. In center-aligned mode, odd values of the repetition counter generate
the update event either on overfow or underflow depending on when the repetition
counter register ``RCR`` was written and the counter launched. If ``RCR`` was
written before starting the counter, the update event will occur on underflow
and on overflow if ``RCR`` was written after starting the counter.

.. figure:: images/stm32-timer-repcnt.png

        Example of repetition counter update event generation :cite:`rm0365`.

Up to now all the details on the signal generation have been given. The only
missing part is now how to expose these signals to the outside via the ``OCx``
pins. This is controlled by the output stage of the capture/compare channel as
seen on :numref:`stm32-cc-output`. In general it is necessary to control both
high and low sides of each inverter leg. For this purpose complementary outputs
can be enabled (``OCxN``). As described in the following section, it is also
possible to insert dead-time when using complementary outputs. Some integrated
drivers do not require complementary signals since they internally take care of
their generation including dead-time insertion.

.. _stm32-cc-output:
.. figure :: images/stm32-cc-output.png

        Output stage of capture/compare channel :cite:`rm0365`.

ADC synchronization
-------------------

As detailed in the :doc:`/theory/currsmp` page, it is crucial to synchronize the
current measurements with the PWM generation. For this purpose, the driver uses
its fourth channel compare unit (``OC4``) to trigger the ADC.  The value of the
``CCR4`` register controlling the signal duty cycle is updated every time phase
voltages are set so that currents are always sampled at an optimal point. The
``OC4`` output is connected to the ``TRGO`` output signal.  The ADC device
managed by the current sampling driver is responsible to connect to this signal
as a trigger source.

Break function
--------------

The break function is used to protect the power stage driven by the PWM signals.
There are two break inputs which are usually connected to fault signals
generated by the power stage circuit (e.g. over-current). When any of the input
is activated a hardware protection mechanism is triggered so that the PWM
outputs are disabled, leaving them in a pre-programmed state. The break
circuitry works asynchronously, that is, it does not depend on any system clock.
This feature makes sure that the circuitry does not suffer from any clock
propagation delay or system clock failures.

.. _stm32-timer-brk:
.. figure:: images/stm32-timer-brk.png

        Break circuitry :cite:`rm0365`.

As shown in :numref:`stm32-timer-brk` ``BRK`` is the result of either an
external event (``BKIN``) or an internal event (``BRK_ACTH``) such as a clock
failure event (refer to :cite:`rm0365` for more details). The first channel,
``BRK``, has priority over ``BRK2``. ``BRK`` can also be configured to either
disable (inactive) or force PWM outputs to a predefined safe state. Furthermore,
a dead-time can be programmed to avoid potential shoot-through when activating
the break functionality. This provides a dual-level protection scheme, where for
instance a low priority protection with all switches off can be overridden by a
higher priority protection with low-side switches active. Let’s consider for
instance that the fault occurs when the high-side PWM is ON, while the safe
state is programmed to have high-side switched OFF and low-side switched ON. At
the time the fault occurs the system will first disable the high-side PWM, and
insert a dead time before switching ON the low side.

.. figure:: images/stm32-timer-brkconf.png

        Typical break use case :cite:`rm0365`.