stm32: Add support for arbitrary SPI clock rates#14749
stm32: Add support for arbitrary SPI clock rates#14749benpicco merged 65 commits intoRIOT-OS:masterfrom
Conversation
|
Recap of all the measurements so far
Edit: all measured on the nucleo-f103rb with |
|
I've extended the measurements table with numbers for the nucleo-f091rc. |
cpu/stm32/include/periph_cpu.h
Outdated
| SPI_CLK_100KHZ = 100000U, /**< drive the SPI bus with 100KHz */ | ||
| SPI_CLK_400KHZ = 400000U, /**< drive the SPI bus with 400KHz */ | ||
| SPI_CLK_1MHZ = 1000000U, /**< drive the SPI bus with 1MHz */ | ||
| SPI_CLK_5MHZ = 5000000U, /**< drive the SPI bus with 5MHz */ | ||
| SPI_CLK_10MHZ = 10000000U /**< drive the SPI bus with 10MHz */ |
There was a problem hiding this comment.
You can also use the MHZ() and KHZ() macros from macros/units.h here.
|
+1 from my side for the caching version. Really helps on CM0 |
cpu/stm32/periph/spi.c
Outdated
| { | ||
| uint32_t bus_clock = periph_apb_clk(conf->apbbus); | ||
| uint8_t div = bus_clock / (2 * clock); | ||
| if (div > 1) { |
There was a problem hiding this comment.
should be if (div > 0) else if clock = bus_clock / 2 then div = 1 and the function return 1 insteed of 0.
There was a problem hiding this comment.
This should be resolved with the current version
cpu/stm32/periph/spi.c
Outdated
| static uint8_t _get_clkdiv(const spi_conf_t *conf, uint32_t clock) | ||
| { | ||
| uint32_t bus_clock = periph_apb_clk(conf->apbbus); | ||
| uint8_t div = bus_clock / (2 * clock); |
There was a problem hiding this comment.
If you require a speed of 100KHz with 32MHz bus_clock then div = 320 which is truncated to 64 because of uint8_t so you will end up with 500KHz speed.
Also for 128 < div < 255 the function return 8 which is overflow the BR register on the SPE bit and result in bus_clock/2 speed (BR bits are effectively set to 0).
There was a problem hiding this comment.
Thanks for the feedback. I've reworked the function a bit taking your feedback into account. I've also added some DEBUG logging printing the resulting clock speed.
|
I've reworked the code a bit to reduce the error caused by the integer division rounding. There is still a small error between |
|
I retested it and it works pretty well now |
e44b64f to
2f3f1e0
Compare
|
Squashed in a |
|
@benpicco All green! :) |
|
1376 lines deleted, nice! |
|
Thanks for the review! |
Contribution description
This PR removes the need for the SPI divtables on the stm32 platform. It calculates the required divider at runtime so that arbitrary clock rates can be supported. This includes support for clock rates above 10 MHz, where supported by the platform.
The current code is rather conservative with selecting the divider value. It will always result in a clock speed equal or lower than the requested speed. This ensures that the clock speed doesn't exceed what a peripheral supports. As the stm32 SPI peripheral only supports divider values of powers of two, this can result in a significantly lower clock speed than requested. Another option would be to allow configuring a clock speed of a certain percentage above the requested speed.
I've left out the removal of the spi_clkdiv tables to keep the diff minimal.
Testing procedure
This should be tested on different clock rates on the different stm32 families.
Issues/PRs references
None