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

I2C reads: executing logic inbetween read bytes. #872

Open
PietPtr opened this issue Nov 12, 2024 · 3 comments
Open

I2C reads: executing logic inbetween read bytes. #872

PietPtr opened this issue Nov 12, 2024 · 3 comments

Comments

@PietPtr
Copy link

PietPtr commented Nov 12, 2024

I'm working on a peripheral that returns the length of an I2C message as the second read byte. I have to read exactly that amount of bytes, otherwise the peripheral enters an error state.

My main question is: How am I supposed to execute logic inbetween read bytes, without the library sending the address again?

The specific logic in this case is that after the second byte I know how many bytes I'll need to read. The usual read functions however need a buffer of a size known at compile time and will read that buffer until it's full.

As far as I've found, the transaction_iter function (https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/i2c/controller.rs#L394) looks promising. I've tried to implement an iterator that returns Operations, which first returns a Write Operation with my command data, and then will read byte by byte, and on the second byte determine how much message is left and supply exactly that amount of single-byte Read operations for the rest of the iterator (not the fastest, but speed is not an issue here). However, the Read operation exposed by the i2c-write-iter crate takes an &'a mut [u8] which has caused lifetime issues while implementing the Iterator trait for my iterator.

Is my solution the intended use of the transaction_iter? Is there an example somewhere using transaction_iter with logic inbetween reads (I looked on github, couldn't find any)? Is there some way that I can read a byte, execute code, then decide what to do next (stop the transaction, read the next byte, etc)?

@thejpster
Copy link
Member

This might be a good question to ask over on the Rust Embedded matrix channel as it relates to the embedded-hal APIs which we implement.

Which chip are you using? I've not come across one like that before - I've always done one read to get the size and then a second read of the correct size.

@PietPtr
Copy link
Author

PietPtr commented Nov 14, 2024

I'm trying to read/write to an industry specific peripheral, as far as I can see its datasheet isn't available online 😅

I've always done one read to get the size and then a second read of the correct size.

What I'm struggling with is how to run a read of a size that I cannot know at compile time. Maybe you have some example code of what you're doing? All read functions that I can find require a &mut [u8] read buffer, which as far as I understand has a fixed size at compile time. Furthermore, those read functions do a call to self.setup() every time, meaning the address is written again, which to my peripheral means a new I2C transaction starts.

I guess if I could have a read function that doesn't call setup my problem would be fixed as well.

@thejpster
Copy link
Member

thejpster commented Nov 14, 2024

No, that's a slice with a run time size.

  1. Make an array that's always big enough
  2. Read the length
  3. Slice the array to the desired length
  4. Read into the slice

Most devices cope with a restart because what if your MCU crashed mid-transaction?

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

No branches or pull requests

2 participants