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

Support for I2C flags to hold SDA low (Unix) #2160

Open
ypedegroot opened this issue Nov 8, 2023 · 1 comment
Open

Support for I2C flags to hold SDA low (Unix) #2160

ypedegroot opened this issue Nov 8, 2023 · 1 comment
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation Priority:2 Work that is important, but not critical for the release

Comments

@ypedegroot
Copy link

Is your feature request related to a problem? Please describe.

I have a Raspberry Pi Compute Module 4 based carrier board that also contains an I2C slave device that needs to be woken up by holding SDA low for at least 75 uS. When the Raspberry Pi's I2C bus runs at 100 kHz, opening a write to 0x00 pulls the SDA low long enough to wake-up the slave. However, this is no longer feasible when the I2C bus runs at 400 kHz; then, the SDA is only pulled low for approximately 25 uS, which is too short.

The problem is that the I2C driver by default stops the transaction when a NAK occurs (which obviously occurs when writing to 0x00, an invalid I2C address). However, Raspberry Pi recently introduced support for the I2C I2C_M_IGNORE_NAK flag (see this commit: raspberrypi/linux@8c4f88c).

Describe the ideal solution

In our implementation, we use the System.Device.Gpio package in combination with the LibGpiodDriver. It would be nice if support for i2c_msg "flags" would be added, so a slave device requiring a low SDA for a longer time than 25 uS to wake up can be woken up nicely.

There are only two alternatives:

  1. Changing the baudrate of the I2C bus back to 100 kHz, which is a shame, since almost all slaves support 400 kHz I2C bus speed;
  2. Use a GPIO pin to pull the SDA low for a certain time. However, this emulates multi-master behaviour which is not supported on the BCM2711, so this is an undesirable alternative).

See this for more information on the I2C_M_IGNORE_NAK flag: https://www.[kernel.org/doc/Documentation/i2c/i2c-protocol](https://www.kernel.org/doc/Documentation/i2c/i2c-protocol)

In the Discord i2c-discussions thread, @Ellerbach suggested to take a look at the files https://github.com/dotnet/iot/blob/main/src/System.Device.Gpio/System/Device/I2c/UnixI2cBus.cs and https://github.com/dotnet/iot/blob/main/src/System.Device.Gpio/System/Device/I2c/UnixI2cFileTransferBus.cs.
In those files, before the I2C action is executed, the flags are being set.

Perhaps it would be good to introduce an overload function on the Write (and/or Read) functions to add additional flags to an I2C operation. Another idea is to add a method to hold the SDA low for a specified amount of time. A final suggestion would be to expose a property in which the I2C flags can be set.

@ypedegroot ypedegroot added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Nov 8, 2023
@ghost ghost added the untriaged label Nov 8, 2023
@krwq krwq added Priority:2 Work that is important, but not critical for the release and removed untriaged labels Nov 9, 2023
@ghost ghost removed the untriaged label Nov 9, 2023
@pgrawehr
Copy link
Contributor

pgrawehr commented Nov 9, 2023

It may not be the perfect solution, but you can also switch a pin between i2c and GPIO. Try something like the following:

Board b = Board.Create();
var controller = b.CreateGpioController();
controller.OpenPin(2, PinMode.Output); // The SDA pin of the default I2C bus
controller.Write(2, PinValue.Low);
Thread.Sleep(10);
controller.Write(2, PinValue.High);
controller.ClosePin(2);
var bus = b.CreateOrGetI2cBus(1);
var device = bus.CreateDevice(deviceId);
// ... Use device, should have been woken up

Using the Board class (or it's concrete implementation) automatically switches the pin mode of the ouput pin between its various functions (here GPIO and I2C). Just make sure the pin is closed before you switch modes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation Priority:2 Work that is important, but not critical for the release
Projects
None yet
Development

No branches or pull requests

3 participants