I2C bus?

Sep 8, 2014 at 9:10 AM
Is there support for I²C bus? How can I access it?
Sep 15, 2014 at 8:08 PM
//============================================================================
// i2c.h - I²C bus access
//============================================================================

pragma once

/*--------------------------------------------------------------------------
  • class CI2C
    *--------------------------------------------------------------------------
    */

if defined(__cplusplus)

class CI2C
{
//---| public enums |-----------------------------------------------
public:
enum AddressMode {
    SubAddrZero =  0,
            SubAddrBYTE     =  1,
            SubAddrWORD     =  2,
    SubAddr3Bytes   =  3,
    SubAddrDWORD    =  4
};

//---| protected members |------------------------------------------
protected:
HANDLE          _hI2C;
DWORD           _dwCount;
DWORD           _dwLineNumber;
virtual BOOL        Read(WORD wAddr, AddressMode eSubAddrMode, WORD wSubAddr, PVOID pBuffer, DWORD count);
virtual BOOL        Write(WORD wAddr, AddressMode eSubAddrMode, WORD wSubAddr, PVOID pBuffer, DWORD count);

//---| public members |---------------------------------------------
public:
            CI2C();
            ~CI2C();
virtual void        Close();
virtual inline DWORD    GetCountBytes() { return _dwCount; }
virtual inline DWORD    GetLineNumber() { return _dwLineNumber; }
virtual inline BOOL IsOpen() { return (_hI2C != INVALID_HANDLE_VALUE); }
virtual DWORD       Open(unsigned int iPort);

virtual DWORD       ReadI2C(WORD wSubAddr, PVOID pBuffer, DWORD count, LPDWORD pRead);
virtual DWORD       SetSlaveAddress(DWORD address, DWORD mode);
virtual DWORD       WriteI2C(WORD wSubAddr, PVOID pBuffer, DWORD count, LPDWORD pWritten);
};

endif

//===| eof - end of file |====================================================
Sep 15, 2014 at 8:10 PM
//============================================================================
// i2c.h - I²C bus access
//============================================================================

//---| includes |-------------------------------------------------------------

include <stdlib.h>

include <stdio.h>

include <tchar.h>

include <memory.h>

include <windows.h>

include <winbase.h>

include <winioctl.h>

define IOCTL_DDK_GET_OAL_I2C_IFC CTL_CODE(FILE_DEVICE_I2C, 0x0100, METHOD_BUFFERED, FILE_ANY_ACCESS)

define IOCTL_I2C_SET_SLAVE_ADDRESS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS)

define IOCTL_I2C_SET_SUBADDRESS_MODE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0201, METHOD_BUFFERED, FILE_ANY_ACCESS)

define IOCTL_I2C_SET_BAUD_INDEX CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0202, METHOD_BUFFERED, FILE_ANY_ACCESS)

//-----------------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------------
CI2C::CI2C()
{
_hI2C = INVALID_HANDLE_VALUE;
}

//-----------------------------------------------------------------------------
// destructor
//-----------------------------------------------------------------------------
CI2C::~CI2C()
{
Close();
}

//-----------------------------------------------------------------------------
// close communication port
//-----------------------------------------------------------------------------
void CI2C::Close()
{
if (_hI2C != INVALID_HANDLE_VALUE)
{
    _dwLineNumber = __LINE__;
    CloseHandle(_hI2C);
    _hI2C = INVALID_HANDLE_VALUE;
}
}

//-----------------------------------------------------------------------------
// open communication port
//-----------------------------------------------------------------------------
DWORD CI2C::Open(unsigned int iPort)
{
TCHAR szPort[16];

_dwLineNumber = __LINE__;
if ((iPort < 1) || (iPort > 3))
    return ERROR_INVALID_PARAMETER;

_sntprintf_s(szPort, _tsizeof(szPort), _TRUNCATE, _T("I2C%u:"), ++iPort);

    if (!IsOpen())
    {
    _hI2C = CreateFile(szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
    }

if (!IsOpen())
    return GetLastError();

_dwLineNumber = __LINE__;
return ERROR_SUCCESS;
}

//-----------------------------------------------------------------------------
// read from i2c bus
//-----------------------------------------------------------------------------
DWORD CI2C::ReadI2C(WORD wSubAddr, PVOID pBuffer, DWORD count, LPDWORD pRead)
{
SetFilePointer(_hI2C, wSubAddr, NULL, FILE_BEGIN);
return ReadFile(_hI2C, pBuffer, count, pRead, NULL);
}

//-----------------------------------------------------------------------------
// set slave address
//-----------------------------------------------------------------------------
DWORD CI2C::SetSlaveAddress(DWORD address, DWORD mode)
{
register DWORD rc;
rc = DeviceIoControl(_hI2C, IOCTL_I2C_SET_SLAVE_ADDRESS, &address, sizeof(address), NULL, 0,NULL, NULL);
rc = DeviceIoControl(_hI2C, IOCTL_I2C_SET_SUBADDRESS_MODE, &mode, sizeof(mode), NULL, 0,NULL, NULL);
return rc;
}

//-----------------------------------------------------------------------------
// write to i2c bus
//-----------------------------------------------------------------------------
DWORD CI2C::WriteI2C(WORD wSubAddr, PVOID pBuffer, DWORD count, LPDWORD pWritten)
{
SetFilePointer(_hI2C, wSubAddr, NULL, FILE_BEGIN);
return WriteFile(_hI2C, pBuffer, count, pWritten, NULL);
}

//-----------------------------------------------------------------------------
// read data from device
//-----------------------------------------------------------------------------
BOOL CI2C::Read(WORD wAddr, AddressMode eSubAddrMode, WORD wSubAddr, PVOID pBuffer, DWORD count)
{
_dwLineNumber = __LINE__;
if (!SetSlaveAddress(wAddr, eSubAddrMode))
    return FALSE;

_dwCount = 0;
_dwLineNumber = __LINE__;
if (!ReadI2C(wSubAddr, pBuffer, count, &_dwCount))
    return FALSE;

_dwLineNumber = __LINE__;
    return TRUE;
}

//-----------------------------------------------------------------------------
// write data to device
//-----------------------------------------------------------------------------
BOOL CI2C::Write(WORD wAddr, AddressMode eSubAddrMode, WORD wSubAddr, PVOID pBuffer, DWORD count)
{
_dwLineNumber = __LINE__;
if (!SetSlaveAddress(wAddr, eSubAddrMode))
    return FALSE;

_dwCount = 0;
_dwLineNumber = __LINE__;
if (!ReadI2C(wSubAddr, pBuffer, count, &_dwCount))
    return FALSE;

_dwLineNumber = __LINE__;
    return TRUE;
}

//===| eof - end of file |====================================================
Sep 15, 2014 at 8:12 PM
Read temperature and pressure from Bosch BMP-085 sensor at 0x77 on i2c:

class CI2C
{
public:
virtual DWORD       ReadPressure(float *pfPressure, float *pfTemp = NULL);
};

//---| definitions |----------------------------------------------------------

define I2C_BOSCH_BMP085_ADDR 0x77

define I2C_BOSCH_BMP085_LEVEL 0

//-----------------------------------------------------------------------------
// BMP085: read temperature and pressure
//-----------------------------------------------------------------------------
DWORD CI2C::ReadPressure(float *pfPressure, float *pfTemp /= NULL/)
{
    static   BYTE  abCoefficients_s[22];
    static   BOOL  bInitialize_s            = TRUE;
             BYTE  abScratch[8];
register DWORD dwRC                     = ERROR_BAD_UNIT;

// check parameter
_dwLineNumber = __LINE__;
if ((!pfPressure) && (!pfTemp))
    return ERROR_INVALID_PARAMETER;

    // read coefficients?
    if (bInitialize_s)
    {
            for (register short i = 0; i < sizeof(abCoefficients_s); i += 2)
            {
                    if (!Read(I2C_BOSCH_BMP085_ADDR, SubAddrBYTE, 0xAA + i, &abCoefficients_s[i], 2))
                            return ERROR_INVALID_DATA;
            }

            bInitialize_s = FALSE;
    }

    // read temperature
    abScratch[0] = 0x2E;
    if (!Write(I2C_BOSCH_BMP085_ADDR, SubAddrBYTE, 0xF4, &abScratch[0], 1))
            return ERROR_WRITE_FAULT;

    Sleep(5);
    if (!Read(I2C_BOSCH_BMP085_ADDR, SubAddrBYTE, 0xF6, &abScratch[1], 2))
            return ERROR_READ_FAULT;

    // read pressure
    if (pfPressure)
    {
            Sleep(5);
            abScratch[0] = 0x34 << (I2C_BOSCH_BMP085_LEVEL << 6);
            if (!Write(I2C_BOSCH_BMP085_ADDR, SubAddrBYTE, 0xF4, &abScratch[0], 1))
                return ERROR_WRITE_FAULT;
            Sleep(10 + (3 << I2C_BOSCH_BMP085_LEVEL));
            if (!Read(I2C_BOSCH_BMP085_ADDR, SubAddrBYTE, 0xF6, &abScratch[3], 3))
                    return ERROR_READ_FAULT;
    }

    // calculate temperature
    register USHORT usAC5 = ((short)abCoefficients_s[ 8] << 8) | ((short)abCoefficients_s[ 9]);
    register USHORT usAC6 = ((short)abCoefficients_s[10] << 8) | ((short)abCoefficients_s[11]);
    register SHORT  sMC   = ((short)abCoefficients_s[18] << 8) | ((short)abCoefficients_s[19]);
    register SHORT  sMD   = ((short)abCoefficients_s[20] << 8) | ((short)abCoefficients_s[21]);
    register LONG   lUT   = ((short)abScratch[1] << 8) | ((short)abScratch[2]);
    register LONG   lX1   = ((lUT - (long)usAC6) * (long)usAC5) >> 15;
    register LONG   lX2   = ((long)sMC << 11) / (lX1 + (long)sMD);
    register LONG   lB5   = (lX1 + lX2);

    // store value
    if (pfTemp)
            *pfTemp = ((float)((lB5 + 8) >> 4)) / (float)10;

    // calculate pressure?
    if (pfPressure)
    {
            // calculate pressure
    // TODO: Check calculation for air pressure!
            //register SHORT  sAC1  = ((short)abCoefficients_s[ 0] << 8) | ((short)abCoefficients_s[ 1]);
    //register SHORT  sAC2  = ((short)abCoefficients_s[ 2] << 8) | ((short)abCoefficients_s[ 3]);
    //register SHORT  sAC3  = ((short)abCoefficients_s[ 4] << 8) | ((short)abCoefficients_s[ 5]);
    //register USHORT usAC4 = ((short)abCoefficients_s[ 6] << 8) | ((short)abCoefficients_s[ 7]);
    //register SHORT  sB1   = ((short)abCoefficients_s[12] << 8) | ((short)abCoefficients_s[13]);
    //register SHORT  sB2   = ((short)abCoefficients_s[14] << 8) | ((short)abCoefficients_s[15]);
    //register LONG   lB6   = lB5 - 4000;
    //                lX1   = ((long)sB2 * (lB6 * (lB6 >> 12))) >> 11;
    //                lX2   = ((long)sAC2 * lB6) >> 11;
    //register LONG   lX3   = (lX1 + lX2);
    //register LONG   lB3   = (((((long)sAC1 << 2) + lX3) << I2C_BOSCH_BMP085_LEVEL) + 2) >> 2;
    //                lX1   = (long)sAC3 * (lB6 >> 13);
    //            lX2   = ((long)sB1 * (lB6 * (lB6 >> 12))) >> 16;
    //            lX3   = ((lX1 + lX2) + 2) >> 2;
    //register ULONG  ulB4  = (ULONG)usAC4 * (((ULONG)lX3 + (ULONG)32768) >> 15);
    //register ULONG  ulB7  = ((ULONG)abScratch[3] << 16) | ((ULONG)abScratch[4] << 8) | ((ULONG)abScratch[5]);
    //                ulB7  = ulB7 >> (8 - I2C_BOSCH_BMP085_LEVEL);
            //            ulB7  = (ulB7 - lB3) * ((ULONG)50000 >> I2C_BOSCH_BMP085_LEVEL);
    //register LONG   lP    = (ulB7 < 0x8000000) ? ((ulB7 << 1) / ulB4) : ((ulB7 / ulB4) << 1);
    //                lX1   = (lP >> 8) * (lP >> 8);
    //            lX1   = (lX1 * (LONG)3038) >> 16;
    //            lX2   = ((LONG)-7357 * lP) >> 16;
    //            lP    = lP + ((lX1 + lX2 + (LONG)3791) >> 4);

            // UT := UT * 2.465
            // correction:
            //   p(0) (h) / (1 - ((0,0065 * h) / 288,15)) ^ 5,255 -> h 320m ü. NHN (Wannweil)
            //   p(0) (h) / (1 - ((0,0065 * 332) / 288,15)) ^ 5,255
            //   p(0) (h) / 0,962415
            //   p(0) (h) * 1,039053
            register ULONG lP   = ((ULONG)abScratch[3] << 16) | ((ULONG)abScratch[4] << 8) | ((ULONG)abScratch[5]);
            lP >>= (8 - I2C_BOSCH_BMP085_LEVEL);
            *pfPressure         = ((float)lP) * 0.0309141419;
    }

    // return success
_dwLineNumber = __LINE__;
    return ERROR_SUCCESS;
}