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

Keep all SPI sub-operations within a single transaction #50

Closed
wants to merge 5 commits into from

Conversation

Dominaezzz
Copy link
Contributor

Starts to address #48 .

This makes sure that calls to transfer, write, read and transfer_inplace regardless of how big the given buffer is happens within a single transaction. Users who wish to break up their transactions can easily do so themselves by calling these operations multiple times.

This doesn't fix exec yet as I want to start small.

@Dominaezzz
Copy link
Contributor Author

Not sure why SPI_TRANS_CS_KEEP_ACTIVE can't be found.
My first guess is that it's because it's a #define but the suggested alternative is also a #define.
(I'm new to bindgen and Rust in general)

@Dominaezzz
Copy link
Contributor Author

I just realised the SPI_TRANS_CS_KEEP_ACTIVE is a ESP_IDF=4.4 feature....

@ivmarkov
Copy link
Collaborator

You can still implement it with conditional compilation of esp idf >= esp idf v4.4

@Dominaezzz
Copy link
Contributor Author

I have but how do I get around the unused variable it might leave behind.

Also, are there any plans to make esp-idf 4.4 a min dep?

@MabezDev
Copy link
Member

4.3 still has 21 months of support (see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/versions.html#support-periods) so it's unlikely we'll stop supporting it completely for a while. With that said, we'll probably make the 4.4 branch the default soon.

Copy link
Collaborator

@ivmarkov ivmarkov left a comment

Choose a reason for hiding this comment

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

Overall, looks OK. Two small nits, and one very important question :)

src/spi.rs Outdated
) -> Result<(), SpiError> {
let flags = 0;

#[cfg(any(esp_idf_version = "4.4", esp_idf_version_major = "5"))]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you turn this check into !V4.3?
I.e. something like #[cfg(not(esp_idf_version = "4.3"))]

This way, if this code is still around when ESP-IDF V6 is released, it won't break (and we don't support ESP-IDF releases < 4.3).

src/spi.rs Outdated
break;
}

if offset == buf.len() && lock.is_none() {
lock = Some(self.lock_bus()?);
let is_last_chunk;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: you can just do let is_last_chunk = if .... Will shorten the code a bit.

@@ -336,6 +336,7 @@ impl<SPI: Spi, SCLK: OutputPin, SDO: OutputPin, SDI: InputPin + OutputPin, CS: O
for offset in (0..len).step_by(TRANS_LEN) {
let read_chunk_end = min(offset + TRANS_LEN, read.len());
let write_chunk_end = min(offset + TRANS_LEN, write.len());
let is_last_chunk = offset + TRANS_LEN < len;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Most important question: is the API of embedded-hal mandating that all transfers not using the Transaction traits should still be in a single transaction? I.e., if I do an innocent long write, it should be in a single transaction?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't see anything mandating this in the embedded-hal API, so technically this isn't strictly breaking contract.
However, I've got some justifications.

  • I'm using this to talk to an epaper driver IT8951 and it requires every transaction to have some preamble bits. I spent a few hours wondering why my code wasn't working until I came to look at the source code here. I've now ended up keeping my writes and reads < 32 to make sure I'm in a single transaction. It's a bit awkward to be breaking up my transfers when the library I'm using is also doing the same thing.
  • The next version of embedded-hal will be enforcing this. https://github.com/rust-embedded/embedded-hal/blob/b5c29b39880e467ef65ceb5534422d0e58539119/src/spi/blocking.rs . Everything has now been written in terms of transactions.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the crux of the problem is that the notion of SPI transaction that ESP-IDF has does not work with buffers of arbitrary length (only up to 64 bytes), and does not work when the read buffer length is different from the write buffer length. Otherwise, we would've not be breaking the user-supplied buffers into multiple ESP-IDF "transactions".

Regarding your comment about the big upcoming changes to embedded-hal SPI traits: given that currently we support e-hal 1.0-alpha7 (in addition to e-hal 0.2) and that we plan to stay up-to-date with e-hal 1.0 pre-releases, perhaps the correct angle to approach the problem is to actually think how the new upcoming e-hal SPI traits can be implemented on top of the ESP-IDF SPI interface, and then in addition provide backwards compat with e-hal 0.2?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, with DMA it can do more than 64 bytes but it's been disabled in here for some reason. Of course, I do appreciate that some people might want to disable DMA, which brings us back.

I've already given that some thought. I've also thought about how DMA might fit into it since it's something I really want.
Would it be alright if I pinged you on Matrix?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The SpiBus trait can't be easily implemented in terms of esp-idf's spi interface, since you need a device to perform transactions but the SpiDevice can be.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I mean, at the moment, what we have with the e-hal 0.2 is essentially only the notion of an spi bus and we emulate it that way.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes it can indeed be emulated with a lock lasting the duration of the SpiBus trait lifetime. It just felt a bit kludgy at first.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Pulling out the Bus from Master will mean breaking changes. Is that acceptable?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes. Not nice but we are at 0.X, so that's okay. And, most of the user code should be coded against the 0.2 e-hal traits anyway. It is the initialization of the SPI driver that might break.

If you have cycles, let's try to explore the path and once we have concrete code, then actually we can say how much and what would break.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

POC: #52

@ivmarkov
Copy link
Collaborator

Obsoleted by #61

@ivmarkov ivmarkov closed this Apr 17, 2022
@Dominaezzz Dominaezzz deleted the spi_trans branch April 17, 2022 08:35
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

3 participants