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

embedded_hal_async::digital::Wait implementation for Pin #903

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

martinsp
Copy link
Contributor

Currently this implementation is only for rp2040.

I plan to implement also the rp235x version, but firstly I would like to fix any issues in the rp2040 implementation to not waste review time if there are soundness issues or other changes needed.

{
fn on_interrupt() {
let pin_id = I::ID;
let mut pin = unsafe { new_pin(pin_id) };
Copy link
Member

Choose a reason for hiding this comment

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

Please add a comment why this is safe.

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 on_interrupt() implementation has changed and this is not needed anymore

if pin.interrupt_status(Interrupt::LevelLow)
|| pin.interrupt_status(Interrupt::LevelHigh)
|| pin.interrupt_status(Interrupt::EdgeLow)
|| pin.interrupt_status(Interrupt::EdgeHigh)
Copy link
Member

Choose a reason for hiding this comment

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

interrupt_status reads PROCx_INTS and then returns the bit selected by the parameter. As the read is volatile, the compiler can't aggregate the 4 reads to a single one. Therefore, this is quite inefficient.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed implementation to read register using proc_ints

Comment on lines 37 to 38
pin.clear_interrupt(Interrupt::LevelLow);
pin.clear_interrupt(Interrupt::LevelHigh);
Copy link
Member

Choose a reason for hiding this comment

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

The level interrupts can't be cleared. From the datasheet (section 2.19.3):

The level interrupts are not latched. This means that if the pin is a logical 1 and the level high interrupt is active, it will become inactive as soon as the pin changes to a logical 0. The edge interrupts are stored in the INTR register and can be cleared by writing to the INTR register.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for pointing this out, changed the implementation


let _ = CPFn::new(
self,
Self::poll_is_high,
Copy link
Member

Choose a reason for hiding this comment

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

I don't think "wait for rising edge" can use poll_is_high as its poll function. A high level does not imply that an edge has occurred.
Better read the INTR register. (This may require that you don't clear the INTR bit in on_interrupt, but only do it in the poll function. I don't remember the details of the waker interactions.)

Copy link
Contributor Author

@martinsp martinsp Feb 23, 2025

Choose a reason for hiding this comment

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

Initialy before this call there was a code to ensure pin is low.

I updated the implementation to not clear interrupt inside on_interrupt and use a poll function specific to the relevant edge interrupt

@martinsp
Copy link
Contributor Author

Thanks for taking a look, I'll work on addressing the comments

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.

2 participants