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

📄 pwm.cpp

📁 SM501基于ARMV4/ARMV4I平台
💻 CPP
字号:
// -----------------------------------------------------------------------------
//
//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
//  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//  PARTICULAR PURPOSE.
//  Copyright (c) 2002 Silicon Motion, Inc.
//
//  Module Name:	pwm.cpp
//
//  Abstract:		Pulse Width Modulation API
//
// -----------------------------------------------------------------------------

#include "precomp.h"
#include "pwm.h"
#include "smi.h"


///////////////////////////////////////////////////////////////////////////////
// Macro for printing debug messages

#if 1
// Print messages only in DEBUG mode
#define MESSAGE DEBUGMSG
#define MESSAGE_ZONE GPE_ZONE_WARNING
#else
// Force messages even in RELEASE mode
#define MESSAGE RETAILMSG
#define MESSAGE_ZONE 0
#endif


///////////////////////////////////////////////////////////////////////////////
// Returns field mask

#define FIELD_MASK(f) ((1 << _F_SIZE(f)) - 1)


///////////////////////////////////////////////////////////////////////////////
// PWM API Command Handler.

ULONG SMI::HandleSMIPWMAPI(ULONG cjIn, PVOID pvIn, ULONG cjOut, PVOID pvOut)
{
	MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::HandleSMIPWMAPI\r\n")));
	ULONG ulRetVal = VGXPWM_INVALID_PARAMETER;

	if ((cjIn == sizeof(VGXPWM_STRUCT)) && (pvIn != NULL))
	{
		PVGXPWM_STRUCT pIn = (PVGXPWM_STRUCT)pvIn;

		switch (pIn->Command)
		{
		case VGXPWMCMD_INIT:
			ulRetVal = pwmInit(pIn->PWMIndex, pIn->wLowCounter,
				pIn->wHighCounter, pIn->byClockDivider, pIn->bIntEnable);
			break;

		case VGXPWMCMD_START:
			ulRetVal = pwmStart(pIn->PWMIndex);
			break;

		case VGXPWMCMD_STOP:
			ulRetVal = pwmStop(pIn->PWMIndex);
			break;

		default:
			MESSAGE(MESSAGE_ZONE, (TEXT("SMI::HandleSMIPWMAPI: invalid command has been specified\r\n")));
		}
	}
	else
	{
		MESSAGE(MESSAGE_ZONE,
			(TEXT("SMI::HandleSMIPWMAPI: invalid input structure\r\n")));
	}

	if (ulRetVal == VGXPWM_INVALID_PARAMETER)
		SetLastError(ERROR_INVALID_PARAMETER);

	MESSAGE(MESSAGE_ZONE, (TEXT("-SMI::HandleSMIPWMAPI\r\n")));
	return ulRetVal;
}


///////////////////////////////////////////////////////////////////////////////
// PWM Interrupt Handler.

VOID SMI::pwmIntHandler()
{
	DWORD pwmStatus;

	// Test PWM 0.
	pwmStatus = peekRegisterDWord(PWM_0);
	if (FIELD_GET(pwmStatus, PWM_0, INTERRUPT_STATUS) == PWM_0_INTERRUPT_STATUS_PENDING)
	{
		pokeRegisterDWord(PWM_0, pwmStatus);
		if (FIELD_GET(pwmStatus, PWM_0, STATUS) == PWM_0_STATUS_ENABLE)
		{
			SetEvent(m_PWMInfo[VGXPWM0].hIntEvent);
		}
	}

	// Test PWM 1.
	pwmStatus = peekRegisterDWord(PWM_1);
	if (FIELD_GET(pwmStatus, PWM_1, INTERRUPT_STATUS) == PWM_1_INTERRUPT_STATUS_PENDING)
	{
		pokeRegisterDWord(PWM_1, pwmStatus);
		if (FIELD_GET(pwmStatus, PWM_1, STATUS) == PWM_1_STATUS_ENABLE)
		{
			SetEvent(m_PWMInfo[VGXPWM1].hIntEvent);
		}
	}

	// Test PWM 2.
	pwmStatus = peekRegisterDWord(PWM_2);
	if (FIELD_GET(pwmStatus, PWM_2, INTERRUPT_STATUS) == PWM_2_INTERRUPT_STATUS_PENDING)
	{
		pokeRegisterDWord(PWM_2, pwmStatus);
		if (FIELD_GET(pwmStatus, PWM_2, STATUS) == PWM_2_STATUS_ENABLE)
		{
			SetEvent(m_PWMInfo[VGXPWM2].hIntEvent);
		}
	}
}


///////////////////////////////////////////////////////////////////////////////
// PWM Interrupt Handler Entry.

VOID pwmIntHandlerEntry(SMI* pSMI)
{
	pSMI->pwmIntHandler();
}


///////////////////////////////////////////////////////////////////////////////
// Initialization routine, called once during start up.

VOID SMI::InitPulseWidthModulation()
{
	// Init done flag
	static BOOL bInitDone = FALSE;

	if (!bInitDone)
	{
		MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::InitPulseWidthModulation\r\n")));

		// Init the info array
		ZeroMemory(&m_PWMInfo, sizeof(m_PWMInfo));

		// Init PWM address
		m_PWMInfo[VGXPWM0].PWMAddress = PWM_0;
		m_PWMInfo[VGXPWM1].PWMAddress = PWM_1;
		m_PWMInfo[VGXPWM2].PWMAddress = PWM_2;

		// Init event names
		m_PWMInfo[VGXPWM0].lpszIntEventName = PWM0_INT_EVENT_NAME;
		m_PWMInfo[VGXPWM1].lpszIntEventName = PWM1_INT_EVENT_NAME;
		m_PWMInfo[VGXPWM2].lpszIntEventName = PWM2_INT_EVENT_NAME;

		bInitDone = TRUE;
	}

	MESSAGE(MESSAGE_ZONE, (TEXT("-SMI::InitPulseWidthModulation\r\n")));
}


///////////////////////////////////////////////////////////////////////////////
// Initializes the selected PWM module.

ULONG SMI::pwmInit(
	VGXPWM_INDEX PWMIndex,	// PWM Index
	WORD wLowCounter,		// Low counter
	WORD wHighCounter,		// High counter
	BYTE byClockDivider,	// Clock divider
	BOOL bIntEnable)		// Interrupt enable
{
	MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::pwmInit\r\n")));
	ULONG nResult = VGXPWM_SUCCESS;

	// Perform the generic init
	InitPulseWidthModulation();

	// Make sure we're within range
	if ((PWMIndex < VGXPWM0) || (PWMIndex >= VGXPWMCOUNT))
	{
		MESSAGE(MESSAGE_ZONE,
			(TEXT("SMI::pwmInit: invalid PWM has been specified\r\n")));
		nResult = VGXPWM_INVALID_PARAMETER;
	}
	else
	{
#ifdef DISABLE_INTERRUPT_MANAGEMENT
		if (bIntEnable)
		{
			nResult = VGXPWM_INT_NOT_SUPPORTED;
		}
		else
		{
			// Close event handle
			if (m_PWMInfo[PWMIndex].hIntEvent)
			{
				CloseHandle(m_PWMInfo[PWMIndex].hIntEvent);
				m_PWMInfo[PWMIndex].hIntEvent = NULL;
			}

			// Init vars
			m_PWMInfo[PWMIndex].wLowCounter    = wLowCounter;
			m_PWMInfo[PWMIndex].wHighCounter   = wHighCounter;
			m_PWMInfo[PWMIndex].byClockDivider = byClockDivider;
			m_PWMInfo[PWMIndex].bIntEnable     = bIntEnable;
		}
#else
		// Close event handle
		if (m_PWMInfo[PWMIndex].hIntEvent)
		{
			CloseHandle(m_PWMInfo[PWMIndex].hIntEvent);
			m_PWMInfo[PWMIndex].hIntEvent = NULL;
		}

		// Init vars
		m_PWMInfo[PWMIndex].wLowCounter    = wLowCounter;
		m_PWMInfo[PWMIndex].wHighCounter   = wHighCounter;
		m_PWMInfo[PWMIndex].byClockDivider = byClockDivider;
		m_PWMInfo[PWMIndex].bIntEnable     = bIntEnable;
#endif
	}

	MESSAGE(MESSAGE_ZONE, (TEXT("-SMI::pwmInit\r\n")));
	return nResult;
}


///////////////////////////////////////////////////////////////////////////////
// Creates a PWM interrupt event if needed.

BOOL SMI::CreatePWMEvent(PWM_STRUCT& PWMInfo)
{
	BOOL bResult = TRUE;

	if (PWMInfo.hIntEvent)
	{
		if (!PWMInfo.bIntEnable)
		{
			CloseHandle(PWMInfo.hIntEvent);
			PWMInfo.hIntEvent = NULL;
		}
	}
	else
	{
		if (PWMInfo.bIntEnable)
		{
			PWMInfo.hIntEvent = CreateEvent(
				NULL, FALSE, FALSE, PWMInfo.lpszIntEventName);
			if (PWMInfo.hIntEvent == NULL)
			{
				MESSAGE(MESSAGE_ZONE,
					(TEXT("SMI::pwmStart: failed to create an event (%d)\r\n"),
						GetLastError()));
				bResult = FALSE;
			}
		}
	}

	return bResult;
}


///////////////////////////////////////////////////////////////////////////////
// Enables the selected PWM module.

ULONG SMI::pwmStart(
	VGXPWM_INDEX PWMIndex)	// PWM number
{
	MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::pwmStart\r\n")));
	ULONG nResult = VGXPWM_SUCCESS;

	// Make sure we're within range
	if ((PWMIndex < VGXPWM0) || (PWMIndex >= VGXPWMCOUNT))
	{
		MESSAGE(MESSAGE_ZONE,
			(TEXT("SMI::pwmStart: invalid PWM has been specified\r\n")));
		nResult = VGXPWM_INVALID_PARAMETER;
	}
	else
	{
		// Make sure PWM is inactive
		pwmStop(PWMIndex);

#ifndef DISABLE_INTERRUPT_MANAGEMENT
		// Register PWM interrupt handler
		RegisterHandler(pwmIntHandlerEntry, _F_MASK(INT_MASK_PWM));
#endif

		// Enable PWM gate register
		setGate(
			_F_MASK(CURRENT_POWER_GATE_GPIO_PWM_I2C),
			FIELD_SET(0, CURRENT_POWER_GATE, GPIO_PWM_I2C, ENABLE));

		// Create an event
		if (!CreatePWMEvent(m_PWMInfo[PWMIndex]))
		{
			nResult = VGXPWM_EVENT_FAILED;
		}
		else
		{
			// Determine init value
			DWORD dwPWMInit =
				FIELD_SET  (0, PWM_0, STATUS, ENABLE) |
				FIELD_VALUE(0, PWM_0, HIGH_COUNTER,
					(m_PWMInfo[PWMIndex].wHighCounter   & FIELD_MASK(PWM_0_HIGH_COUNTER))) |
				FIELD_VALUE(0, PWM_0, LOW_COUNTER,
					(m_PWMInfo[PWMIndex].wLowCounter    & FIELD_MASK(PWM_0_LOW_COUNTER)))  |
				FIELD_VALUE(0, PWM_0, CLOCK_DIVIDE,
					(m_PWMInfo[PWMIndex].byClockDivider & FIELD_MASK(PWM_0_CLOCK_DIVIDE))) |
				FIELD_VALUE(0, PWM_0, INTERRUPT,
					(m_PWMInfo[PWMIndex].bIntEnable? PWM_0_INTERRUPT_ENABLE : PWM_0_INTERRUPT_DISABLE));

			// Program init value
			pokeRegisterDWord(m_PWMInfo[PWMIndex].PWMAddress,
				dwPWMInit);

			// Set flags
			m_PWMInfo[PWMIndex].bPWMEnabled = TRUE;
			m_bPWMEnabled = TRUE;
		}
	}

	MESSAGE(MESSAGE_ZONE, (TEXT("-SMI::pwmStart\r\n")));
	return nResult;
}


///////////////////////////////////////////////////////////////////////////////
// Stops the selected PWM module.

BOOL SMI::pwmStop(
	VGXPWM_INDEX PWMIndex)	// PWM number
{
	MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::pwmStop\r\n")));
	ULONG nResult = VGXPWM_SUCCESS;

	// Make sure we're within range
	if ((PWMIndex < VGXPWM0) || (PWMIndex >= VGXPWMCOUNT))
	{
		MESSAGE(MESSAGE_ZONE,
			(TEXT("SMI::pwmStop: invalid PWM has been specified\r\n")));
		nResult = VGXPWM_INVALID_PARAMETER;
	}
	else
	{
		if (m_PWMInfo[PWMIndex].bPWMEnabled)
		{
			// Reset the flags
			m_PWMInfo[PWMIndex].bPWMEnabled = FALSE;

			BOOL bAtleastOneEnabled = FALSE;
			BOOL bAtleastOneNeedsInts = FALSE;
			for (INT i = 0; i < VGXPWMCOUNT; i++)
			{
				if (m_PWMInfo[i].bPWMEnabled)
				{
					bAtleastOneEnabled = TRUE;
					if (m_PWMInfo[i].bIntEnable)
						bAtleastOneNeedsInts = TRUE;
				}
			}

			m_bPWMEnabled = bAtleastOneEnabled;

#ifndef DISABLE_INTERRUPT_MANAGEMENT
			// Delete the PWM interrupt handler
			if (!bAtleastOneNeedsInts)
				DisableHandler(_F_MASK(INT_MASK_PWM));
#endif

			// Stop PWM
			DWORD dwPWM = peekRegisterDWord(m_PWMInfo[PWMIndex].PWMAddress);
			dwPWM = FIELD_SET(dwPWM, PWM_0, STATUS, DISABLE);
			dwPWM = FIELD_SET(dwPWM, PWM_0, INTERRUPT, DISABLE);
			pokeRegisterDWord(m_PWMInfo[PWMIndex].PWMAddress, dwPWM);

			// Close the event handle
			if (m_PWMInfo[PWMIndex].hIntEvent)
			{
				CloseHandle(m_PWMInfo[PWMIndex].hIntEvent);
				m_PWMInfo[PWMIndex].hIntEvent = NULL;
			}

			// Disable PWM gate register
			setGate(
				_F_MASK(CURRENT_POWER_GATE_GPIO_PWM_I2C),
				FIELD_SET(0, CURRENT_POWER_GATE, GPIO_PWM_I2C, DISABLE));
		}
	}

	MESSAGE(MESSAGE_ZONE, (TEXT("-SMI::pwmStop\r\n")));
	return nResult;
}

⌨️ 快捷键说明

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