-
Notifications
You must be signed in to change notification settings - Fork 2
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: Add I2C Controller implementation #27
Conversation
fc92300
to
2cd9a63
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tested these on the H5 as well? I'd be a bit suspicious around some of the timing calcs, so at least one functional test would give some confidence.
Main comments in this are around the use of nb. I didn't closely look into the register calcs or device datasheet
Cargo.toml
Outdated
@@ -50,6 +50,7 @@ embedded-hal = "1.0.0" | |||
defmt = { version = "0.3.8", optional = true } | |||
paste = "1.0.15" | |||
log = { version = "0.4.20", optional = true} | |||
nb = "1.1.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really would avoid using the nb
crate nowadays. There's been talk of entirely deprecating it. It was intended to support embedded async
before async
was possible on embedded, but there's more modern approaches now with async
frameworks targeting embedded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, thanks for this context. I'll look at embedded-hal-async
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ryan-summers I looked at embedded-hal-async
, but I'm not sure how it solves the same problem? It doesn't provide any tool to manage repeatedly trying a blocking call. Is the suggestion to remove non-blocking calls entirely? Wouldn't they be useful in interrupts, or for creating a Future implementation for async?
Is it embedded-hal-nb
that might be deprecated rather than the nb
crate? That wasn't actually at 1.0 when I originally created this driver, so I didn't implement those APIs.
Turns out I did implement this for the SPI driver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ryan-summers Coming back to this, is the recommendation to declare non-blocking/async methods that return a Future
instead of using the nb
crate? Or have non-blocking methods that just check a status and return bool
/ Result<bool>
instead of returning an nb::Error::WouldBlock
and then have methods that can't be easily decomposed to a bool return a Future
? If you're not using an async runtime, how would one implement interrupt based operations? Just manually invoking poll on a future?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally, the way HALs do this is to have entirely blocking APIs for external embedded-hal
traits. If you also want a non-blocking API, you'd use embedded-hal-async
and could compose your software internally to handle both cases. nb
doesn't really solve the problem at all.
src/i2c.rs
Outdated
//! i2c.start(0x18, AddressMode::AddressMode7bit, write.len(), Stop::Automatic) | ||
//! | ||
//! for byte in write { | ||
//! block!(i2c.write_nb(byte))?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd remove the nb
implementation and instead go for embedded-hal-async
personally, but up to you
src/i2c.rs
Outdated
Event::AddressMatch => w.addrie().enabled(), | ||
}); | ||
let _ = self.i2c.cr1().read(); | ||
let _ = self.i2c.cr1().read(); // Delay 2 peripheral clocks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be helpful to document why there's a delay here
The suspicion is warranted, I'll give you that. I honestly don't understand them properly and the reference manual doesn't explain them very well and just refers you to use STM32Cube to determine the timing values. However, I have tested these timing values quite extensively on the H503. I'm using them for a I2C target implementation (which I'll put up for review after I merge this) in pre-production hardware and they have worked well so far. I'll take another look a them though. |
2cd9a63
to
9ac41de
Compare
I've looked at the TIMINGR calculations again, and I still don't know where some of those numbers come from, but between the tests, the fact that they've been working pretty well for me, and seem to do a good job for the H7 and the fact that embassy uses a very similar derivation (probably copied from stm32h7xx-hal, based on timing and similarity), I think I'll stick with them as is. |
3fc911e
to
cecddec
Compare
34c9dc5
to
9ada869
Compare
@ryan-summers I've removed |
9ada869
to
7d65a92
Compare
7d65a92
to
c26264d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Nicely organized.
This adds the I2C Controller driver implementation for the STM32H5. It implements a blocking, and non-blocking API, as well as the embedded-hal 1.0 traits.
It borrows a lot from the STM32H7 HAL (particularly the TIMINGR configuration, which is a bit inscrutable in the reference manual), but it borrows the
Instance
concept from the STM32F4 project to minimize the need for macros.It uses the updated terminology of Controller/Target from the latest version of the I2C spec (Rev. 7.0)