Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers/periph/spi: added means to make SPI thread-safe #2290

Merged
merged 2 commits into from
Jan 19, 2015

Conversation

haukepetersen
Copy link
Contributor

extended the SPI driver's API with locking/unlocking functions and implemented them exemplary for the stm32f4.

These functions are needed for applications that share a SPI bus for more then one slave device, e.g. 2 sensors, while their drivers run in separate threads.

Usage:

...
spi_aquire(SPI_x);
gpio_set(CS_PIN);
spi_transfer(SPI_X, ...);
gpio_clear(CS_PIN);
spi_release(SPI_X);
...

The price to pay:

for 1 configured SPI interface:    84 byte ROM and  8 byte RAM
for 2 configured SPI interfaces:  112 byte ROM and 16 byte RAM
(compiling the tests/periph_spi application)

@haukepetersen haukepetersen added Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation Area: drivers Area: Device drivers labels Jan 13, 2015
@jnohlgard
Copy link
Member

I think the memory bytes is a small price to pay for the thread safety of our device drivers. Errors caused by these kinds of race conditions will be extremely difficult to reproduce or locate when they bite you, adding a simple NOP somewhere completely unrelated could potentially make such a problem hide again.

👍 for the API, it is similar to what is being used in ChibiOS (which has been around for a very long time), so the general idea has already been tested thoroughly.

I was thinking of whether to put spi_acquire in a common file for all ports, but I believe that it is better to keep all SPI related functions in one file. It also opens the possibility for some corner cases where you would want to customize the locking mechanism (I have something in mind for kinetis_common #2265 ).

@PeterKietzmann
Copy link
Member

I also think that the price is ok for the benefit we get. Should we maybe adapt the test? Or extend it?

@haukepetersen
Copy link
Contributor Author

@gebart I wouldn't put the locking in a central file, as there might be platforms where the locking can be handled more efficient without mutexes or similar. Also the additional implementation effort is not too high...

@PeterKietzmann I don't think we need to adapt the test, the Mutexes itself are well tested and I think the effort for a 'good' test are not worth it (as the locking implementation is quite straight forward...).

@PeterKietzmann
Copy link
Member

Well, I would ACK this. Any other opinions?

@BytesGalore
Copy link
Member

looks also good from my side

@@ -123,6 +123,28 @@ int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data));
int spi_conf_pins(spi_t dev);

/**
* @brief Get mutual access to the given SPI bus
Copy link
Member

Choose a reason for hiding this comment

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

Maybe mutual exclusive access?

Copy link
Member

Choose a reason for hiding this comment

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

..."mutually exclusive"...

@haukepetersen haukepetersen added the CI: needs squashing Commits in this PR need to be squashed; If set, CI systems will mark this PR as unmergable label Jan 15, 2015
@haukepetersen
Copy link
Contributor Author

here is an update - the mutex initialization issue is fixed through static initialization - multiple calls to spi_init should now be save.

I decided against calling spi_acquire in the init function. If you application uses one SPI bus for more then one device (with differing configurations), I think it should be up to the user to protect the complete acquire->init->transfer->release sequence. This is possible as the mutex works already before init is called the first time...

@haukepetersen
Copy link
Contributor Author

... and the new change even saved 24 bytes in ROM :-)

@thomaseichinger
Copy link
Member

Looks good to me.

@PeterKietzmann
Copy link
Member

I am fine with this soultion and willing to ACK. But also I would like to hear @gebart 's optinion on it.

@jnohlgard
Copy link
Member

@haukepetersen While it is still most likely a user error, I think it would be beneficial for developers to have the init function lock the mutex while initializing, to avoid any race conditions between two drivers, or between an application main thread and some data consumer thread. I don't really see why we should not lock the mutex for all of spi_init?

@haukepetersen
Copy link
Contributor Author

@gebart You are right, the overhead is limited and it could save some trouble. I was first reluctant against this idea since the major design goal was to keep the peripheral drivers as slim as possible - and every function call adds some more bytes to them... But I agree, the benefits for locking the init function are greater then the drawbacks of 2 function calls, so I will update this PR as soon as I have a minute.

@jnohlgard
Copy link
Member

@haukepetersen I will update #2317 accordingly.

@jnohlgard
Copy link
Member

@PeterKietzmann I think this is a good solution to the problem. The locking inside spi_init should be added before merging though.

@thomaseichinger
Copy link
Member

As the mutexes (mutices?) are statically initialised I thought usage would be

spi_acquire(dev);
spi_init_master(dev, ...);
spi_release(dev);

Wouldn't this result in a more consistent usage?

@jnohlgard
Copy link
Member

@thomaseichinger It would make the API usage more consistent, yes. I am updating #2317 again.

@haukepetersen
Copy link
Contributor Author

I am completely for @thomaseichinger's solution! I think it is for (i) more consitent and it (ii) leaves it to the user to omit the locking for setups where I can sure that I am only using one SPI device for example...

squashed and rebased - ready for merge?

@jnohlgard
Copy link
Member

ACK

@jnohlgard jnohlgard removed the CI: needs squashing Commits in this PR need to be squashed; If set, CI systems will mark this PR as unmergable label Jan 18, 2015
@haukepetersen
Copy link
Contributor Author

ok, somehow Travis is complaining that the PR needs to be squashed, though the label was removed... Do we have a bug in our Travis script?

@PeterKietzmann
Copy link
Member

Travis is happy

@haukepetersen
Copy link
Contributor Author

finally. go then!

haukepetersen added a commit that referenced this pull request Jan 19, 2015
drivers/periph/spi: added means to make SPI thread-safe
@haukepetersen haukepetersen merged commit e1801cc into RIOT-OS:master Jan 19, 2015
@haukepetersen haukepetersen deleted the opt_spi_threadsafe branch January 19, 2015 08:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: drivers Area: Device drivers 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.

5 participants