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 infinite loop when building with optimizations #5

Closed
ijager opened this issue Mar 18, 2020 · 3 comments
Closed

i2c infinite loop when building with optimizations #5

ijager opened this issue Mar 18, 2020 · 3 comments
Assignees
Labels
bug Something isn't working

Comments

@ijager
Copy link
Contributor

ijager commented Mar 18, 2020

When I build with optimizations (1 or 2) enabled

[profile.dev]
opt-level = 1

Then i2c read operations can get into an infinite loop in the busy_wait macro.
Bus speed = =100khz.

// Wait until address was sent
busy_wait!(self.i2c, busy);

Here the intention is to wait until the peripheral is not busy anymore and then break out of the loop.

} else if isr.$flag().bit_is_set() {
    break;
}

However, the busy flag is 1 if busy and will be cleared when not busy anymore. So the check should actually check for bit_is_cleared().

But I guess that's not true for all $flags that can be passed in.

Because optimization is on, the code is faster, the bit is already cleared so it ends up in an infinite loop.

@dotcypress dotcypress added the bug Something isn't working label Mar 24, 2020
@dotcypress dotcypress self-assigned this Mar 24, 2020
@ijager
Copy link
Contributor Author

ijager commented May 5, 2020

Just tested 9697aef and it is not fixed yet.

For now I need to add a 'timeout' to the busy_wait loops

 ($i2c:expr) => {
        let mut count = 0;
        loop {
            let isr = $i2c.isr.read();
            if isr.berr().bit_is_set() {
                $i2c.icr.write(|w| w.berrcf().set_bit());
                return Err(Error::BusError);
            } else if isr.arlo().bit_is_set() {
                $i2c.icr.write(|w| w.arlocf().set_bit());
                return Err(Error::ArbitrationLost);
            } else if isr.nackf().bit_is_set() {
                $i2c.icr.write(|w| w.nackcf().set_bit());
                return Err(Error::Nack);
            } else if isr.busy().bit_is_clear() {
                break;
            }
            count += 1;
            if count > 1000 {
                break;
            }
        }
    };

I'll try to look into it further soon

@andresv
Copy link
Member

andresv commented May 23, 2020

Yes, I have the same problem.

At some point stuff from L0 https://github.com/stm32-rs/stm32l0xx-hal/blob/master/src/i2c.rs should be merged.
G0 and L0 are quite similar. However G0 uses modern DMAMUX.

andresv added a commit to andresv/stm32g0xx-hal that referenced this issue May 23, 2020
`write_read` is also now fixed - before this fix stop was added after write
andresv added a commit to andresv/stm32g0xx-hal that referenced this issue May 23, 2020
`write_read` is also now fixed - before this fix stop was added after write
dotcypress added a commit that referenced this issue May 24, 2020
fix i2c infinite loop - issue #5
@ijager
Copy link
Contributor Author

ijager commented May 24, 2020

I was just getting ready to tackle this issue, so I did a git pull and turns out it is already fixed 😃
Thanks @andresv, I just tested it and it also works with optimizations on now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants