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

SCL release? #14

Open
rscheff opened this issue Dec 14, 2021 · 5 comments
Open

SCL release? #14

rscheff opened this issue Dec 14, 2021 · 5 comments

Comments

@rscheff
Copy link

rscheff commented Dec 14, 2021

Hi,

Line 95 is supposed to "release" SCL (that is, make it an input pin, and validate that no other device pulls it down).

However, the code keeps this as an output (PORTB PIN is set, rather than unset)...

Unless I am mistaken, this should be a
PORT_USI_CL &= ~(1<<PIN_USI_SCL);

What am I missing?

PORT_USI_CL |= 1<<PIN_USI_SCL; // Release SCL.

@technoblogy
Copy link
Owner

Thanks - I'll have a look.

@rscheff
Copy link
Author

rscheff commented Dec 14, 2021

Should have written

/* Release SCL to ensure that (repeated) Start can be performed */
DDR_USI_CL &= ~(1<<PIN_USI_SCL); // Release SCL.
while (!(PIN_USI_CL & 1<<PIN_USI_SCL)); // Verify that SCL becomes high.
DDR_USI_CL |= (1<<PIN_USI_SCL);

(make SCL an input, validate that the pull up still keeps SCL high, and make it a driven output again).

See https://www.i2c-bus.org/clock-stretching/

Unless I am mistaken, SCL "High" should normally be done not by driving it as an output high, but making it an input and rely on the pull-up resistor to pull SCL high (or a client keeping it low, if it needs more processing time).

@technoblogy
Copy link
Owner

Thanks for your comment. From the datasheet:

The Serial Data (SDA) and the Serial Clock (SCL) pins are bi- directional and use open-collector output drives. The output drivers are enabled by setting the corresponding bit for SDA and SCL in the DDR Register.

As I understand it, because they are open-collector, setting SCL low leaves the slave free to pull it high, so it's OK the way it's written.

Was this a theoretical point, or have you encountered problems with the library as it's written?

@rscheff
Copy link
Author

rscheff commented Feb 16, 2022

Well, if you keep the PORT as output and set it high, the PIN will most likely read one - as you are injecting current not only via the (high resistance, 1-22kOhm) pull up, but a low-resistance (0.1-10Ohm) MOS driver. Especially if the slave is some line resistance away and not able to pull down the 50 or 100 mA the MOS PIN driver can inject. Therefore you can not actually observe, if a I2C slave is pulling the SCL low to extend the clock cycle - the code will just "mostly" work as extendning the clock is not very often done.

IIRC the SDA is doing it correct, as NACK/ACK is a more common pattern, where pull form the pull-up resistor (a few kOhm) has to work properly - and a MOS high output (few milliohms to few ohms - depending on the MCU) would be too strong driving the line.

@technoblogy
Copy link
Owner

I believe that putting the USI into two-wire mode changes the SCL and SDA output pins to open-collector. I based my code on the Atmel example code; I assume they knew what they were doing.

Have you done any testing to compare both approaches in practice?

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