📄 pwm.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 + -