STM32 gotchas
40.First TIM period is too short, prescaler does not work - PSC is preloaded; and so is RCR

Some timer registers are preloaded, which means, that writing to the given register does not write the actual "working" register, but an "intermediate" register1; and transfer value from "intermediate" to "working" register at the Update event. Update event is typically generated at counter overflow/underflow; but it has several other possible sources, some of which can be disabled - for the exhaustive details, see the TIM chapter in RM.

The reason for preloading registers is twofold - changing some of the registers "on the run" may lead to confusing results (e.g. changing ARR to a value below current CNT value would result in CNT to count up all the way to its upper limit, 0xFFFF or 0xFFFF'FFFF depending on counter width). The other reason is, that some registers are best to be changed at once at one given point - e.g. it's usually required to change PWM period and duty cycle at once.

Preloading of some of the registers is optional, e.g. ARR is preloaded only if CR1.ARPE=1, CCRx is preloaded only if the respective CCMRx.OCxPE=12. On the other hand, the prescaler (PSC) and - in timers where it's available - the repetition-count register (RCR) are preloaded unconditionally. This means, that after loading them, their new value won't get "accepted" until an Update event occurs. So, as a practical consequence, unless this "acceptance" is "forced", the first timer period after setting PSC is run with the old PSC setting As PSC after reset is by default 0, i.e. no prescaling, the first timer period appears to be too short for those unaware of the PSC preload.

One way to "force" "acceptance" of new values into PSC and/or RCR is to generate Update "artificially", by setting EGR.UG. Note, that this - as with any Update - results also in setting SR.UIF, so if there's any related interrupt or DMA enabled by DIER.UIE or DIER.UDE, the interrupt gets activated and DMA performs the associated transfer.

1. ST uses the term "shadow" register for what is called here "working" register. As probably many users would associate "shadow" with "intermediate" rather than "working", "shadow" is not used here.
2. In some timers (advanced, with complementary outputs), CCER.CCxE, CCER.CCxNE and CCMRx.OCxM bits can be preloaded, but they are not loaded to their "working" counterparts upon Update event, but upon Commutation/Trigger event. This is aimed at changing the output mode of all channels at once, upon a one-off stimulus/signal, mainly to be used in motor-control applications.