The CCR register is a 32 register that takes a 16 bit value. Ok. However if you feed it from an array of 32bit ints, you get different behaviour if you feed with 16bit ints. 8 bit ints don't work.
Worse yet. If you DMA transfer to the CCR register byte by byte, it goes nuts. If you transfer to it in half words it works, if you transfer to it in 32bit full words, it runs at half speed. WTF?
Don't know which STM32 you are using, but from several RMs, when timer registers are described one can read this:
The peripheral registers must be written by half-words (16 bits) or words (32 bits). Read accesses can be done by bytes (8 bits), half-word (16 bits) or words (32 bits)
So, no, 8 bits writes are not allowed.
That much was apparent. I suppose I should dig in and find out how it behaves when you send it as half words or full words, especially when it contains 16 bit ints.
I'm still a little baffled, as in my normal day world of very strong types I dont have 8 bit ints masquerading as 32 bit ones or vice versa, but I do in STM C.
To explain.
My PWM "period" is 90 OCC cycles for 800kHz with a 72Mhz clock. (ARR=90) <--- Or is it? Sometimes the bus clock is 50% OCC.
My PWM duty cycles are 33% (30) or 67% (61) CCR is fed by DMA.
Normally / ideally those numbers 30, 67 fit into uint8_t to save memory. However knowing that the CCR register takes 16 bit values I decided to use uint16_t to store them. Great so far.
However the DMA transfer function takes a uint32_t* for it's data to send and an ambiguous parameter, "Length". Note, not Size, but Length. I believe I have even seen it referred to as "The number of items to send"... what are items?
Now my figuring is, if I have 2400 uint16_t values I should be passing the Length 2400/2 for 32bit pointers. However I am no longer entirely sure this is correct as to how it behaves.
So now the seed of doubt is planted we come to the DMA configuration itself. It allows byte, half word, full word. Tutorials, as I said, always just shrug and say it doesn't matter, pick half word as it's the default. Turns out it does absolutely matter.
The annoying thing is, it's so slippery and ambiguous. So, so many blind explicit casts of datatypes and pointers there is no protection at all from weird alignment disorders.
Maybe more RTFM and more investigations will make it clearer to me, but for a newbie to STM world it's always this kind of stuff that gets really confusing, really fast and wastes hours and hours on abiguity. I figure reading the entire 300+ page reference manual will help... however having been down that route in Application Notes for PCB layout, it's the SAME SHIT. The notes are stacked and apply to a dozen different MCUs ALL with DIFFERENT aspects. It makes the App Notes and Reference manuals really difficult to track. "The ABC is enabled (F0-only) when the F4 would enable it's DEF, unless you need the RRT of the F4 then ...." etc. "The widget can be used (except in F1) when the CCF1 register (Not available on all packages) is high...."
For now I am assuming... to retain sanity...
I store 16bit CCR register values in a 16bit uint array.
I send Half words, aka 16bit words to the CCR register via DMA
When I sent the array as a 32bit uint pointer, I halve the length.
If I leave all of that alone, my frequency and duty cycle values should remain non-insane.
Anyway, now that I got that working, todays "It's quiet in work" is trying to get the F030 to animate 100 WS2812s. The F1 was too easy. Note 100 LEDs will more than fill the memory twice on the F030F4. I only moved to an F1 because I wanted to stop dealing with heap and stack crashes until I got the LEDs at least working. I've been tempted to just ASM bit bang them. It's not like there will be much left of the F030F4 to do anything else while the DMA is transfering.
EDIT:
ld.exe: region `RAM' overflowed by 56 bytes
Hmmmm..... what needs to go.