基于S3C2450 + WINCE的背光驱动及背光亮度调节应用程序移植详解之驱动篇
2014-02-26 21:13
316 查看
背光驱动程序设计
1. 这里硬件接口使用S3C2450的GPB1,即定时器1.
定时器的输入频率 = PCLK /{prescaler value + 1} / {divider value}。
首先设置prescaler value:
[cpp] view
plaincopy
static void BAK_SetPrescaleAndMux( DWORD v_Prescale, DWORD v_Mux )
{
// Set prescale.
if(v_Prescale<=255)
{
v_pPWMRegs->TCFG0 = v_pPWMRegs->TCFG0 & (~0xff) | v_Prescale;
}
// Set divider value.Timer1 is used
switch(v_Mux)
{
case 1:// 1/2
v_pPWMRegs->TCFG1 = v_pPWMRegs->TCFG1 & (~0xF0) | (0x0<<4);
break;
case 2:// 1/4
v_pPWMRegs->TCFG1 = v_pPWMRegs->TCFG1 & (~0xF0) | (0x1<<4);
break;
case 3:// 1/8
v_pPWMRegs->TCFG1 = v_pPWMRegs->TCFG1 & (~0xF0) | (0x2<<4);
break;
case 4:// 1/16
v_pPWMRegs->TCFG1 = v_pPWMRegs->TCFG1 & (~0xF0) | (0x3<<4);
break;
case 5:
default:// External TCLK0
v_pPWMRegs->TCFG1 = v_pPWMRegs->TCFG1 & (~0xF0) | (0x4<<4);
break;
}
}
然后设置divider value:
[cpp] view
plaincopy
static void BAK_SetTCNTB( DWORD v_Tcntb)
{
if(v_Tcntb<=0xffff)
{
v_pPWMRegs->TCNTB1 = v_Tcntb;
}
}
2. 接着设置TOUT1的定时器PWM脉宽:
[cpp] view
plaincopy
static void BAK_SetTCMPB( DWORD v_Tcmpb)
{
if(v_Tcmpb<=0xffff)
{
v_pPWMRegs->TCMPB1 = v_Tcmpb;
}
}
3. 设置完这些就可以开启TOUT1了。代码如下:
[cpp] view
plaincopy
static void BAK_StartPwmTimer( void )
{
// Set GPB1 to TOUT1.
v_pIOPregs->GPBCON &= ~(0x03<<2);
v_pIOPregs->GPBCON |= (0x02<<2);
// Stop pwm timer 1, first.
v_pPWMRegs->TCON &= ~(0xF<<8);
v_pPWMRegs->TCON |= (0x6<<8); // 这里0x2<<8也OK吧!!!!!
// Start it again.
v_pPWMRegs->TCON &= ~(0xF<<8);
v_pPWMRegs->TCON |= (0x9<<8);
}
4. 背光亮度调节代码如下(将亮度设置为10个级别):
[cpp] view
plaincopy
static void BAK_AdjuctBacklightLevel(DWORD v_Level)
{
if((v_Level>=BAK_LEVEL_MIN)&&(v_Level<=BAK_LEVEL_MAX))// v_Level=[1:10]
{
l_dwBackLightLevel = v_Level;
BAK_SetTCMPB((l_dwTcntb * la_dwLevel[v_Level-1])/100);
}
}
5.以上事情都做完了后,就可以编写通用的流接口程序了。由于程序比较简单,这里
仅贴上XXX_IOControl的代码如下:
[cpp] view
plaincopy
BOOL BAK_IOControl(
DWORD hOpenContext,
DWORD dwCode,
PBYTE pBufIn,
DWORD dwLenIn,
PBYTE pBufOut,
DWORD dwLenOut,
PDWORD pdwActualOut
)
{
DWORD dwErr = ERROR_INVALID_PARAMETER;
BOOL bRc;
RETAILMSG(lqm_bakdbg, (TEXT("[lqm:BKL] IOCTL code = %d/r/n"), dwCode));
switch (dwCode)
{
case IOCTL_POWER_CAPABILITIES: // determines device-specific capabilities
RETAILMSG(DBGBAK, (TEXT("[lqm:BKL] IOCTL_POWER_CAPABILITIES/r/n")));
if (pBufOut && dwLenOut >= sizeof (POWER_CAPABILITIES) && pdwActualOut)
{
__try
{
PPOWER_CAPABILITIES PowerCaps = (PPOWER_CAPABILITIES)pBufOut;
// Right now supports D0 (permanently on) and D4(off) only.
memset(PowerCaps, 0, sizeof(*PowerCaps));
PowerCaps->DeviceDx = 0x12; //support D0, D1, D4
*pdwActualOut = sizeof(*PowerCaps);
bRc = TRUE;
dwErr = ERROR_SUCCESS;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
RETAILMSG(DBGBAK1, (TEXT("<BKL> exception in ioctl/r/n")));
}
}
else
bRc = FALSE;
break;
case IOCTL_POWER_QUERY: // determines whether changing power state is feasible
RETAILMSG(DBGBAK, (TEXT("<BKL> Received IOCTL_POWER_QUERY/r/n")));
if (pBufOut && dwLenOut >= sizeof(CEDEVICE_POWER_STATE))
{
// Return a good status on any valid query, since we are always ready to
// change power states (if asked for state we don't support, we move to next highest, eg D3->D4).
__try
{
CEDEVICE_POWER_STATE ReqDx = *(PCEDEVICE_POWER_STATE)pBufOut;
if (VALID_DX(ReqDx))
{
// This is a valid Dx state so return a good status.
bRc = TRUE;
dwErr = ERROR_SUCCESS;
}
else
{
bRc = FALSE;
}
RETAILMSG(DBGBAK, (TEXT("<BKL> IOCTL_POWER_QUERY %s/r/n"), dwErr == ERROR_SUCCESS ? (TEXT("succeeded")) : (TEXT("failed")) ));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
RETAILMSG(DBGBAK1, (TEXT("<BKL> Exception in ioctl/r/n")));
}
}
else
bRc = FALSE;
break;
case IOCTL_POWER_SET: // requests a change from one device power state to another
RETAILMSG(lqm_bakdbg, (TEXT("[lqm:BKL] Received IOCTL_POWER_SET/r/n")));
if (pBufOut && dwLenOut >= sizeof(CEDEVICE_POWER_STATE))
{
__try
{
CEDEVICE_POWER_STATE ReqDx = *(PCEDEVICE_POWER_STATE)pBufOut;
if (VALID_DX(ReqDx))
{
RETAILMSG(lqm_bakdbg,(TEXT("[lqm:BKL] Received IOCTL_POWER_SET=%d/r/n"), ReqDx));
if( ReqDx == (CEDEVICE_POWER_STATE)D2 || ReqDx == (CEDEVICE_POWER_STATE)D3)
bklStatus = (CEDEVICE_POWER_STATE)D4;
else
bklStatus = ReqDx;
//SetEvent(g_evtBacklight);
// 调整亮度值后调用函数执行调整
BAK_hw_setBL();
*(PCEDEVICE_POWER_STATE) pBufOut = bklStatus;
*pdwActualOut = sizeof(CEDEVICE_POWER_STATE);
bRc = TRUE;
dwErr = ERROR_SUCCESS;
RETAILMSG(lqm_bakdbg, (TEXT("[lqm:BKL] IOCTL_POWER_SET to D%d /r/n"), ReqDx));
}
else
{
bRc = FALSE;
RETAILMSG(DBGBAK1, (TEXT("<BKL> Invalid state request D%d/r/n"), ReqDx));
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
RETAILMSG(DBGBAK1, (TEXT("<BKL> Exception in ioctl/r/n")));
}
}
else
{
bRc = FALSE;
}
break;
case IOCTL_POWER_GET: // gets the current device power state
RETAILMSG(DBGBAK, (TEXT("<BKL> Received IOCTL_POWER_GET/r/n/n")));
if (pBufOut != NULL && dwLenOut >= sizeof(CEDEVICE_POWER_STATE))
{
__try
{
*(PCEDEVICE_POWER_STATE)pBufOut = getBacklightStatus();
bRc = TRUE;
dwErr = ERROR_SUCCESS;
RETAILMSG(DBGBAK, (TEXT("<BKL> IOCTL_POWER_GET: passing back %u/r/n"), getBacklightStatus()));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
RETAILMSG(DBGBAK1, (TEXT("<BKL> Exception in ioctl/r/n")));
}
}
else
bRc = FALSE;
break;
// 背光亮度调节
case IOCTL_BACKLIGHT_ADJUST:
if (pBufOut != NULL && (dwLenOut>=sizeof(DWORD)))
{
DWORD dwBackLight = *((DWORD*)pBufOut);
if((BAK_LEVEL_MAX <dwBackLight) || (BAK_LEVEL_MIN > dwBackLight ))
{
*(DWORD*)pBufOut = ERROR_INVALID_PARAMETER;
*pdwActualOut = sizeof(DWORD);
bRc = FALSE;
}
else
{
BAK_AdjuctBacklightLevel(*(DWORD*)pBufOut);
// Adjust backlight level.
*(DWORD*)pBufOut = ERROR_SUCCESS;
*pdwActualOut = sizeof(DWORD);
bRc = TRUE;
}
}
else
{
bRc = FALSE;
}
break;
case IOCTL_BACKLIGHT_GETLEVEL:
if (pBufOut != NULL && (dwLenOut>=sizeof(DWORD)))
{
// Return the current backlight level.
*(DWORD*)pBufOut = l_dwBackLightLevel;
*pdwActualOut = sizeof(DWORD);
bRc = TRUE;
}
else
{
bRc = FALSE;
}
break;
}
return(bRc);
}
可以看到有如下几个case:
IOCTL_POWER_CAPABILITIES;
IOCTL_POWER_QUERY;
IOCTL_POWER_SET;
IOCTL_POWER_GET;
IOCTL_BACKLIGHT_ADJUST;
IOCTL_BACKLIGHT_GETLEVEL;
其中
IOCTL_POWER_CAPABILITIES:代表电源管理器请求设备驱动返回设备支持的电源状态及相关特征;
IOCTL_POWER_SET:请求驱动更新设备的电源状态;
IOCTL_POWER_QUERY:电源管理器询问设备是否准备好进行状态切换;
IOCTL_POWER_GET:请求驱动返回当前设备的电源状态;
IOCTL_BACKLIGHT_ADJUST:调节背光亮度的接口;
IOCTL_BACKLIGHT_GETLEVEL:获取背光亮度级别的接口。
1. 这里硬件接口使用S3C2450的GPB1,即定时器1.
定时器的输入频率 = PCLK /{prescaler value + 1} / {divider value}。
首先设置prescaler value:
[cpp] view
plaincopy
static void BAK_SetPrescaleAndMux( DWORD v_Prescale, DWORD v_Mux )
{
// Set prescale.
if(v_Prescale<=255)
{
v_pPWMRegs->TCFG0 = v_pPWMRegs->TCFG0 & (~0xff) | v_Prescale;
}
// Set divider value.Timer1 is used
switch(v_Mux)
{
case 1:// 1/2
v_pPWMRegs->TCFG1 = v_pPWMRegs->TCFG1 & (~0xF0) | (0x0<<4);
break;
case 2:// 1/4
v_pPWMRegs->TCFG1 = v_pPWMRegs->TCFG1 & (~0xF0) | (0x1<<4);
break;
case 3:// 1/8
v_pPWMRegs->TCFG1 = v_pPWMRegs->TCFG1 & (~0xF0) | (0x2<<4);
break;
case 4:// 1/16
v_pPWMRegs->TCFG1 = v_pPWMRegs->TCFG1 & (~0xF0) | (0x3<<4);
break;
case 5:
default:// External TCLK0
v_pPWMRegs->TCFG1 = v_pPWMRegs->TCFG1 & (~0xF0) | (0x4<<4);
break;
}
}
然后设置divider value:
[cpp] view
plaincopy
static void BAK_SetTCNTB( DWORD v_Tcntb)
{
if(v_Tcntb<=0xffff)
{
v_pPWMRegs->TCNTB1 = v_Tcntb;
}
}
2. 接着设置TOUT1的定时器PWM脉宽:
[cpp] view
plaincopy
static void BAK_SetTCMPB( DWORD v_Tcmpb)
{
if(v_Tcmpb<=0xffff)
{
v_pPWMRegs->TCMPB1 = v_Tcmpb;
}
}
3. 设置完这些就可以开启TOUT1了。代码如下:
[cpp] view
plaincopy
static void BAK_StartPwmTimer( void )
{
// Set GPB1 to TOUT1.
v_pIOPregs->GPBCON &= ~(0x03<<2);
v_pIOPregs->GPBCON |= (0x02<<2);
// Stop pwm timer 1, first.
v_pPWMRegs->TCON &= ~(0xF<<8);
v_pPWMRegs->TCON |= (0x6<<8); // 这里0x2<<8也OK吧!!!!!
// Start it again.
v_pPWMRegs->TCON &= ~(0xF<<8);
v_pPWMRegs->TCON |= (0x9<<8);
}
4. 背光亮度调节代码如下(将亮度设置为10个级别):
[cpp] view
plaincopy
static void BAK_AdjuctBacklightLevel(DWORD v_Level)
{
if((v_Level>=BAK_LEVEL_MIN)&&(v_Level<=BAK_LEVEL_MAX))// v_Level=[1:10]
{
l_dwBackLightLevel = v_Level;
BAK_SetTCMPB((l_dwTcntb * la_dwLevel[v_Level-1])/100);
}
}
5.以上事情都做完了后,就可以编写通用的流接口程序了。由于程序比较简单,这里
仅贴上XXX_IOControl的代码如下:
[cpp] view
plaincopy
BOOL BAK_IOControl(
DWORD hOpenContext,
DWORD dwCode,
PBYTE pBufIn,
DWORD dwLenIn,
PBYTE pBufOut,
DWORD dwLenOut,
PDWORD pdwActualOut
)
{
DWORD dwErr = ERROR_INVALID_PARAMETER;
BOOL bRc;
RETAILMSG(lqm_bakdbg, (TEXT("[lqm:BKL] IOCTL code = %d/r/n"), dwCode));
switch (dwCode)
{
case IOCTL_POWER_CAPABILITIES: // determines device-specific capabilities
RETAILMSG(DBGBAK, (TEXT("[lqm:BKL] IOCTL_POWER_CAPABILITIES/r/n")));
if (pBufOut && dwLenOut >= sizeof (POWER_CAPABILITIES) && pdwActualOut)
{
__try
{
PPOWER_CAPABILITIES PowerCaps = (PPOWER_CAPABILITIES)pBufOut;
// Right now supports D0 (permanently on) and D4(off) only.
memset(PowerCaps, 0, sizeof(*PowerCaps));
PowerCaps->DeviceDx = 0x12; //support D0, D1, D4
*pdwActualOut = sizeof(*PowerCaps);
bRc = TRUE;
dwErr = ERROR_SUCCESS;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
RETAILMSG(DBGBAK1, (TEXT("<BKL> exception in ioctl/r/n")));
}
}
else
bRc = FALSE;
break;
case IOCTL_POWER_QUERY: // determines whether changing power state is feasible
RETAILMSG(DBGBAK, (TEXT("<BKL> Received IOCTL_POWER_QUERY/r/n")));
if (pBufOut && dwLenOut >= sizeof(CEDEVICE_POWER_STATE))
{
// Return a good status on any valid query, since we are always ready to
// change power states (if asked for state we don't support, we move to next highest, eg D3->D4).
__try
{
CEDEVICE_POWER_STATE ReqDx = *(PCEDEVICE_POWER_STATE)pBufOut;
if (VALID_DX(ReqDx))
{
// This is a valid Dx state so return a good status.
bRc = TRUE;
dwErr = ERROR_SUCCESS;
}
else
{
bRc = FALSE;
}
RETAILMSG(DBGBAK, (TEXT("<BKL> IOCTL_POWER_QUERY %s/r/n"), dwErr == ERROR_SUCCESS ? (TEXT("succeeded")) : (TEXT("failed")) ));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
RETAILMSG(DBGBAK1, (TEXT("<BKL> Exception in ioctl/r/n")));
}
}
else
bRc = FALSE;
break;
case IOCTL_POWER_SET: // requests a change from one device power state to another
RETAILMSG(lqm_bakdbg, (TEXT("[lqm:BKL] Received IOCTL_POWER_SET/r/n")));
if (pBufOut && dwLenOut >= sizeof(CEDEVICE_POWER_STATE))
{
__try
{
CEDEVICE_POWER_STATE ReqDx = *(PCEDEVICE_POWER_STATE)pBufOut;
if (VALID_DX(ReqDx))
{
RETAILMSG(lqm_bakdbg,(TEXT("[lqm:BKL] Received IOCTL_POWER_SET=%d/r/n"), ReqDx));
if( ReqDx == (CEDEVICE_POWER_STATE)D2 || ReqDx == (CEDEVICE_POWER_STATE)D3)
bklStatus = (CEDEVICE_POWER_STATE)D4;
else
bklStatus = ReqDx;
//SetEvent(g_evtBacklight);
// 调整亮度值后调用函数执行调整
BAK_hw_setBL();
*(PCEDEVICE_POWER_STATE) pBufOut = bklStatus;
*pdwActualOut = sizeof(CEDEVICE_POWER_STATE);
bRc = TRUE;
dwErr = ERROR_SUCCESS;
RETAILMSG(lqm_bakdbg, (TEXT("[lqm:BKL] IOCTL_POWER_SET to D%d /r/n"), ReqDx));
}
else
{
bRc = FALSE;
RETAILMSG(DBGBAK1, (TEXT("<BKL> Invalid state request D%d/r/n"), ReqDx));
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
RETAILMSG(DBGBAK1, (TEXT("<BKL> Exception in ioctl/r/n")));
}
}
else
{
bRc = FALSE;
}
break;
case IOCTL_POWER_GET: // gets the current device power state
RETAILMSG(DBGBAK, (TEXT("<BKL> Received IOCTL_POWER_GET/r/n/n")));
if (pBufOut != NULL && dwLenOut >= sizeof(CEDEVICE_POWER_STATE))
{
__try
{
*(PCEDEVICE_POWER_STATE)pBufOut = getBacklightStatus();
bRc = TRUE;
dwErr = ERROR_SUCCESS;
RETAILMSG(DBGBAK, (TEXT("<BKL> IOCTL_POWER_GET: passing back %u/r/n"), getBacklightStatus()));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
RETAILMSG(DBGBAK1, (TEXT("<BKL> Exception in ioctl/r/n")));
}
}
else
bRc = FALSE;
break;
// 背光亮度调节
case IOCTL_BACKLIGHT_ADJUST:
if (pBufOut != NULL && (dwLenOut>=sizeof(DWORD)))
{
DWORD dwBackLight = *((DWORD*)pBufOut);
if((BAK_LEVEL_MAX <dwBackLight) || (BAK_LEVEL_MIN > dwBackLight ))
{
*(DWORD*)pBufOut = ERROR_INVALID_PARAMETER;
*pdwActualOut = sizeof(DWORD);
bRc = FALSE;
}
else
{
BAK_AdjuctBacklightLevel(*(DWORD*)pBufOut);
// Adjust backlight level.
*(DWORD*)pBufOut = ERROR_SUCCESS;
*pdwActualOut = sizeof(DWORD);
bRc = TRUE;
}
}
else
{
bRc = FALSE;
}
break;
case IOCTL_BACKLIGHT_GETLEVEL:
if (pBufOut != NULL && (dwLenOut>=sizeof(DWORD)))
{
// Return the current backlight level.
*(DWORD*)pBufOut = l_dwBackLightLevel;
*pdwActualOut = sizeof(DWORD);
bRc = TRUE;
}
else
{
bRc = FALSE;
}
break;
}
return(bRc);
}
可以看到有如下几个case:
IOCTL_POWER_CAPABILITIES;
IOCTL_POWER_QUERY;
IOCTL_POWER_SET;
IOCTL_POWER_GET;
IOCTL_BACKLIGHT_ADJUST;
IOCTL_BACKLIGHT_GETLEVEL;
其中
IOCTL_POWER_CAPABILITIES:代表电源管理器请求设备驱动返回设备支持的电源状态及相关特征;
IOCTL_POWER_SET:请求驱动更新设备的电源状态;
IOCTL_POWER_QUERY:电源管理器询问设备是否准备好进行状态切换;
IOCTL_POWER_GET:请求驱动返回当前设备的电源状态;
IOCTL_BACKLIGHT_ADJUST:调节背光亮度的接口;
IOCTL_BACKLIGHT_GETLEVEL:获取背光亮度级别的接口。
相关文章推荐
- 基于S3C2450 + WINCE的背光驱动及背光亮度调节应用程序移植详解之驱动篇[原创]
- 【嵌入式Linux学习七步曲之第四篇 Linux内核移植】详解Linux2.6内核中基于platform机制的驱动模型
- 基于嵌入式Linux的LCD背光调节及驱动的实现
- 基于嵌入式Linux的LCD背光调节及驱动的实现
- Linux内核驱动在Tx2440上的移植详解(七、LCD背光驱动移植)
- S3c6410 linux内核移植(8)---添加pwm驱动,控制lcd背光亮度
- 详解Linux2.6内核中基于platform机制的驱动模型
- 基于3.14内核PL2303_USB驱动的移植
- 基于设备树的TQ2440触摸屏驱动移植
- 快速开启小太阳图标、解决显卡亮度调节。(适用于多种显卡驱动方式)
- 基于tiny210v2的linux-3.9.6内核驱动移植2:按键驱动
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- 省电模式下调节背光亮度后重启手机,背光亮度恢复默认。
- 基于ubuntu-2.6.35内核的SDIO-WiFi驱动移植
- WINCE基于PWM实现的背光驱动
- android调节屏幕亮度(包括只修改应用程序和修改系统)
- 基于MT6752/32平台 Android L版本驱动移植步骤
- 一、利用Visual Studio 2010创建第一个基于服务和数据驱动的Silverlight应用程序
- 详解Linux2.6内核中基于platform机制的驱动模型 (经典)
- I.mx6s上移植wm8960驱动(基于linux3.0.101版本)