显示屏幕(LCD)模块提供屏幕相关功能接口,调用者为上层应用模块(含 init、状态机、ui),上下文依赖关系,如图 3-7 所示。
系统框架为 linux Huawei LiteOS 双系统架构,媒体业务部署在 Huawei LiteOS 端,为了上电快速预览,需要屏幕需部署在 Huawei LiteOS。
- 用户交互业务在 linux 端,屏幕亮度、熄屏/亮屏等屏幕动态属性需要在 linux 端提供接口。
- 屏幕 HAL 层含 linux 和 Huawei LiteOS 业务接口。
- linux 通过 ipcmsg 将命令传送给 Huawei liteOS,所有业务功能实现都在 Huawei LiteOS 端。
LCD HAL 层架构图
初始化流程主要包含以下方面:
- 操作系统配置,如双核驱动、共享文件系统初始化;
- 芯片配置,如管脚配置、系统时钟、媒体驱动加载;
- 外设配置,如屏幕配置、外设驱动加载;
- 业务服务启动,如媒体初始化、开机业务、UI 启动。
INIT 模块在系统中对外的依赖关系如图 4-82 所示。
1. 目录结构:
1.1 双系统 AMP 目录结构
代码语言:javascript复制├──liteos
│ ├── src
│ │ ├── hi_product_init_main.c //Huawei LiteOS 端初始化 main 函数
│ │ ├── hi_product_init_hi35xxvxx.c //芯片相关初始化 C 文件
│ │ ├── hi_product_init_chip.h //芯片相关初始化头文件
│ │ ├── hi_product_ init _os.c //OS 相关初始化 C 文件
│ │ ├── hi_product_ init _os.h //OS 相关初始化头文件
│ │ ├── hi_product_ init _peripheral.c //外设相关初始化 C 文件
│ │ ├── hi_product_ init _peripheral.h //外设相关初始化头文件
│ │ └── hi_product_ init _service.c //业务相关初始化 C 文件
│ │ └── hi_product_ init _service.h //业务相关初始化头文件
│ ├──Makefile
├──linux
│ ├── src
│ │ ├── hi_product_main.c //linux 端初始化实现
│ ├──Makefile
└── Makefile
2. linux 一端的代码
Linux 端初始化主要处理与业务功能强相关的初始化操作,如状态管理业务、按键业务、储存管理业务、文件管理业务、UI 等。
在Hi3556AV100_MobileCam_SDK_V2.0.1.0referenceactioncammodulesinitamplinuxsrc
中的hi_product_main.c
进程名字为main_app
,在bootapp脚本下运行:
从main
函数开始:
HI_S32 main(HI_S32 s32Argc, HI_CHAR* pszArgv[])
{
HI_TIME_STAMP;
HI_PDT_WORKMODE_E enPoweronWorkmode = HI_PDT_WORKMODE_BUTT;
HI_STORAGEMNG_CFG_S stStorageMngCfg;
PDT_Init(&enPoweronWorkmode, &stStorageMngCfg);
#if PDT_APP_COMMAND_DEBUG
printf(GREEN"nenable command line debug toolnn"NONE);
PDT_CommandDebug(enPoweronWorkmode, &stStorageMngCfg);
#endif
/** wait for poweroff Semaphore, it can not run to here when
** PDT_APP_COMMAND_DEBUG is true and the while loop is not over */
while((HI_SUCCESS != sem_wait(&s_PowerOffSem)) && (errno == EINTR));
PDT_Deinit(&stStorageMngCfg);
return HI_SUCCESS;
}
看一下主要的函数PDT_Init()
函数,下面主要讲几个主要的关于LCD的函数:
static HI_VOID PDT_Init(HI_PDT_WORKMODE_E *penPoweronWorkmode,
HI_STORAGEMNG_CFG_S* pstStorageMngCfg)
{
HI_S32 s32Ret = HI_SUCCESS;
/** init debug related setting */
PDT_SetDebugLogLevel(); //初始化打印优先级
PDT_SetCrashHandleType(); //初始化错误发生的时候的处理的句柄函数,其实里面就是处理了相应的信号函数
/** init semaphore */
sem_init(&s_PowerOffSem, 0, 0); //初始化信号量
/** init Param */
s32Ret = HI_PDT_PARAM_Init(); //初始化变量
PDT_APP_CHECK_RET(s32Ret, "HI_PDT_PARAM_Init");
/** init ShareFs */
extern void sharefs_server_init(void);
sharefs_server_init(); //这里是调用ipcm 中的sharefs,sharedfs是liteos与Linux之间利用 IPCM 通信和共享内存,实现其读写 Linux上指定目录下的内容。
/** init custom msg client */
s32Ret = HI_MSG_CLIENT_Init(); //初始化ipcm中的client端
PDT_APP_CHECK_RET(s32Ret, "HI_MSG_CLIENT_Init");
/** set system time */
PDT_SyncLinuxLiteosTime(); //同步liteos和Linux的时间
/** register hal sreen ops */
#if defined(CONFIG_SCREEN)
extern HI_HAL_SCREEN_OBJ_S stHALSCREENObj;
s32Ret = HI_HAL_SCREEN_Register(HI_HAL_SCREEN_IDX_0, &stHALSCREENObj); //HI_HAL_SCREEN_IDX_0是指枚举,是指第一个屏幕,初始化重复注册一次
PDT_APP_CHECK_RET(s32Ret, "HI_HAL_SCREEN_Register");
s32Ret = HI_HAL_SCREEN_Init(HI_HAL_SCREEN_IDX_0); //屏幕注册0
PDT_APP_CHECK_RET(s32Ret, "HI_HAL_SCREEN_Init");
#endif
/** create load driver thread */
s32Ret = PDT_LoadDriverThread();
PDT_APP_CHECK_RET(s32Ret, "PDT_LoadDriverThread");
/** get rtc time from liteOS */
/** init eventhub */
s32Ret = HI_EVTHUB_Init(); //初始化事件路由模块,详情参考《camera 中间件开发参考》,统一管理系统中事件订阅和发布的模块
PDT_APP_CHECK_RET(s32Ret, "HI_EVTHUB_Init");
HI_STORAGEMNG_RegisterEvent(); //将存储注册到eventhub里面
HI_RECMNG_RegisterEvent(); //将RECMNG注册到eventhub里面
HI_PHOTOMNG_RegisterEvent();
HI_FILEMNG_RegisterEvent();
HI_PDT_USBCTRL_RegisterEvent();
HI_PDT_STATEMNG_RegisterEvent();
HI_KEYMNG_RegisterEvent();
HI_PDT_MEDIA_RegisterEvent();
HI_PDT_PARAM_RegisterEvent();
HI_LIVESVR_RegisterEvent();
HI_PDT_SCENE_RegisterEvent();
HI_UPGRADE_RegisterEvent();
HI_PDT_NETCTRL_RegisterEvent();
#ifdef CONFIG_GAUGE_ON
HI_GAUGEMNG_RegisterEvent();
#endif
/** init mapi sys */
s32Ret = HI_MAPI_Sys_Init(); //初始化系统资源,参考文档《HiMAPI V1.0媒体处理开发流程》
PDT_APP_CHECK_RET(s32Ret, "HI_MAPI_Sys_Init");
HI_PDT_WORKMODE_E enPoweronWorkmode = HI_PDT_WORKMODE_BUTT;
HI_PDT_POWERON_ACTION_E enPoweronAction = HI_PDT_POWERON_ACTION_BUTT;
s32Ret = HI_PDT_STATEMNG_GeneratePoweronWorkmode(&enPoweronAction, &enPoweronWorkmode); //状态管理电源开机状态机
PDT_APP_CHECK_RET(s32Ret,"GetPowerOnWorkMode");
MLOGD("PowerOn WorkMode(%d)n", enPoweronWorkmode);
*penPoweronWorkmode = enPoweronWorkmode;
HI_PDT_MEDIAMODE_E enMediaMode = HI_PDT_MEDIAMODE_BUTT;
s32Ret = HI_PDT_PARAM_GetWorkModeParam(enPoweronWorkmode, HI_PDT_PARAM_TYPE_MEDIAMODE,
(HI_VOID *)&enMediaMode); //获取工作模式参数
PDT_APP_CHECK_RET(s32Ret,"GetWorkModeParam MediaMode");
MLOGD("Init MediaMode[%d]n", enMediaMode);
HI_PDT_MEDIA_CFG_S stMediaCfg;
HI_PDT_SCENE_MODE_S stSceneModeCfg;
s32Ret = HI_PDT_PARAM_GetMediaCfg(enPoweronWorkmode, enMediaMode, &stMediaCfg, &stSceneModeCfg); //获取媒体模式的配置
PDT_APP_CHECK_RET(s32Ret,"GetMediaModeCfg");
HI_BOOL bLoadDsp = HI_FALSE;
#ifdef CFG_POST_PROCESS
if (HI_PDT_WORKMODE_SING_PHOTO == enPoweronWorkmode
|| HI_PDT_WORKMODE_DLAY_PHOTO == enPoweronWorkmode)
{
bLoadDsp = HI_TRUE;
}
#endif
/** init media */
s32Ret = HI_PDT_MEDIA_Init(&stMediaCfg.stViVpssMode, &stMediaCfg.stVBCfg, bLoadDsp); //媒体初始化,包括 VI VPSS 模式配置和通路 VB 配置。
PDT_APP_CHECK_RET(s32Ret,"HI_MEDIA_Init");
/** update vo config */
s32Ret = HI_PDT_Media_UpdateDispCfg(&stMediaCfg, &stMediaCfg.stVideoOutCfg.astDispCfg[0]);
PDT_APP_CHECK_RET(s32Ret, "HI_PDT_Media_UpdateDispCfg");
/** init video out */
s32Ret = HI_PDT_MEDIA_VideoOutInit(&(stMediaCfg.stVideoOutCfg)); //视频输出通路初始化
PDT_APP_CHECK_RET(s32Ret,"HI_MEDIA_VideoOutInit");
MLOGD(GREEN"vo init donen"NONE);
/** init timedtask */
s32Ret = HI_TIMEDTASK_Init(); //定时器初始化
PDT_APP_CHECK_RET(s32Ret, "HI_TIMEDTASK_Init");
/** init player */
s32Ret = HI_PLAYER_Init(); //初始化播放器
PDT_APP_CHECK_RET(s32Ret, "HI_PLAYER_Init");
/** init ui */
s32Ret = HI_PDT_UI_Init();
PDT_APP_CHECK_RET(s32Ret, "HI_PDT_UI_Init");
MLOGD(GREEN"UI init donen"NONE);
/** load mmc driver */
PDT_LoadMmcDriver(); //加载mmc driver
/** init storagemng */
memset(pstStorageMngCfg, 0, sizeof(HI_STORAGEMNG_CFG_S));
s32Ret = HI_PDT_PARAM_GetStorageCfg(pstStorageMngCfg);
PDT_APP_CHECK_RET(s32Ret, "GetStorageCfg");
MLOGD("DevPath[%s] MountPath[%s]n"NONE,
pstStorageMngCfg->szDevPath, pstStorageMngCfg->szMntPath);
HI_STORAGEMNG_CALLBACK_S stCallback;
stCallback.pfnFormatPreProc = PDT_StoragemngFormatPreProc;
s32Ret = HI_STORAGEMNG_Create(pstStorageMngCfg,&stCallback); //创建SD卡管理模块
PDT_APP_CHECK_RET(s32Ret, "HI_STORAGEMNG_Create");
/* init osd */
HI_PDT_MEDIA_OSD_VIDEO_ATTR_S stOsdVideoAttr;
HI_PDT_PARAM_GetOSDVideoAttr(&stOsdVideoAttr);
s32Ret = HI_PDT_MEDIA_InitOSD(&stOsdVideoAttr, &stMediaCfg.stVideoCfg.stOsdCfg); //OSD 初始化,分配时间/字符串格式 OSD 位图资源。
PDT_APP_CHECK_RET(s32Ret, "InitOSD");
/** init netCtrl */
s32Ret = HI_PDT_NETCTRL_Init();
PDT_APP_CHECK_RET(s32Ret, "HI_PDT_NETCTRL_Init");
#ifdef CONFIG_GAUGE_ON
HI_GAUGEMNG_CFG_S stGaugeCfg = {};
stGaugeCfg.s32LowLevel = PDT_BATTERT_LOW_LEVEL;
stGaugeCfg.s32UltraLowLevel = PDT_BATTERT_ULTRA_LOW_LEVEL;
s32Ret = HI_GAUGEMNG_Init(&stGaugeCfg); //初始化电源管理模块
PDT_APP_CHECK_RET(s32Ret, "HI_GAUGEMNG_Init");
#endif
#ifdef CONFIG_RAWCAP_ON
/** init rawcap */
s32Ret = HI_RAWCAP_Init();
PDT_APP_CHECK_RET(s32Ret, "HI_RAWCAP_Init");
#endif
/** init statemng */
HI_PDT_STATEMNG_CONFIG_S stStatemngCfg;
stStatemngCfg.pfnExitMode = PDT_ExitModeCallback;
stStatemngCfg.pfnFormatPreProc = PDT_StoragemngFormatPreProc;
s32Ret = HI_PDT_STATEMNG_Init(&stStatemngCfg); //以普通录像为主
PDT_APP_CHECK_RET(s32Ret, "HI_PDT_STATEMNG_Init");
/** create delay services start thread */
s32Ret = PDT_ServiceDelayedStartThread();
PDT_APP_CHECK_RET(s32Ret, "PDT_ServiceDelayedStartThread");
}
- HI_MSG_CLIENT_Init
IPCM的初始化,详情参考:《HiSysLink API 开发参考.pdf》
代码语言:javascript复制/**
* @brief init the msg client.
* @return 0 success,non-zero error code.
* @exception None
* @author HiMobileCam Reference Develop Team
* @date 2017/12/22
*/
HI_S32 HI_MSG_CLIENT_Init(HI_VOID)
{
HI_S32 s32Ret = 0;
HI_APPCOMM_CHECK_EXPR(-1 == g_s32MsgFd, HI_EINITIALIZED);
HI_IPCMSG_CONNECT_S stConnectAttr = {1, HI_APPCOMM_MSG_SRVPORT, 1};
s32Ret = HI_IPCMSG_AddService(HI_APPCOMM_MSG_SRVNAME, &stConnectAttr); //增加IPCM的服务
if (HI_SUCCESS != s32Ret)
{
HI_LOG_PrintFuncErr(HI_IPCMSG_AddService, s32Ret);
return HI_EINTER;
}
s32Ret = HI_IPCMSG_Connect(&g_s32MsgFd, HI_APPCOMM_MSG_SRVNAME, MSG_Handler); //阻塞方式建立连接
if (HI_SUCCESS != s32Ret)
{
HI_IPCMSG_DelService(HI_APPCOMM_MSG_SRVNAME);
HI_LOG_PrintFuncErr(HI_IPCMSG_Connect, s32Ret);
return HI_EINTER;
}
pthread_t threadid;
s32Ret = pthread_create(&threadid, NULL, MSG_CLIENT_Run, NULL);
if (HI_SUCCESS != s32Ret)
{
HI_IPCMSG_Disconnect(g_s32MsgFd);
HI_IPCMSG_DelService(HI_APPCOMM_MSG_SRVNAME);
g_s32MsgFd = -1;
MLOGE("pthread_create fail:%sn", strerror(errno));
return HI_ENORES;
}
return HI_SUCCESS;
}
这就证明了上图的方式,Linux作为client,用ipcm与liteos建立联系,读写sharefs;
- 创造PDT_LoadDriverThread线程
读取驱动的线程:
代码语言:javascript复制HI_S32 HI_insmod(const HI_CHAR* pszPath, const HI_CHAR* pszOptions)
{
HI_S32 rc = 0;
HI_APPCOMM_CHECK_POINTER(pszPath, HI_EINVAL);
rc = hi_init_module(pszPath, pszOptions);
if (rc)
{
MLOGE("can't insert '%s': %sn", pszPath, moderror(rc));
}
return rc;
}
HI_S32 HI_HAL_TOUCHPAD_Init(HI_VOID)
{
HI_S32 s32Ret = HI_SUCCESS;
if (HI_FALSE == s_bTOUCHPADInitState)
{
HAL_TOUCHPAD_PinoutInit(); //初始化相应的管脚
/** insmod touchpad driver */
s32Ret = HI_insmod(HAL_TOUCHPAD_KO_PATH,NULL);
if(0 != s32Ret)
{
MLOGE("insmod touchpad:failed, errno(%d)n", errno);
return HI_HAL_EINVOKESYS;
}
s_bTOUCHPADInitState = HI_TRUE;
}
else
{
MLOGE("touchapd already initn");
return HI_HAL_EINITIALIZED;
}
return HI_SUCCESS;
}
/** load driver task */
static HI_U32 PDT_LoadDriver(void* pVoid)
{
HI_S32 s32Ret = HI_SUCCESS;
pthread_detach(pthread_self());
#ifdef CFG_LCD_TOUCHPAD_ON
s32Ret = HI_HAL_TOUCHPAD_Init(); //先加载驱动
PDT_APP_CHECK_RET(s32Ret, "HI_HAL_TOUCHPAD_Init");
s32Ret = HI_HAL_TOUCHPAD_Suspend(); //然后触摸板进行睡眠
PDT_APP_CHECK_RET(s32Ret, "HI_HAL_TOUCHPAD_Suspend");
#endif
PDT_LoadUSBPhy();
return s32Ret;
}
/** create thread to load driver */
static HI_S32 PDT_LoadDriverThread()
{
HI_S32 s32Ret = HI_SUCCESS;
s32Ret = pthread_create(&s_KoThread, NULL, (void*)PDT_LoadDriver, NULL);
PDT_APP_CHECK_RET(s32Ret, "pthread_create for PDT_LoadDriver");
return s32Ret;
}
- 其他都以注释的方式的再以上面来说:
2.1 以screen代码而言:
我们使用了以下两个函数:
- HI_HAL_SCREEN_Register
- HI_HAL_SCREEN_Init
在HI_HAL_SCREEN_Register
中:
HI_S32 HI_HAL_SCREEN_Register(HI_HAL_SCREEN_IDX_E enScreenIndex, const HI_HAL_SCREEN_OBJ_S* pstScreenObj)
{
//检查pstScreenObj是否为空指针
HI_APPCOMM_CHECK_POINTER(pstScreenObj, HI_HAL_EINVAL);
HI_APPCOMM_CHECK_POINTER(pstScreenObj->pfnDeinit, HI_HAL_EINVAL);
HI_APPCOMM_CHECK_POINTER(pstScreenObj->pfnGetAttr, HI_HAL_EINVAL);
HI_APPCOMM_CHECK_POINTER(pstScreenObj->pfnGetBackLightState, HI_HAL_EINVAL);
HI_APPCOMM_CHECK_POINTER(pstScreenObj->pfnGetContrast, HI_HAL_EINVAL);
HI_APPCOMM_CHECK_POINTER(pstScreenObj->pfnGetDisplayState, HI_HAL_EINVAL);
HI_APPCOMM_CHECK_POINTER(pstScreenObj->pfnGetLuma, HI_HAL_EINVAL);
HI_APPCOMM_CHECK_POINTER(pstScreenObj->pfnGetSaturature, HI_HAL_EINVAL);
HI_APPCOMM_CHECK_POINTER(pstScreenObj->pfnInit, HI_HAL_EINVAL);
HI_APPCOMM_CHECK_POINTER(pstScreenObj->pfnSetBackLightState, HI_HAL_EINVAL);
HI_APPCOMM_CHECK_POINTER(pstScreenObj->pfnSetContrast, HI_HAL_EINVAL);
HI_APPCOMM_CHECK_POINTER(pstScreenObj->pfnSetDisplayState, HI_HAL_EINVAL);
HI_APPCOMM_CHECK_POINTER(pstScreenObj->pfnSetLuma, HI_HAL_EINVAL);
HI_APPCOMM_CHECK_POINTER(pstScreenObj->pfnSetSaturature, HI_HAL_EINVAL);
HAL_SCREEN_CHECK_IDX(enScreenIndex);
if (s_astHALSCREENCtx[enScreenIndex].bRegister) //如果之前注册过
{
MLOGD("Screen[%d] has been registeredn", enScreenIndex);
return HI_HAL_EREGRED;
}
memcpy(&s_astHALSCREENCtx[enScreenIndex].stScreenObj, pstScreenObj, sizeof(HI_HAL_SCREEN_OBJ_S));
s_astHALSCREENCtx[enScreenIndex].bRegister = HI_TRUE;
return HI_SUCCESS;
}
其实就是将传进来的参数赋值给s_astHALSCREENCtx
;
2.2 HI_HAL_SCREEN_Init函数
代码语言:javascript复制HI_S32 HI_HAL_SCREEN_Init(HI_HAL_SCREEN_IDX_E enScreenIndex)
{
HAL_SCREEN_CHECK_IDX(enScreenIndex);
HAL_SCREEN_CHECK_REGISTER(enScreenIndex);
if (s_astHALSCREENCtx[enScreenIndex].bInit)
{
MLOGD("Screen[%d] has been initedn", enScreenIndex);
return HI_SUCCESS;
}
HI_S32 s32Ret = HI_SUCCESS;
if(HI_NULL != s_astHALSCREENCtx[enScreenIndex].stScreenObj.pfnInit)
{
s32Ret = s_astHALSCREENCtx[enScreenIndex].stScreenObj.pfnInit(); //在这里调用了相应的函数
HI_APPCOMM_CHECK_RETURN_WITH_ERRINFO(s32Ret, HI_HAL_EINTER, "pfnInit");
}
else
{
MLOGE("Screen[%d] Null ptr.n", enScreenIndex);
return HI_HAL_EINVAL;
}
s_astHALSCREENCtx[enScreenIndex].bInit = HI_TRUE;
return HI_SUCCESS;
}
2.3 pfnInit()函数
这里调用的是stHALSCREENObj
为ST7789实现的结构体;
在hal_screens_st7789文件中:
代码语言:javascript复制/** OTA5182 Object */
HI_HAL_SCREEN_OBJ_S stHALSCREENObj =
{
.pfnInit = HAL_SCREEN_ST7789_Init,
.pfnGetAttr = HAL_SCREEN_ST7789_GetAttr,
.pfnSetDisplayState = HAL_SCREEN_ST7789_SetDisplayState,
.pfnGetDisplayState = HAL_SCREEN_ST7789_GetDisplayState,
.pfnSetBackLightState = HAL_SCREEN_ST7789_SetBackLightState,
.pfnGetBackLightState = HAL_SCREEN_ST7789_GetBackLightState,
.pfnSetLuma = HAL_SCREEN_ST7789_SetLuma,
.pfnGetLuma = HAL_SCREEN_ST7789_GetLuma,
.pfnSetSaturature = HAL_SCREEN_ST7789_SetSatuature,
.pfnGetSaturature = HAL_SCREEN_ST7789_GetSatuature,
.pfnSetContrast = HAL_SCREEN_ST7789_SetContrast,
.pfnGetContrast = HAL_SCREEN_ST7789_GetContrast,
.pfnDeinit = HAL_SCREEN_ST7789_Deinit,
};
代码语言:javascript复制static HI_S32 HAL_SCREEN_ST7789_Init(HI_VOID)
{
/** Initial screen Device */
#if (defined(AMP_LINUX_HUAWEILITE) && defined(__HuaweiLite__)) || defined(AMP_HUAWEILITE)
HI_S32 s32Ret = HI_SUCCESS;
s32Ret = hi_ssp_lcd_init();
if (HI_SUCCESS != s32Ret)
{
MLOGE("init screen failedn");
return HI_HAL_EINTER;
};
s_stHALSCREENFt7789Ctx.enSCREENDisplayState = HI_TRUE;
#elif (defined(AMP_LINUX))
//所以在Linux这一端就是用这边的函数:
HI_S32 s32Ret = HI_SUCCESS;
s32Ret = HI_insmod(HI_APPFS_KOMOD_PATH"/hi_ssp_st7789.ko",NULL);
if(HI_SUCCESS != s32Ret)
{
MLOGE("insmod hi_ssp_st7789:failedn");
return HI_HAL_EINTER;
}
s_s32HALSCREENFd = open(HAL_SCREEN_DEV, O_RDWR);
if (HAL_FD_INITIALIZATION_VAL == s_s32HALSCREENFd)
{
HI_rmmod(HI_APPFS_KOMOD_PATH"/hi_ssp_st7789.ko");
return HI_HAL_EINTER;
}
s_stHALSCREENFt7789Ctx.enSCREENDisplayState = HI_TRUE;
#endif
return HI_SUCCESS;
}