STM32 gotchas
3.Advanced timers (TIM1, TIM8, ...) need to have TIMx_BDTR.MOE set to enable output

The timers in STM32 are relatively complex. They come in several flavours, although the basic design is always the same: a single counter with a prescaler, a "slave mode controller" which is mainly a steering unit for clocks and other signals such as reset, one to four (or more in some models) capture-compare (CC) units which interface to external pins, and interface to interrupts and DMA and other signals interconnecting from and to other modules within the mcu.

This is the "normal" "model"; then there are a few stripped-down timers which don't have any CC units nor connectivity to external pins or options for external clocks, serving mostly as timebase; and then there are the "advanced" timers, which have extra features.

ST in the various STM32 models mostly sticks to a the same scheme in numbering timers, i.e. Advanced timers are numbered TIM1, TIM8, TIM20 where available. While ST does not call TIM15, TIM16 and TIM17 as Advanced timers, and while they have only one or two CC channels, they share many of the characteristics of Advanced timers, and the gotcha described here applies to them, too.

As the vast majority of STM32 timers, the Advanced timers are 16-bit, i.e. they have 16-bit counter and the CC registers (CCRx) are 16-bit too. In STM32 models where there is a "slow" and "fast" APB bus, Advanced timers tend to be located on the "fast" bus.

The purpose of the Advanced timers is mainly in providing PWM or PWM-like output for power converters and motor controllers, usually driving one or several half-bridges. This is why Advanced timers have an additional unit on the first three CC channels, providing complementary output, i.e. each CC channel can control two complementary outputs (onto pins TIMx_CHy and TIMx_CHyN).

To be able to "kill" all complementary channels of one timer simultaneously, there is a common enable bit, MOE (Master Output Enable) in the TIMx_BDTR register (together with a couple of other features common to all complementary channels of the timer, e.g. deadtime). This bit has to be set in software, to enable the complementary channels' output towards the pins; it can be cleared in software, but its main purpose is, that it can be cleared by hardware (a.k.a. BREAK), upon various signals, depending on the particular STM32 model.

Often, users, who migrate code from the non-advanced timers, are not aware of the TIMx_BDTR.MOE pin thus don't set it, leading to a frustrating "PWM does not work" problem.