My code
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
namespace zigbox.fezcobra2.OneWire
{
public enum Pin
{
GP0A = 0x01,
GP1A = 0x02,
GP2A = 0x04,
GP3A = 0x08,
GP4A = 0x10,
GP5A = 0x20,
GP6A = 0x40,
GP7A = 0x80,
GP0B = 0x01,
GP1B = 0x02,
GP2B = 0x04,
GP3B = 0x08,
GP4B = 0x10,
GP5B = 0x20,
GP6B = 0x40,
GP7B = 0x80,
ALL = 0xFF,
}
public enum ConfigRegister
{
/// <summary>
/// Sequential Operation
/// 0 = enabled(default)
/// 1 = disabled
/// </summary>
SEQOP = 0x20,
/// <summary>
/// SDA Slew Rate
/// 0 = enabled(default)
/// 1 = disabled
/// </summary>
DISSLW = 0x10,
/// <summary>
/// Hardware Address Enable for MCP23S08 SPI version only
/// 0 = disabled(default)
/// 1 = enabled
/// </summary>
HAEN = 0x08,
/// <summary>
/// INT pin as open-drain
/// 0 = Active driver output(default)
/// 1 = Open-drain output
/// </summary>
ODR = 0x04,
/// <summary>
/// INT polarity
/// 0 = Active-low(default)
/// 1 = Active-high
/// </summary>
INTPOL = 0x02,
}
/// <summary>
/// MCP23017 pin expander
/// </summary>
public class Mcp23017
{
#region "Contructor"
/// <summary>
/// Reference to the I�C bus
/// </summary>
private I2CDevice _Device;
const ushort DS2482_ADDRESS = 0x18; // 7 bit address from data sheet, default address
const int CLOCK_FREQ = 100; // 100kHz, will also work at 400kHz
const int DELAY = 60; // not sure, might be the number of clock cycles?
const int POLL_LIMIT = 200; // limit for polling of status
const byte ONE_WIRE_BUSY = 0x01; // final bit of status is 1, indicating 1-Wire is busy
private enum DeviceCommand : byte // size of storage, still needs explicit cast when used.
{
ADDRESS = 0x18, // assuming both add pins are either left open or low. Change if they aren't.
DRST = 0xF0, // Command Device Reset
SRP = 0xE1, // Command Set Read Pointer
WCFG = 0xD2, // Command Write Configuration
CHANNELSELECT = 0xC3, // Command Write Configuration
oneWRS = 0xB4, // Command 1-Wire Reset
oneWSB = 0x87, // Command 1-Wire Single Bit
oneWWB = 0xA5, // Command 1-Wire Write Byte
oneWRB = 0x96, // Command 1-Wire Read Byte
oneWT = 0x78, // Command 1-Wire Triplet
}
public enum ReadPointer : byte
{
Status = 0xF0, // Status Register F0h
Read = 0xE1, // Read Data Register E1h
Configuration = 0xC3, // Configuration Register C3h
}
// Registers for port A
private const byte _IODIRA = 0x00;
private const byte _IPOLA = 0x02;
private const byte _GPINTENA = 0x04;
private const byte _DEFVALA = 0x06;
private const byte _INTCONA = 0x08;
private const byte _IOCONA = 0x0a;
private const byte _GPPUA = 0x0c;
private const byte _INTFA = 0x0e;
private const byte _INTCAPA = 0x10;
private const byte _GPIOA = 0x12;
private const byte _OLATA = 0x14;
OutputPort resetPin;
byte[] singleCommand = new byte[1];
byte[] writeBuffer = new byte[2];
byte[] readBuffer = new byte[1];
I2CDevice.I2CTransaction[] writeTrans = new I2CDevice.I2CTransaction[1];
I2CDevice.I2CTransaction[] readTrans = new I2CDevice.I2CTransaction[2];
I2CDevice.I2CWriteTransaction _writeTrans;
I2CDevice.I2CReadTransaction _readTrans;
I2CDevice.I2CTransaction[] _transactions;
public Mcp23017(byte address, OutputPort resetPin)
{
//this._Device = new I2CDevice(new I2CDevice.Configuration(address, 100));
//Init();
_Device = new I2CDevice(new I2CDevice.Configuration(DS2482_ADDRESS, CLOCK_FREQ));
DeviceReset();
}
#endregion
private void Init()
{
Reset();
Write((byte)DeviceCommand.DRST, 0x0);
WaitFreeGetStatus();
}
private byte WaitFreeGetStatus()
{
// Wait until the 1-Wire is not busy or polling limit is reached.
byte[] _status = new byte[1];
_writeTrans = I2CDevice.CreateWriteTransaction(new byte[2] { (byte)DeviceCommand.SRP, (byte)ReadPointer.Status });
_readTrans = I2CDevice.CreateReadTransaction(_status);
_transactions = new I2CDevice.I2CTransaction[] { _writeTrans, _readTrans };
_Device.Execute(_transactions, DELAY);
I2CDevice.I2CTransaction[] readTransaction = new I2CDevice.I2CTransaction[] { _readTrans }; // used to read status if 1-wire bus busy.
int i = 0; // used with POLL_LIMIT to make sure we don't wait forever for status byte.
while (((_status[0] & ONE_WIRE_BUSY) != 0x00) && i < POLL_LIMIT) // if the 1-Wire bus is busy
{
_Device.Execute(readTransaction, DELAY);
i++;
}
return _status[0];
}
public byte Configuration
{
get
{
// read the current configuration
/* Configuration Register Bit Assignment bit 7 to 0: 1WS SPU 1 APU 1WS SPU 0 APU
* Active Pullup (APU)
* Strong Pullup (SPU)
* 1-Wire Speed (1WS)
*/
byte[] _config = new byte[1];
WaitFreeGetStatus();
_writeTrans = I2CDevice.CreateWriteTransaction(new byte[2] { (byte)DeviceCommand.SRP, (byte)ReadPointer.Configuration }); // change pointer to config register
_readTrans = I2CDevice.CreateReadTransaction(_config); // single byte configuraiton, as above
_transactions = new I2CDevice.I2CTransaction[] { _writeTrans, _readTrans };
_Device.Execute(_transactions, DELAY);
return _config[0];
}
set
{
// write configuration. Top 4 bits, desired config, lower 4 bits 1's compliment of the top 4. So 0xF0 would work. or 0xE1 for APU only.
/* Configuration Register Bit Assignment bit 7 to 0: 1WS SPU 1 APU 1WS SPU 0 APU
* Active Pullup (APU) // 1 unless there is a single device on the line.
* Strong Pullup (SPU) // for some devices (e.g. EEPROM) can be set to 1
* 1-Wire Speed (1WS) // 0 for standard speed
*/
byte[] _config = new byte[1];
WaitFreeGetStatus();
_writeTrans = I2CDevice.CreateWriteTransaction(new byte[2] { (byte)DeviceCommand.WCFG, value }); // change the configuration
_readTrans = I2CDevice.CreateReadTransaction(_config); // single byte configuraiton, as above
_transactions = new I2CDevice.I2CTransaction[] { _writeTrans, _readTrans };
_Device.Execute(_transactions, DELAY);
if (!(_config[0] == value))
{
WaitFreeGetStatus();
_Device.Execute(_transactions, DELAY);
}
}
}
public void OneWireReset()
{
int written;
_writeTrans = I2CDevice.CreateWriteTransaction(new byte[1] { (byte)DeviceCommand.oneWRS });
_transactions = new I2CDevice.I2CTransaction[] { _writeTrans };
written = _Device.Execute(_transactions, DELAY);
WaitFreeGetStatus();
}
public byte[] ReadData(int bytes)
{
int written;
// Read one or more bytes from the read register
_writeTrans = I2CDevice.CreateWriteTransaction(new byte[2] { (byte)DeviceCommand.SRP, (byte)ReadPointer.Read });
byte[] data = new byte[bytes];
_readTrans = I2CDevice.CreateReadTransaction(data); // is this right?
_transactions = new I2CDevice.I2CTransaction[] { _writeTrans, _readTrans };
written = _Device.Execute(_transactions, DELAY);
return data; // should we return this?
}
public void OneWireSingleBit(byte slot)
{
int written;
/*
* Generates a single 1-Wire time slot. If bit 7 is:
* 0 then it generates a write-zero time slot
* 1 then it generates a write-one time slot, which also functions as a read-data time slot
* In either case, the logic level at the 1-Wire line is tested at tMSR and SBR is updated.
* */
WaitFreeGetStatus();
_writeTrans = I2CDevice.CreateWriteTransaction(new byte[2] { (byte)DeviceCommand.oneWSB, slot });
_transactions = new I2CDevice.I2CTransaction[] { _writeTrans };
written = _Device.Execute(_transactions, DELAY);
}
public void OneWireWriteByte(byte dataByte)
{
int written;
WaitFreeGetStatus();
_writeTrans = I2CDevice.CreateWriteTransaction(new byte[2] { (byte)DeviceCommand.oneWWB, dataByte });
_transactions = new I2CDevice.I2CTransaction[] { _writeTrans };
written = _Device.Execute(_transactions, DELAY);
}
public byte OneWireReadByte()
{
int written;
WaitFreeGetStatus();
byte[] _data = new byte[1];
_writeTrans = I2CDevice.CreateWriteTransaction(new byte[1] { (byte)DeviceCommand.oneWRB });
_readTrans = I2CDevice.CreateReadTransaction(_data);
_transactions = new I2CDevice.I2CTransaction[] { _writeTrans, _readTrans };
// shouldn't there be a read tx here?
written = _Device.Execute(_transactions, DELAY);
return _data[0];
}
public void DeviceReset()
{
int written;
_writeTrans = I2CDevice.CreateWriteTransaction(new byte[1] { (byte)DeviceCommand.DRST });
_transactions = new I2CDevice.I2CTransaction[] { _writeTrans };
written = _Device.Execute(_transactions, DELAY);
if (written != writeBuffer.Length)
{
if (Program.DebugLevel >= 1) Debug.Print(singleCommand.ToString() + " has NOT been written to I2C device[" + _Device.Config.Address + "].");
}
else
{
if (Program.DebugLevel >= 4) Debug.Print(singleCommand.ToString() + " has been written to I2C device[" + _Device.Config.Address + "].");
}
WaitFreeGetStatus();
}
/// <summary>
/// Hardware or software reset
/// </summary>
public void Reset()
{
int written;
//singleCommand[0] = (byte)DeviceCommand.DRST;
_writeTrans = I2CDevice.CreateWriteTransaction(new byte[1] { (byte)DeviceCommand.DRST });
writeTrans = new I2CDevice.I2CTransaction[] { _writeTrans };
written = _Device.Execute(writeTrans, 100);
if (written != writeBuffer.Length)
{
if (Program.DebugLevel >= 1) Debug.Print(singleCommand.ToString() + " has NOT been written to I2C device[" + _Device.Config.Address + "].");
}
else
{
if (Program.DebugLevel >= 4) Debug.Print(singleCommand.ToString() + " has been written to I2C device[" + _Device.Config.Address + "].");
}
}
public void OneWireTriplet(bool searchDirection)
{
int written = 0;
WaitFreeGetStatus();
_writeTrans = I2CDevice.CreateWriteTransaction(new byte[2] { (byte)DeviceCommand.oneWT, searchDirection ? (byte)0x80 : (byte)0x00 });
// should there be a read transaction here?
_transactions = new I2CDevice.I2CTransaction[] { _writeTrans };
written = _Device.Execute(_transactions, DELAY);
}
public void SetReadPointer(byte readPointer)
{
int written = 0;
//
WaitFreeGetStatus();
_writeTrans = I2CDevice.CreateWriteTransaction(new byte[2] { (byte)DeviceCommand.SRP, readPointer });
_transactions = new I2CDevice.I2CTransaction[] { _writeTrans };
written = _Device.Execute(_transactions, DELAY);
}
public void ChannelSelect(byte readPointer)
{
int written;
WaitFreeGetStatus();
_writeTrans = I2CDevice.CreateWriteTransaction(new byte[2] { (byte)DeviceCommand.CHANNELSELECT, readPointer });
_transactions = new I2CDevice.I2CTransaction[] { _writeTrans };
written = _Device.Execute(_transactions, DELAY);
if (written != writeBuffer.Length)
{
if (Program.DebugLevel >= 1) Debug.Print(singleCommand.ToString() + " has NOT been written to I2C device[" + _Device.Config.Address + "].");
}
else
{
if (Program.DebugLevel >= 4) Debug.Print(singleCommand.ToString() + " has been written to I2C device[" + _Device.Config.Address + "].");
}
}
// property
public byte Status
{
get
{
// read the current status
/* Status Register Bit Assignment 7 to 0: DIR TSB SBR RST LL SD PPD 1WB
* Branch Direction Taken (DIR)
* Triplet Second Bit (TSB)
* Single Bit Result (SBR)
* Device Reset (RST)
* Logic Level (LL)
* Short Detected (SD)
* Presence-Pulse Detect (PPD)
* 1-Wire Busy (1WB)
*/
return WaitFreeGetStatus();
}
}
/// <summary>
/// Write single register
/// </summary>
/// <param name="reg">Register name</param>
/// <param name="val">Register value</param>
public void Write(byte reg, byte val)
{
int written;
writeBuffer[0] = (byte)reg;
writeBuffer[1] = val;
writeTrans[0] = I2CDevice.CreateWriteTransaction(writeBuffer);
written = _Device.Execute(writeTrans, 100);
if (written != writeBuffer.Length)
{
if (Program.DebugLevel >= 1) Debug.Print(val + " has NOT been written to " + reg + " I2C device[" + _Device.Config.Address + "].");
}
else
{
if (Program.DebugLevel >= 4) Debug.Print(val + " has been written to " + reg + " I2C device[" + _Device.Config.Address + "].");
}
}
/// <summary>
/// Read single register
/// </summary>
/// <param name="reg">Register name</param>
/// <returns>Register value</returns>
public byte Read(byte reg)
{
singleCommand[0] = (byte)reg;
readTrans[0] = I2CDevice.CreateWriteTransaction(singleCommand);
readTrans[1] = I2CDevice.CreateReadTransaction(readBuffer);
int resylt = _Device.Execute(readTrans, 100);
if (resylt > 0)
{
if (Program.DebugLevel >= 4) Debug.Print(" Read " + reg + " I2C device[" + _Device.Config.Address + "] Result[" + readBuffer[0] + "]");
}
else
{
if (Program.DebugLevel >= 1) Debug.Print(" Read " + reg + " I2C device[" + _Device.Config.Address + "] No data returned");
}
return readBuffer[0];
}
/// <summary>
/// Write GPIO pin(s)
/// </summary>
/// <param name="pin">pin</param>
/// <param name="value">value</param>
public void WritePinA(Pin pinMask, bool value)
{
SetRegisterForPin(_GPIOA, pinMask, value);
}
/// <summary>
/// Read single GPIO pin
/// </summary>
/// <param name="pin">pin</param>
/// <returns>pin value</returns>
public bool ReadPin(Pin pin)
{
byte current_GPIO = Read(_GPIOA);
if ((current_GPIO & (byte)pin) > 0)
{
return true;
}
else
{
return false;
}
}
/// <summary>
/// Read GPIO pin(s)
/// </summary>
/// <param name="pin">pin mask</param>
/// <returns>masked value</returns>
public byte ReadPinsA(Pin pinMask)
{
byte current_GPIOA = Read(_GPIOA);
current_GPIOA &= (byte)pinMask;
return current_GPIOA;
}
/// <summary>
/// Set pin value mask
/// </summary>
/// <param name="reg">register</param>
/// <param name="pin">pin</param>
/// <param name="value">value</param>
private void SetRegisterForPin(byte reg, Pin pinMask, bool value)
{
byte current = Read(reg);
if (value)
{
current |= (byte)pinMask;
}
else
{
current &= (byte)((int)~pinMask);
}
Write(reg, current);
}
/// <summary>
/// Set configuration
/// </summary>
/// <param name="cr">config</param>
public void SetConfigRegister(ConfigRegister cr)
{
Write(_IOCONA, (byte)cr);
}
/// <summary>
/// Clear INTF by reading INTCAP
/// </summary>
public void ClearInterruptA()
{
Read(_INTCAPA);
}
}
}