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

spi: add Operation::DelayUs(u32). #462

Merged
merged 1 commit into from
Jun 20, 2023
Merged

Conversation

Dirbaio
Copy link
Member

@Dirbaio Dirbaio commented May 10, 2023

depends on #461

There are SPI devices out there that need delays between transfers within a transaction. Not dummy bytes, SCK must be idle during the delay. And it must be a single transaction, CS must not be deasserted.

This is not doable with the new operation-list API (it was doable with the previous closure API).

Examples:

To support these, this adds a new Operation::DelayUs(u32).

Linux spidev can implement this fine, it supports delaying after each transfer.

The downside is that SpiDevice impls now need a time source. Discussed a bit in yesterday's WG meeting.

I don't think separating the traits by capability is worth it, we end up with the same problem as with the read-only/write-only traits (#461)

@ryankurte
Copy link
Contributor

ryankurte commented May 11, 2023

hmm, is this a similar problem to the need to be able to do weird acknowledgement things within a transaction (eh. send command, wait on pin assertion, fetch data)? iirc for those cases we'd recommend using the bus instead of the device abstraction (which works for most cases with the usual caveats related to manual CS with multiple apps sharing buses under linux)

cc. @eldruin because we had a big chat about this recently

@jannic
Copy link
Contributor

jannic commented May 16, 2023

Could there be SpiDevice implementations that can't support the delay operation? Perhaps there should be some documented best practice on how to react in that situation.

For example:

  • drivers should avoid the delay operation if possible, to improve compatibility
  • SpiDevice implementations should support the delay operation if possible, for the same reason
  • in case an SpiDevice can't support the delay operation, it should reject a transaction containing such an operation. (It could return an error with a newly defined ErrorKind OperationNotSupported?) It should return that error immediately, even if Operation::DelayUs is not the first operation

With an OperationNonSupported error kind, one could even make Operation non_exhaustive to allow for later extensions. Who knows, perhaps there are devices which need varying SPI clocks within a single transaction?

@Dirbaio Dirbaio force-pushed the spi-delay branch 2 times, most recently from a64dc24 to 3425ea7 Compare May 23, 2023 19:26
@Dirbaio
Copy link
Member Author

Dirbaio commented May 23, 2023

Discussed in today's WG meeting (chatlog, minutes)

Changed:

  • Added new_no_delay() convenience method to embedded-hal-bus impls. Uses a dummy NoDelay that panics on use.
  • The delay is no longer within the RefCell/Mutex. Otherwise the user would have had to pass RefCell<(BUS, NoDelay)> which is awkward. This requires a Delay instance for each device, so it assumes the HAL allows obtaining as many delays as you want (or clone them), which should be the case in general (it's something we want to encourage, at least).

I haven't added new_no_delay() to embedded-hal-async impl because I didn't want to copypaste NoDelay , and the ExclusiveDevice there should be moved to embedded-hal-bus anyway. Will do in a follow-up PR.

@Dirbaio Dirbaio force-pushed the spi-delay branch 2 times, most recently from 52370a3 to 27824ec Compare May 23, 2023 23:13
Copy link
Member

@eldruin eldruin left a comment

Choose a reason for hiding this comment

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

I think this might make embedded-hal-bus unusable for linux-embedded-hal (or any implementation which provides meaningful buffering of the SPI transfers).

While this would work for SpiDevice implementations provided by l-e-h, I think it would not work for its SpiBus implementation, since delays there are appropriately marked transfers to the kernel and not something handled externally without SpiBus knowing about it.

This means that when using e-h-b on a l-e-h::SpiBus, we are delaying in "program-defined time", not in "bus-transfer-defined time".
Depending on the internal queue fill-up status of the SPI handler in the kernel, we might delay for a shorter time than requested to, down to no delay at all.

However, I do not know how the linux kernel buffers SPI transfers, and if there is a queue at all, so somebody with knowledge of the matter should clarify.
Nevertheless, the same issue applies to any HAL implementation which provides some kind of buffering due to the fundamental time difference.

@Dirbaio
Copy link
Member Author

Dirbaio commented May 24, 2023

Good point about buffering/queueing. I've added bus.flush() calls before the delays. This ensures the queued operations are fully finished before delaying, so the delay now becomes bus time, not just program time.

(Note that supporting flush() was already mandatory for SpiBus, and is also needed for correct software CS. So we're not ruling out any impls by doing this. Also I'm pretty sure linux spidev doesn't buffer transfers, or if it does then there must be a way to flush it for sure)

@Dirbaio
Copy link
Member Author

Dirbaio commented Jun 8, 2023

friendly ping @eldruin @ryankurte @therealprof

Copy link
Member

@eldruin eldruin left a comment

Choose a reason for hiding this comment

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

Alright, I checked a bit over at l-e-h and this seems fine although we would not be able to use the kernel API for the delay when using e-h-b, but for that we would need to make the e-h::SpiBus know about delays and that would further the impact of this special case, without a clear benefit. When absolutely needed, it would be possible to define a different implementation for e-h-b. Let's get it merged.
Thank you!

bors r+

@Dirbaio
Copy link
Member Author

Dirbaio commented Jun 20, 2023

bors r+

@Dirbaio Dirbaio added this pull request to the merge queue Jun 20, 2023
Merged via the queue into rust-embedded:master with commit a8ff64f Jun 20, 2023
11 checks passed
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 this pull request may close these issues.

None yet

5 participants