显示屏幕(LCD)模块提供屏幕相关功能接口,调用者为上层应用模块(含 init、状态机、ui),上下文依赖关系,如图 3-7 所示。linux
系统框架为 linux+Huawei LiteOS 双系统架构,媒体业务部署在 Huawei LiteOS 端,为了上电快速预览,须要屏幕需部署在 Huawei LiteOS。api
LCD HAL 层架构图架构
初始化流程主要包含如下方面:app
INIT 模块在系统中对外的依赖关系如图 4-82 所示。框架
├──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
Linux 端初始化主要处理与业务功能强相关的初始化操做,如状态管理业务、按键业务、储存管理业务、文件管理业务、UI 等。ide
在Hi3556AV100_MobileCam_SDK_V2.0.1.0\reference\actioncam\modules\init\amp\linux\src
中的hi_product_main.c
函数
进程名字为main_app
,在bootapp脚本下运行:oop
从main
函数开始:ui
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 tool\n\n"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 done\n"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 done\n"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"); }
IPCM的初始化,详情参考:《HiSysLink API 开发参考.pdf》
/** * @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:%s\n", strerror(errno)); return HI_ENORES; } return HI_SUCCESS; }
这就证实了上图的方式,Linux做为client,用ipcm与liteos创建联系,读写sharefs;
读取驱动的线程:
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': %s\n", 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 init\n"); 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; }
咱们使用了如下两个函数:
在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 registered\n", 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
;
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 inited\n", 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; }
这里调用的是stHALSCREENObj
为ST7789实现的结构体;
在hal_screens_st7789文件中:
/** 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, };
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 failed\n"); 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:failed\n"); 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; }