Skip to content

stm32: Add support for arbitrary SPI clock rates#14749

Merged
benpicco merged 65 commits intoRIOT-OS:masterfrom
bergzand:pr/stm32/dynamic_spi_freqs
Aug 18, 2020
Merged

stm32: Add support for arbitrary SPI clock rates#14749
benpicco merged 65 commits intoRIOT-OS:masterfrom
bergzand:pr/stm32/dynamic_spi_freqs

Conversation

@bergzand
Copy link
Copy Markdown
Member

@bergzand bergzand commented Aug 12, 2020

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

@bergzand bergzand added Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation Discussion: RFC The issue/PR is used as a discussion starting point about the item of the issue/PR Area: drivers Area: Device drivers labels Aug 12, 2020
@bergzand bergzand requested a review from aabadie August 12, 2020 12:45
@bergzand
Copy link
Copy Markdown
Member Author

bergzand commented Aug 14, 2020

Recap of all the measurements so far

commit note nucleo-f103rb nucleo-f091rc
master 5.39 μs 8.20 μs
0b24d3a iterative approach 5.97 - 7.32 μs 8.91 - 10.50 μs
9645b8d bitarithm_msb(apb_clock/spi_clock) 5.86 μs 10.30 μs
d2da736 caching 5.55 μs 8.47 μs

Edit: all measured on the nucleo-f103rb with tests/periph_spi

@bergzand bergzand changed the title [RFC] stm32: Add support for arbitrary SPI clock rates stm32: Add support for arbitrary SPI clock rates Aug 14, 2020
@bergzand bergzand removed the Discussion: RFC The issue/PR is used as a discussion starting point about the item of the issue/PR label Aug 14, 2020
@bergzand
Copy link
Copy Markdown
Member Author

I've extended the measurements table with numbers for the nucleo-f091rc.

Comment on lines +629 to +633
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 */
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also use the MHZ() and KHZ() macros from macros/units.h here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@benpicco
Copy link
Copy Markdown
Contributor

+1 from my side for the caching version. Really helps on CM0

{
uint32_t bus_clock = periph_apb_clk(conf->apbbus);
uint8_t div = bus_clock / (2 * clock);
if (div > 1) {
Copy link
Copy Markdown
Contributor

@hugueslarrive hugueslarrive Aug 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be if (div > 0) else if clock = bus_clock / 2 then div = 1 and the function return 1 insteed of 0.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be resolved with the current version

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);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

hugueslarrive pushed a commit to hugueslarrive/RIOT that referenced this pull request Aug 17, 2020
hugueslarrive pushed a commit to hugueslarrive/RIOT that referenced this pull request Aug 17, 2020
hugueslarrive pushed a commit to hugueslarrive/RIOT that referenced this pull request Aug 17, 2020
@bergzand
Copy link
Copy Markdown
Member Author

I've reworked the code a bit to reduce the error caused by the integer division rounding. There is still a small error between BR = 0 and BR = 1, but I would consider this to be negligible enough to ignore for now.

@hugueslarrive
Copy link
Copy Markdown
Contributor

I retested it and it works pretty well now

@bergzand bergzand force-pushed the pr/stm32/dynamic_spi_freqs branch from e44b64f to 2f3f1e0 Compare August 18, 2020 14:55
@bergzand
Copy link
Copy Markdown
Member Author

Squashed in a DEBUG formatter fix for llvm.

@bergzand
Copy link
Copy Markdown
Member Author

@benpicco All green! :)

@benpicco benpicco merged commit 4a2d867 into RIOT-OS:master Aug 18, 2020
@benpicco
Copy link
Copy Markdown
Contributor

1376 lines deleted, nice!

@bergzand
Copy link
Copy Markdown
Member Author

Thanks for the review!

@bergzand bergzand deleted the pr/stm32/dynamic_spi_freqs branch August 18, 2020 15:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: drivers Area: Device drivers CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: cleanup The issue proposes a clean-up / The PR cleans-up parts of the codebase / documentation Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants