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

📄 i2cclass.cpp

📁 Microsoft WinCE 6.0 BSP FINAL release source code for use with the i.MX27ADS TO2 WCE600_FINAL_MX27_S
💻 CPP
📖 第 1 页 / 共 5 页
字号:
//
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
//  Use of this source code is subject to the terms of the Microsoft end-user
//  license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
//  If you did not accept the terms of the EULA, you are not authorized to use
//  this source code. For a copy of the EULA, please see the LICENSE.RTF on your
//  install media.
//
//------------------------------------------------------------------------------
//
//  Copyright (C) 2004-2008, Freescale Semiconductor, Inc. All Rights Reserved.
//  THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS
//  AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT
//
//------------------------------------------------------------------------------
//
//  File:  i2cclass.c
//
//  This file contains the main I2C protocol engine class.
//
//------------------------------------------------------------------------------

#pragma warning(push)
#pragma warning(disable: 4127 4201)
#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <linklist.h>
#include <windev.h>
#include <stdlib.h>
#include "csp.h"
#pragma warning(pop)

#include "socarm_macros.h"
#include "mx27_i2c.h"

#include "i2cbus.h"
#include "i2cclass.h"

//------------------------------------------------------------------------------
// External Functions
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// External Variables 
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Defines 
//------------------------------------------------------------------------------
#define  I2C_TIMEOUT_INTERLEAVE     (1)
#define  I2C_TRANSMIT_WAIT          (3840*9)

//------------------------------------------------------------------------------
// Types
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Global Variables 
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Local Variables 
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Local Functions
//------------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//
// Function: I2CClass::I2CClass
//
// This I2CClass constructor creates all the mutexes, events and heaps required
// for the subsequent use of I2C bus interface. It will also allocate the
// interrupt id from the HAL and binds the interrupt event to the interrupt id.
// This constructor has a built-in mechanism to prevent concurrent execution and a
// multiple interrupt binding procedure.
//
// Parameters:
//  None.
//
// Returns:  
//      None.
//
//-----------------------------------------------------------------------------

I2CClass::I2CClass(UINT32 index)
{
    DEBUGMSG(ZONE_INIT, (TEXT("I2CClass::I2CClass +\r\n")));

    m_iModuleIndex = index;

    // Mapped I2C Register Base Physical Address -> Virtual Address +
    {
        PHYSICAL_ADDRESS phyAddr;

        // Copy I2C physical address
        phyAddr.QuadPart = I2CGetBaseRegAddr(m_iModuleIndex);
        // Map to virtual address
        pI2CReg = (PCSP_I2C_REG) MmMapIoSpace(phyAddr, sizeof(CSP_I2C_REG), FALSE);

        // If mapping fails, fatal error, quit
        if (pI2CReg == NULL)
        {
            DEBUGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("I2CClass::I2CClass:MmMapIoSpace(): Failed! ErrCode=%d \r\n"), GetLastError()));
            iResult = I2C_ERR_PA_VA_MISSING;
            return;
        }
    }
    DEBUGMSG(ZONE_INIT, (TEXT("I2CClass::I2CClass:MmMapIoSpace(): pI2CReg=0x%x \r\n"), pI2CReg));

    // Create Hardware Interrupt Occurrence Event
    {
        hInterrupted = CreateEvent(NULL, FALSE, FALSE, NULL);
        // Able to create or obtain the event?
        if (hInterrupted == NULL)
        {
            DEBUGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("I2CClass::I2CClass:CreateEvent(): Interrupt Occurrence Event (hardware) Failed! ErrCode=%d \r\n"), GetLastError()));
            iResult = I2C_ERR_EOPS_CREATE;
            return;
        }
    }
    DEBUGMSG(ZONE_INIT, (TEXT("I2CClass::I2CClass:CreateEvent(): hInterrupted=0x%x \r\n"), hInterrupted));

    // Create Software Interrupt Event (to obviate priority inversion bugs)
    {
        // Create event in manual reset mode.
        m_hI2CIntrEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        // Able to create or obtain the event?
        if (m_hI2CIntrEvent == NULL)
        {
            DEBUGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("I2CClass::I2CClass:CreateEvent(): Interrupt Occurrence Event (software) Failed! ErrCode=%d \r\n"), GetLastError()));
            iResult = I2C_ERR_EOPS_CREATE;
            return;
        }
    }
    DEBUGMSG(ZONE_INIT, (TEXT("I2CClass::I2CClass:CreateEvent(): m_hI2CIntrEvent=0x%x \r\n"), m_hI2CIntrEvent));

    // Create Software Update Event to notify applications that I2C slave is written.
    {
        // Create event in manual reset mode.
        switch( m_iModuleIndex )
        {
        case 1:
              m_hI2CUpdateSlaveEvent = CreateEvent(NULL, TRUE, FALSE, L"EVENT_I2C1SLAVE");
              break;
        case 2:
              m_hI2CUpdateSlaveEvent = CreateEvent(NULL, TRUE, FALSE, L"EVENT_I2C2SLAVE");
              break;
        case 3:
              m_hI2CUpdateSlaveEvent = CreateEvent(NULL, TRUE, FALSE, L"EVENT_I2C3SLAVE");
              break;
        default:
              m_hI2CUpdateSlaveEvent = NULL;
              break;
        }       
        // Able to create or obtain the event?
        if (m_hI2CUpdateSlaveEvent == NULL)
        {
            DEBUGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("I2CClass::I2CClass:CreateEvent(): Interrupt Occurrence Event (software) Failed! ErrCode=%d \r\n"), GetLastError()));
            iResult = I2C_ERR_EOPS_CREATE;
            return;
        }
        bSlaveEventNotified = FALSE;
    }
    DEBUGMSG(ZONE_INIT, (TEXT("I2CClass::I2CClass:CreateEvent(): m_hI2CIntrEvent=0x%x \r\n"), m_hI2CIntrEvent));

    DEBUGMSG(ZONE_INIT, (TEXT("I2CClass::I2CClass:InitializeCriticalSection(): Creating I2C_IOControl Critical Section! \r\n")));

    // Configure IOMUX for I2C pins
    {
        if (!BSPI2CIOMUXConfig(m_iModuleIndex))
        {
            DEBUGMSG(ZONE_ERROR, 
                (TEXT("%s: Error configuring IOMUX for I2C.\r\n"), __WFUNCTION__));
            return;
        }
    }

    DEBUGMSG(ZONE_INIT, (TEXT("I2CClass::I2CClass:InitializeCriticalSection(): Creating I2C Bus Critical Section! \r\n")));

    // I2C Bus Critical Section
    {
        InitializeCriticalSection(&gcsI2CBusLock);
        InitializeCriticalSection(&gcsI2CSlaveLock);
    }

    // Map IRQ -> System Interrupt ID
    {
        // Copy our I2C IRQ Number
        DWORD dwIrq = I2CGetIRQ(m_iModuleIndex);

        // Get kernel to translate IRQ -> System Interrupt ID
        if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwIrq, sizeof(DWORD), &dwSysIntr, sizeof(DWORD), NULL))
        {
            DEBUGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("I2CClass::I2CClass:KernelIoControl(): IRQ -> SysIntr Failed! ErrCode=%d \r\n"), GetLastError()));
            iResult = I2C_ERR_IRQ_SYSINTR_MISSING;
            return;
        }
    }
    DEBUGMSG(ZONE_INIT, (TEXT("I2CClass::I2CClass:KernelIoControl(): dwSysIntr=0x%x \r\n"), dwSysIntr));

    // Link hInterrupted -> I2C Interrupt Pin
    {
        if (!InterruptInitialize(dwSysIntr, hInterrupted, NULL, 0))
        {
            DEBUGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("I2CClass::I2CClass:Interruptinitialize(): Linking failed! ErrCode=%d \r\n"), GetLastError()));
            iResult = I2C_ERR_INT_INIT;
            return;
        }
    }
    DEBUGMSG(ZONE_INIT, (TEXT("I2CClass::I2CClass:Interruptinitialize(): Linking passed! \r\n")));

    // Get BSP interrupt wait timeout value
    {
        iIntrWaitTimeout = BSPGetTimeoutValue();
        iIntrWaitTimeoutRetry = iIntrWaitTimeout/I2C_TIMEOUT_INTERLEAVE;
        iIntrWaitTimeout = I2C_TIMEOUT_INTERLEAVE;
    }
    DEBUGMSG(ZONE_INIT, (TEXT("I2CClass::I2CClass:BSPGetTimeoutValue(): Timeout retrieved! \r\n")));


    // Create IST thread to receive hardware interrupts
    {
        // Initialize this to FALSE to allow the IST handler thread to start
        // up and run.
        bTerminateISTThread = FALSE;

        // Start I2C IST thread
        // Initialize thread for I2C interrupt handling
        //      pThreadAttributes = NULL (must be NULL)
        //      dwStackSize = 0 => default stack size determined by linker
        //      lpStartAddress = I2CIST => thread entry point
        //      lpParameter = this => point to thread parameter
        //      dwCreationFlags = 0 => no flags
        //      lpThreadId = NULL => thread ID is not returned
        PREFAST_SUPPRESS(5451, "This warning does not apply to WinCE because it is not a 64-bit OS");
        DWORD tid;
        m_hI2CIST = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)I2CIST, this, 0, &tid);//NULL);

        if (m_hI2CIST == NULL)
        {
            DEBUGMSG(ZONE_INIT,(TEXT("%s: CreateThread failed!\r\n"), __WFUNCTION__));
            iResult = I2C_ERR_INT_INIT;
            return;
        }
        else
        {
            DEBUGMSG(ZONE_INIT, (TEXT("%s: create I2C IST thread success\r\n"), __WFUNCTION__));
            DEBUGMSG(ZONE_FUNCTION, (TEXT("%s: create I2C IST thread success, TID: %08x\r\n"), __WFUNCTION__, tid));
            CeSetThreadPriority(m_hI2CIST, 100);//THREAD_PRIORITY_TIME_CRITICAL);
        }

    }
    DEBUGMSG(ZONE_INIT, (TEXT("I2CClass::I2CClass:BSPGetTimeoutValue(): Timeout retrieved! \r\n")));
    

    // Disable I2C Module Initially
    {
       OUTREG16(&pI2CReg->I2CR, 0);
    }
    DEBUGMSG(ZONE_INIT, (TEXT("I2CClass::I2CClass:I2C_WORD_OUT(): I2CR=0x0 \r\n")));

    // Initialize I2C Mode
    byLastMode = I2C_MASTER_MODE;
    DEBUGMSG(ZONE_INIT, (TEXT("I2CClass::I2CClass: Default to Master Mode \r\n")));

    pSBuf =0;
    bSlaveInUse =0;

    // After this point, all initialization routines completed
    iResult = I2C_NO_ERROR;

    bDispatchEvent = FALSE;

    DEBUGMSG(ZONE_INIT, (TEXT("I2CClass::I2CClass -\r\n")));

}

//-----------------------------------------------------------------------------
//
// Function: I2CClass::~I2CClass
//
// This I2CClass destructor releases all the mutexes, events and heaps created.
// It will also attempt to terminate the worker thread. It has built-in 
// mechanism to determine whether it is safe to unbind the interrupt event from
// the interrupt id. This is to facilitate situations where multiple
// processes have obtained the same file handle to the I2C Bus Interface.
//
// Parameters:
//  None.
//
// Returns:  
//      None.
//
//-----------------------------------------------------------------------------
    
I2CClass::~I2CClass(void)
{
    DEBUGMSG(ZONE_DEINIT, (TEXT("I2CClass::~I2CClass +\r\n")));

    // Release the interrupt resources
    InterruptDisable(dwSysIntr);
    DEBUGMSG(ZONE_DEINIT, (TEXT("I2CClass::~I2CClass: Release System Interrupt \r\n")));

    // Kill interrupt service thread
    if (m_hI2CIST)
    {
        // Set the bTerminateISTThred flag to TRUE and then wake up the IST
        // thread to ensure that it will gracefully terminate (by simply
        // executing all of the "return" calls).
        bTerminateISTThread = TRUE;
        PulseEvent(hInterrupted);

        CloseHandle(m_hI2CIST);
        m_hI2CIST = NULL;
    }

    CloseHandle(hInterrupted);
    // Prevent the later sections from thinking it is still valid
    hInterrupted = NULL;

    CloseHandle(m_hI2CIntrEvent);
    // Prevent the later sections from thinking it is still valid
    m_hI2CIntrEvent = NULL;

    // Release the interrupt
    DEBUGMSG(ZONE_DEINIT, (TEXT("I2CClass::~I2CClass(): Releasing dwSysIntr = 0x%x \r\n"), dwSysIntr));
    if (!KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &dwSysIntr, sizeof(DWORD), NULL, 0, NULL))
        DEBUGMSG(ZONE_DEINIT | ZONE_ERROR, (TEXT("ERROR: Failed to release dwSysIntr.\r\n")));                

    DEBUGMSG(ZONE_DEINIT, (TEXT("I2CClass::~I2CClass:DeleteCriticalSection(): Deleting I2C_IOControl Critical Section! \r\n")));

    // I2C Bus Critical Section
    {
        DeleteCriticalSection(&gcsI2CBusLock);
        DeleteCriticalSection(&gcsI2CSlaveLock);
    }

    // Release Interrupt Occurrence Event -
    {   
        if (hInterrupted != NULL)
            CloseHandle(hInterrupted);

        DEBUGMSG(ZONE_DEINIT, (TEXT("I2CClass::~I2CClass: Release Interrupt Occurence Event \r\n")));
    }

    // Release I2C Register Base Mapped Virtual Memory -
    {
        if (pI2CReg != NULL)
            MmUnmapIoSpace((LPVOID) pI2CReg, sizeof(CSP_I2C_REG));

        DEBUGMSG(ZONE_DEINIT, (TEXT("I2CClass::~I2CClass: Release I2C Register Base Mapped Virtual Memory \r\n")));
    }

    if(pSBuf != NULL) 
    {
        delete pSBuf;
    }
    DEBUGMSG(ZONE_DEINIT, (TEXT("I2CClass::~I2CClass -\r\n")));
}

//-----------------------------------------------------------------------------
//
// Function: I2CClass::Reset
//
// This method performs a software reset on I2C internal register (I2CR). It is
// important to take note that the fields of the I2CClass are not modified in
// any way.
//
// Parameters:
//  None.
//

⌨️ 快捷键说明

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