⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c.cxx

📁 开放源码实时操作系统源码.
💻 CXX
📖 第 1 页 / 共 2 页
字号:
//==========================================================================
//
//      i2c.cxx
//
//      Generic API for accessing devices attached to an I2C bus
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 2004, 2005 eCosCentric Limited
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//###DESCRIPTIONBEGIN####
//
// Author(s):     bartv
// Date:          2004-10-05
//
//###DESCRIPTIONEND####
//========================================================================

#include <pkgconf/infra.h>
#include <pkgconf/io_i2c.h>
#include <cyg/infra/cyg_ass.h>
#include <cyg/infra/cyg_type.h>
#include <cyg/infra/diag.h>
#include <cyg/io/i2c.h>
#include <cyg/hal/hal_io.h>
#include <cyg/hal/hal_intr.h>
#include <cyg/hal/hal_diag.h>

// ----------------------------------------------------------------------------
// Static initialization.
//
// This is somewhat tricky. There is a strong argument for leaving the
// initialization to the platform HAL since with most I2C buses that
// code will be straightforward. However that would mean that the
// cyg_i2c_bus structure(s) and associated code would always get
// linked in, even if the application does not use any i2c devices.
// Instead to get the maximum benefit of linker garbage collection
// initialization is handled by the generic I2C code, using the usual
// dummy C++ object with a prioritized constructor. There is a dummy
// references to this object from the transaction end function. The
// result should be that if the application uses any I2C functionality
// then all required code and data should get included, otherwise it
// will all be elided.
//
// The init priority is configurable, defaulting to CYG_INIT_DRIVERS.
// Arguably it should happen a bit earlier to allow other drivers to
// perform I2C operations, but there is no CYG_INIT_BUS.
//
// All I2C buses are kept in a table, so that the init code can
// iterate through each one.

CYG_HAL_TABLE_BEGIN(cyg_i2c_buses, i2c_buses);
CYG_HAL_TABLE_END(cyg_i2c_buses_end, i2c_buses);

class cyg_i2c_init {
  public:
    cyg_uint8   i2c_dummy;
    cyg_i2c_init();
};

static cyg_i2c_init cyg_i2c_init_object CYGBLD_ATTRIB_INIT_PRI(CYGNUM_I2C_INIT_PRIORITY);

cyg_i2c_init::cyg_i2c_init()
{
    cyg_i2c_bus*    bus;

    cyg_i2c_init_object.i2c_dummy   = 0;
    for (bus = &(cyg_i2c_buses[0]); bus != &cyg_i2c_buses_end; bus++) {
        cyg_drv_mutex_init(&(bus->i2c_lock));
#ifdef CYGDBG_USE_ASSERTS
        bus->i2c_current_device = (const cyg_i2c_device*) 0;
#endif        
        if ((void (*)(cyg_i2c_bus*))0 != bus->i2c_init_fn) {
            (*bus->i2c_init_fn)(bus);
        }
    }
}

// ----------------------------------------------------------------------------
// The main exported routines just operate in terms of the transaction ones.

extern "C" cyg_uint32
cyg_i2c_tx(const cyg_i2c_device* dev, const cyg_uint8* buf, cyg_uint32 count)
{
    cyg_uint32  result;
    cyg_i2c_transaction_begin(dev);
    result = cyg_i2c_transaction_tx(dev, true, buf, count, true);
    cyg_i2c_transaction_end(dev);
    return result;
}

extern "C" cyg_uint32
cyg_i2c_rx(const cyg_i2c_device* dev, cyg_uint8* buf, cyg_uint32 count)
{
    cyg_uint32  result;
    cyg_i2c_transaction_begin(dev);
    result = cyg_i2c_transaction_rx(dev, true, buf, count, true, true);
    cyg_i2c_transaction_end(dev);
    return result;
}

// Transaction begin/end relate to the per-bus locking. There does not
// seem to be any need to interact with the hardware at this point.
extern "C" void
cyg_i2c_transaction_begin(const cyg_i2c_device* dev)
{
    cyg_i2c_bus*    bus;
    
    CYG_CHECK_DATA_PTR(dev, "valid I2C device pointer required");
    bus = dev->i2c_bus;
    CYG_CHECK_DATA_PTR(bus, "I2C device does not point at a valid bus structure");

    while (! cyg_drv_mutex_lock(&(bus->i2c_lock)));
#ifdef CYGDBG_USE_ASSERTS
    bus->i2c_current_device = dev;
#endif
    // All done, return with the bus locked.
}

extern "C" cyg_bool
cyg_i2c_transaction_begin_nb(const cyg_i2c_device* dev)
{
    cyg_bool        result  = false;
    cyg_i2c_bus*    bus;

    CYG_CHECK_DATA_PTR(dev, "valid I2C device pointer required");
    bus = dev->i2c_bus;
    CYG_CHECK_DATA_PTR(bus, "I2C device does not point at a valid bus structure");

    if (cyg_drv_mutex_trylock(&(bus->i2c_lock))) {
#ifdef CYGDBG_USE_ASSERTS
        bus->i2c_current_device = dev;
#endif
        result = true;
    }

    return result;
}

extern "C" void
cyg_i2c_transaction_end(const cyg_i2c_device* dev)
{
    cyg_i2c_bus*    bus;
    
    CYG_CHECK_DATA_PTR(dev, "valid I2C device pointer required");
    bus = dev->i2c_bus;
    CYG_CHECK_DATA_PTR(bus, "I2C device does not point at a valid bus structure");
    CYG_PRECONDITION(bus->i2c_current_device == dev, "I2C transaction end requested without claiming the bus");

    cyg_drv_mutex_unlock(&(bus->i2c_lock));
#ifdef CYGDBG_USE_ASSERTS
    bus->i2c_current_device = (const cyg_i2c_device*)0;
#endif
    // Avoid problems with linker garbage collection
    cyg_i2c_init_object.i2c_dummy   = 0;
}

// The I/O operations just indirect through the per-bus function pointers
extern "C" cyg_uint32
cyg_i2c_transaction_tx(const cyg_i2c_device* dev, cyg_bool start, const cyg_uint8* buf, cyg_uint32 count, cyg_bool stop)
{
    cyg_i2c_bus*    bus;
    cyg_uint32      result;
    
    CYG_CHECK_DATA_PTR(dev, "valid I2C device pointer required");
    bus = dev->i2c_bus;
    CYG_CHECK_DATA_PTR(bus, "I2C device does not point at a valid bus structure");
    CYG_PRECONDITION(bus->i2c_current_device == dev, "I2C transaction end requested without claiming the bus");
    CYG_CHECK_FUNC_PTR(bus->i2c_tx_fn, "I2C bus has not provided a tx function");
    
    result = (*(bus->i2c_tx_fn))(dev, start, buf, count, stop);
    return result;
}

extern "C" cyg_uint32
cyg_i2c_transaction_rx(const cyg_i2c_device* dev, cyg_bool start, cyg_uint8* buf, cyg_uint32 count, cyg_bool nak, cyg_bool stop)
{
    cyg_i2c_bus*    bus;
    cyg_uint32      result;
    
    CYG_CHECK_DATA_PTR(dev, "valid I2C device pointer required");
    bus = dev->i2c_bus;
    CYG_CHECK_DATA_PTR(bus, "I2C device does not point at a valid bus structure");
    CYG_PRECONDITION(bus->i2c_current_device == dev, "I2C transaction end requested without claiming the bus");
    CYG_CHECK_FUNC_PTR(bus->i2c_rx_fn, "I2C bus has not provided an rx function");
    
    result = (*(bus->i2c_rx_fn))(dev, start, buf, count, nak, stop);
    return result;
}

extern "C" void
cyg_i2c_transaction_stop(const cyg_i2c_device* dev)
{
    cyg_i2c_bus*    bus;
    
    CYG_CHECK_DATA_PTR(dev, "valid I2C device pointer required");
    bus = dev->i2c_bus;
    CYG_CHECK_DATA_PTR(bus, "I2C device does not point at a valid bus structure");
    CYG_PRECONDITION(bus->i2c_current_device == dev, "I2C transaction end requested without claiming the bus");
    CYG_CHECK_FUNC_PTR(bus->i2c_stop_fn, "I2C bus has not provided a stop function");
    
    (*(bus->i2c_stop_fn))(dev);
}

// ----------------------------------------------------------------------------
// The bit-banging support
//
// Optional debug support, useful while sorting out the platform-specific
// bitbang function.
#if 1
# define DEBUG(_format_, ...)
#else
# define DEBUG(_format_, ...) diag_printf(_format_, ## __VA_ARGS__)
#endif


// Initialization calls into the h/w specific bit-bang function to set
// up the GPIO pins and to set both SCL and SDA as outputs and high.

extern "C" void
cyg_i2c_bitbang_init(cyg_i2c_bus* mash)
{
    cyg_i2c_bitbang_fn      banger  = (cyg_i2c_bitbang_fn)(mash->i2c_extra);
    CYG_CHECK_FUNC_PTR(banger, "bitbanged i2c bus has not provided a bitbang function");
    
    DEBUG("i2c bitbang init\n");
    (*banger)(mash, CYG_I2C_BITBANG_INIT);
}

// Send a single byte out of the bus and get back the acknowledgement.
// This may be the addressing byte or a data byte.
// Preconditions:
//     SCL     output low. The previous operation has completed, the

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -