Skip to content

Sending 0xFF byte with CS deasserted when used on shared bus #184

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

Open
avsaase opened this issue Apr 8, 2025 · 1 comment · May be fixed by #185
Open

Sending 0xFF byte with CS deasserted when used on shared bus #184

avsaase opened this issue Apr 8, 2025 · 1 comment · May be fixed by #185

Comments

@avsaase
Copy link

avsaase commented Apr 8, 2025

This is related to #176 but since it also affect the non-async api I figured it deserves it's own issue.

As discussed in #176 (comment), according to several non-official sources, SD cards that share the bus with other slaves need to be sent a dummy 0xFF byte with CS deasserted after every communication, before communicating with other slaves. Otherwise a bus conflict can occur.

If you share the SPI bus with other slaves, always send another "dummy" byte (or more) with the CS line inactive (high) after each communication to the SD card before accessing other slaves. Otherwise, the SD card will keep the DO/MISO ((master in slave out)) output active and cause two slaves to drive/short-circuit the MISO line! So: CS low, exchange data with SD card, CS high, send dummy data (e.g. one byte 0xFF), then you can communicate with other slaves.

https://electronics.stackexchange.com/a/602106/256470

In the SPI bus, each slave device is selected with separated CS signals, and plural devices can be attached to an SPI bus. Generic SPI slave device enables/disables its DO output by CS signal asynchronously to share an SPI bus. However MMC/SDC enables/disables the DO output in synchronising to the SCLK. This means there is a posibility of bus conflict with MMC/SDC and another SPI slave that shares an SPI bus. [...] Therefore to make MMC/SDC release the MISO line, the master device needs to send a byte after the CS signal is deasserted.

http://elm-chan.org/docs/mmc/mmc_e.html#spibus

I brought this up on matrix and the conclusion was that this requirement is fundamentally not compatible with the SpiDevice trait. Workarounds like using a second SpiDevice don't solve the problem. This applies to both the blocking and the async versions because in both cases there's no way to guarantee that other tasks or threads don't sneak in and use the bus between the main communication and sending the dummy byte.

The solution proposed in chat and in rust-embedded/embedded-hal#478 is to define a new trait SdCardDevice and provide impls for (OutputPin, &RefCell<SpiBus>), (OutputPin, &Mutex<SpiBus>), (OutputPin, SpiBus) (for exclusive use of the bus) that have the desired behavior. This still allows the bus to be shared with other devices by using embedded-hal-bus types. If backwards compatibility is important there could also be an impl for SpiDevice that keeps the current possibly incorrect behavior.

This seems like a feasible approach but it adds some boilerplate to the crate and probably an optional dependency on embassy-sync to allow users to share the bus in embassy projects. I'm happy to give this a go but I wanted to first ask if these downsides are acceptable. embasys-sync is not 1.0 yet so this would add a small maintenance burden.

cc @Be-ing

@thejpster
Copy link
Member

Sounds like a good idea to me.

@avsaase avsaase linked a pull request Apr 10, 2025 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants