Skip to content

resets I2C pins back to original state, not blindly to input #59

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

Merged
merged 1 commit into from
May 26, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 32 additions & 7 deletions Raspberry.IO.InterIntegratedCircuit/I2cDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public class I2cDriver : IDisposable

private readonly ProcessorPin sdaPin;
private readonly ProcessorPin sclPin;
private readonly bool wasSdaPinSet;
private readonly bool wasSclPinSet;

private readonly IntPtr gpioAddress;
private readonly IntPtr bscAddress;
Expand Down Expand Up @@ -72,8 +74,9 @@ public I2cDriver(ProcessorPin sdaPin, ProcessorPin sclPin)
throw new InvalidOperationException("Unable to access device memory");

// Set the I2C pins to the Alt 0 function to enable I2C access on them
SetPinMode((uint) (int) sdaPin, Interop.BCM2835_GPIO_FSEL_ALT0); // SDA
SetPinMode((uint) (int) sclPin, Interop.BCM2835_GPIO_FSEL_ALT0); // SCL
// remembers if the values were actually changed to clear them or not upon dispose
wasSdaPinSet = SetPinMode((uint)(int)sdaPin, Interop.BCM2835_GPIO_FSEL_ALT0); // SDA
wasSclPinSet = SetPinMode((uint) (int) sclPin, Interop.BCM2835_GPIO_FSEL_ALT0); // SCL

// Read the clock divider register
var dividerAddress = bscAddress + (int) Interop.BCM2835_BSC_DIV;
Expand All @@ -89,9 +92,15 @@ public I2cDriver(ProcessorPin sdaPin, ProcessorPin sclPin)
/// </summary>
public void Dispose()
{
// Set all the I2C/BSC1 pins back to input
SetPinMode((uint) (int) sdaPin, Interop.BCM2835_GPIO_FSEL_INPT); // SDA
SetPinMode((uint) (int) sclPin, Interop.BCM2835_GPIO_FSEL_INPT); // SCL
// Set all the I2C/BSC1 pins back to original values if changed
if (wasSdaPinSet)
{
SetPinMode((uint)(int)sdaPin, Interop.BCM2835_GPIO_FSEL_INPT); // SDA
}
if (wasSclPinSet)
{
SetPinMode((uint)(int)sclPin, Interop.BCM2835_GPIO_FSEL_INPT); // SCL
}

Interop.munmap(gpioAddress, Interop.BCM2835_BLOCK_SIZE);
Interop.munmap(bscAddress, Interop.BCM2835_BLOCK_SIZE);
Expand Down Expand Up @@ -369,15 +378,31 @@ private static uint GetBscBase(ProcessorPin sdaPin, ProcessorPin sclPin)
}
}

private void SetPinMode(uint pin, uint mode)
/// <summary>
///
/// </summary>
/// <param name="pin"></param>
/// <param name="mode"></param>
/// <returns>True when value was changed, false otherwise.</returns>
private bool SetPinMode(uint pin, uint mode)
{
// Function selects are 10 pins per 32 bit word, 3 bits per pin
var paddr = gpioAddress + (int) (Interop.BCM2835_GPFSEL0 + 4*(pin/10));
var shift = (pin%10)*3;
var mask = Interop.BCM2835_GPIO_FSEL_MASK << (int) shift;
var value = mode << (int) shift;

WriteUInt32Mask(paddr, value, mask);
var existing = ReadUInt32(paddr) & mask;
if (existing != value)
{
//Console.WriteLine($"existing is {x} masked:{x & mask} vs mask:{mask} value:{value}");
WriteUInt32Mask(paddr, value, mask);
return true;
}
else
{
return false;
}
}

private static void WriteUInt32Mask(IntPtr address, uint value, uint mask)
Expand Down