Turns out, it pays out to read documentation to the end... Wavedrom does have "arrows" to denote causal relationships.
OTOH, whether the result is more illustrative than the textual version above, is questionable... it also took me considerably more time to generate it.
JW
[picture would come here, but embedding pictures doesn't work for me, sorry, please click on the thumbnail]
a, f, k, t, y -- when CNT==ARR, CNT is zeroed and UPdate event is generated
d, i, n, u, z -- UPdate event causes the value from buffer-CCR1
to be transferred into acting-CCR1
b, g, l -- if acting-CCR1>ARR, Compare (CC1) event is generated at UPdate
q, v -- if acting-CCR1<=ARR (as is usual), CC1 event is generated
when CNT==acting_CCR1
c, h, m, r, w -- DMA is set so that it is triggered by the CC1 event;
it takes some time until DMA fulfills the request by transferring data from
memory to buffer-CCR1, here we used as an example 5 timer-cycles
e, j, o, s, x -- DMA transfers value from buffer in RAM into buffer-CCR1
and increments the pointer into memory (DMA_MAR)
Note, that in the period between k and t there are two DMA transfers. This means,
that there's one less timer period than total DMA transfers, thus one less pulse
in the observed pulsetrain. The value 1500 from memory buffer position 8 (marked
as 1500 [1]) gets overwritten in the buffer-CCR1 by the next value (1500 [2])
before UPdate, i.e. it never contributes to pulse generation, so between
the 1200- and 500-pulse there are only two 1500-pulses, instead of three.
Remedy is simple, for PWM, perform the DMA-to-CCRx transfer upon UPdate event,
not upon the CCRx event. In that way, there's exactly one transfer per period.
CCRx buffering ensures that whatever the DMA transfer delay is, the new value
won't be used in this particular period, but in the next period (after the next
UPdate event transfers this value from buffer-CCRx into acting-CCR).