2021-09-09 07:02 AM
I've just been caught by this very same issue:
https://community.st.com/s/question/0D50X00009XkaBXSAZ/rm0090-usart-minimum-attainable-baudrate
At this place I'd like to ask ST to reconsider baudrates generation for both UART and SPI - please connect them to timers, for greater flexibility.
JW
2021-09-10 03:30 AM
It is a pity that ST likes to save transistors and test time. What other peripheral needs that high APB frequency in your case? Probably mostly timers. Can you run APB with a divisor of two and still have full speed at the timers?
2021-09-10 03:42 AM
Some parts have an additional prescaler that's off in some extended init field. Watch when doing cut-n-paste between platforms.
Really wish ST guys had learned to use ADDERS rather than COUNTERS for clock division. This integer stuff is tiresome and naive.
2021-09-10 04:05 AM
Thanks for the comments.
> What other peripheral needs that high APB frequency in your case?
SPI1, and it's crucial to have it at maximum speed.
Luckily, couterparts to UART are PC or own other products, both perfectly adjustable to higher baudrates. So the solution was simply to throw out the 1200 choice from menu. To start the baudrate list with 1200 just happened to be a design decision I made after having merrily forgotten about that limitation. And I do generate the UART registers' content from a template, it's very easy to add a check into it... just I've neglected that... [EDIT] Oh yes the (compile-time) check is there, except that the default value at initialization here is 9600, and the 1200 was chosen afterwards from menu... given enough paranoia a run-time check could be employed, but IMO that's beyond any reason. [/EDIT]
> ADDERS rather than COUNTERS for clock division
Can you please elaborate?
Thanks,
JW
2021-09-10 05:44 AM
Ok, so Counters would be where you increment/decrement by 1, and then have a comparator to see if you've hit the terminal count, ie N-1, next 0 or 0, next N-1
Of these Down Counters are the simplest, as you are checking for a zero count (figure a wide OR), and then you have a static Load register, the combinational logic here being really shallow/clean. See for example how SysTick does it.
These are integer, have 50/50 duty.
The cleverer design is to use an Adder, where you have an Accumulating register, and then a constant (programmable) value you add to it at each clock cycle. Think of it as a phase angle, for 16-bit you always have 1/65536th subdivisions of the whole cycle. You take the High Order Bit(s) as your clock output, you can take multiple and put them through a SINE ROM and get sine wave via a DAC. These adders could be 16, 24 or 32-bit wide depending on how small you want the frequency divisions/granularity.
Now the high order bit might not be exactly 50/50, but it's going to be pretty close, there will be some jitter, but it will be distributed, and long term you'll get the fractional frequency you desire, and certainly adequate for serial comms, and frankly a lot of things which can tolerate jitter of edges in nano-second ranges. (would avoid radio, ethernet, etc)
Perhaps think of it like drawing a diagonal line on a computer display, the center point where it transitions to the next pixel up can change from one section to the next, the fractional error accumulates briefly, but is corrected as soon as possible, and the average comes out with the fractional division you wanted. Compare that to doing one integer division, and applying that over all the line sections, the deviation at the far end will have accumulated a lot of error that isn't addressed, ie you wanted 3.5, to do that you need 3 & 4 alternating, and not 3 & 3 or 4 & 4
2021-09-10 06:04 AM
Say for example I wanted to generate a 13 MHz signal, from a 100 MHz clock source.
Using integer methods, like the STM32 TIM, I could get 12.5 MHz (-4%) or 14.285714 MHz (+10%), whereas my approach would yield 13.000488 MHz for a 16-bit design, and 12.99999999 (ppm) for a 32-bit one
2021-09-10 03:00 PM
You mean an NCO?
2021-09-10 04:36 PM
NCO/DDS if you will, more like a real divider, point being it's not significantly more complicated than the counter method everyone goes with, and that it works with a latched constant, is less of a critical path.
Used a method like this as a baud rate generator in a early 1990's ASICs, also GPS receiver and floppy disk bit-copier.
It would have been better to have decomposed the TIM into some simpler specialized units, and gone 32-bit from the outset, and had some as committed counters for things like encoders.
2021-09-11 05:57 AM
Thanks for the explanation.
> It would have been better to have decomposed the TIM into some simpler specialized units,
Yes, and we can think of other related units such as shift registers. The key is then to have flexible interconnects, so that it all can be used to generate/consume serial streams of varying nature, generate clocks and various framing signals, possibly externally synchronized, all this seamlessly from configured hardware.
JW