-
Notifications
You must be signed in to change notification settings - Fork 34
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
Inherent race condition when using SPI #8
Comments
Yes, that is absolutely correct ... I agree, the best solution is a fix in |
@ryankurte, you wrote the original patch for supporting SPI. What is your thought on this? I'd suggest removing SPI support in its current form and then thinking about introducing something like |
Yeah this isn't ideal, sorry it took me so long to come back around to it. I'd rather not remove support (because I'm using it alright from a single threaded context), but maybe a note that it's dangerous could be useful? I've got an open PR for transactions (rust-embedded/embedded-hal#178) which mitigates this a wee bit in that you can batch all the operations together, and we have an issue for discussion about CS traits now (rust-embedded/embedded-hal#180) if y'all would like to have any input there. |
Thanks for the reply, @ryankurte! I am not sure whether I correctly understand your proposal in rust-embedded/embedded-hal#180. Maybe you can provide some (pseudo) code to elaborate? From my point of view, the only thing we can do now is adding a new Does this sound reasonable? |
After talking a bit in Of course, this prevents SPI usage from different execution contexts. But I think with the current |
My hope with Completely untested example (actual impl in linked crates) but, i would expect this to look something like: // ManagedCS specifies that all `spi` operations will be preceded by asserting the CS pin,
// and followed by de-asserting the CS pin.
// If you need to adapt from a HAL which does not provided `ManagedCS`, use`SpiWithCs::new(spi, cs_pin)`
// to construct a wrapper object.
trait ManagedCS {}
// HAL implementer, whether Hal provides ManagedCS depends on configuration
// (possible in linux, unlikely in other situations)
impl spi::Transactional for Hal { ... }
// SPI consumer, asserts that they expect the CS pin to be managed
impl <S: spi::Transactional + spi::ManagedCS> Driver {
pub fn new(spi: S) -> Self { ... }
}
// SPI mux, only supported where CS is managed to avoid breaking up transactions
impl <T> spi::Transactional for T where T: spi::ManagedCS { ... }
// SPI CS Wrapper
// combines SPI and CS_PIN and manages CS assertion/de-assertion
struct SpiWithCs<S, P> {
spi: S,
cs_pin: P,
}
impl <S, P> SpiWithCs<S, P> {
pub fn new(spi: S, cs_pin: P) -> Self { ... }
}
impl <S, P> ManagedSpi for SpiWithCs<S, P> {} This lets driver authors specify their expectations about CS, HALs implement auto-cs where viable, and users adapt from unmanaged to managed instances. The only limitation that is obvious to me is that we cannot currently assert |
Yeah, this looks good!
I think this should not be encouraged at all as such drivers prevent bus-sharing (see this issue ...). IMO a driver shouldn't know about the CS pin at all, it should expect that whenever it interacts with its peripheral, CS will be asserted by a lower level (either your |
The unsoundness is now fixed so we can close this issue I'd say. Of course, now |
SPI uses chip select lines to select which chip to talk to but this crate only synchronizes the SPI data transaction itself, not the chip select lines, so there's a possible race condition where a transaction occurs with multiple chip select lines asserted. I was bitten by this in an actual project, and had to revert to manually synchronizing everything.
The way to do chip select lines with
embedded-hal
seems to be to just pass them to drivers separately from the SPI peripheral, so there is no real way to synchronize access via just the SPI trait. The only idea I had was to add a method likeBusManager::acquire_spi(cs_pin)
which takes ownership of the chip selectOutputPin
, and returns you both aBusProxy
as well as a wrapper for the chip select pin, and the wrapper actually does the locking (lock when chip select is asserted). This sounds incredibly hacky though, and I think the correct solution would be to expand theembedded-hal
SPI traits to include chip select support. I think some peripherals with hardware chip selects might benefit from it anyways.The text was updated successfully, but these errors were encountered: