📄 i2cclass.cpp
字号:
//
// 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 + -