1.GPIO的使用
GPIO的設(shè)置一般為三步:
1 設(shè)置gpio端口復(fù)用、
2 設(shè)置GPIO口的方向、
3 讀取或者寫入GPIO值了袁;
第一步不是每個(gè)GPIO口都是要配置的最筒,如果你設(shè)置的GPIO端口有復(fù)用功能贺氓,那么你需要對(duì)GPIO對(duì)應(yīng)復(fù)用寄存器進(jìn)行配置,例如:文檔中GPIO5_5是有復(fù)用功能的床蜘,0:PWM_OUT0 辙培; 1:GPIO5_5,所以把復(fù)用寄存器設(shè)置為1就是表示為GPIO5_5邢锯;
但有些GPIO端口是沒有復(fù)用功能的扬蕊,例如GPIO0_0,這個(gè)就不需要復(fù)用寄存器的設(shè)置;
1.1丹擎、設(shè)置gpio端口復(fù)用
所謂復(fù)用尾抑,就是指一個(gè)端口能同時(shí)干很多事,但是具體你要求他干啥,是需要設(shè)置的蛮穿,這就是管腳復(fù)用寄存器的作用庶骄。
舉個(gè)例子,如果我們想設(shè)置GPIO5_5践磅,需要首先找到對(duì)應(yīng)的管腳復(fù)用寄存器地址单刁;通過手冊查詢,如果你想讓這個(gè)管腳作為io口使用府适,需要給復(fù)用控制寄存器muxctrl_reg54這個(gè)寄存器里寫0x01羔飞;管腳復(fù)用寄存器的基地址為0x120f_0000,muxctrl_reg54的偏移地址0xD8,所以這個(gè)寄存器的地址為0x120f00D8檐春;
通過HIS自帶的himm命令輸入以下即可:
himm 0x120F00D8 0x01逻淌;
1.2、設(shè)置GPIO口的方向
所謂方向疟暖,就是你是把io做輸入用還是輸出用卡儒。比如如果你的板子外接了個(gè)電池模塊,你希望電池模塊在沒電的時(shí)候俐巴,能夠給你的板子一個(gè)信號(hào)骨望,告訴你沒電了,這時(shí)你就需要將io口作為輸入使用欣舵。反過來擎鸠,如果你需要告訴外接的什么設(shè)備什么事情,那就要將io口做輸出缘圈,設(shè)置GPIO口的方向劣光,實(shí)際上就是寫 GPIO_DIR寄存器。同樣的糟把,首先需要找地址绢涡,對(duì)于GPIO5的基地址為:0x121A_0000;GPIO_DIR的偏移地址為0x400,得到GPIO5_5的寄存器地址為0x121A_0400;然后GPIO_DIR寄存器里有8位,每一位對(duì)應(yīng)一個(gè)GPIO的方向遣疯,如果你想把GPIO5_5的方向設(shè)為輸出雄可,則需要把BIT5置1;
himm 0x121A0400 0x20(二進(jìn)制 0010 0000)
1.3另锋、讀取或者寫入GPIO值
GPIO_DATA為GPIO數(shù)據(jù)寄存器,用來對(duì)輸入或輸出數(shù)據(jù)進(jìn)行緩存狭归;當(dāng)配置GPIO_DIR中對(duì)應(yīng)位為輸出時(shí)夭坪,寫入GPIO_DATA 寄存器的值將會(huì)輸出到相應(yīng)的管腳(注意需要配置正確的管腳復(fù)用);如果配置為輸入時(shí)过椎,將會(huì)讀取相應(yīng)輸入管腳的值室梅。
注意:當(dāng)GPIO_DIR相應(yīng)的比特配置為輸入時(shí),有效讀取的結(jié)果將返回管腳的值;當(dāng)配置為輸出的時(shí)候亡鼠,有效讀取的結(jié)果將返回寫入的值赏殃。GPIO_DATA 寄存器利用PADDR[9:2]實(shí)現(xiàn)了讀寫寄存器比特的屏蔽操作。該寄存器對(duì)應(yīng)256個(gè)地址空間间涵。PADDR[9:2]分別對(duì)應(yīng)GPIO_DATA[7:0]仁热,當(dāng)相應(yīng)的bit 為高時(shí),則可以對(duì)相應(yīng)的位進(jìn)行讀寫操作勾哩;反之抗蠢,若對(duì)應(yīng)bit 為低則不能進(jìn)行操作。
例如:
若地址為0x3FC(0b11_1111_1100)思劳,則對(duì)GPIO_DATA[7:0]這8bit 操作全部有效迅矛。
若地址為0x200(0b10_0000_0000),則僅對(duì)GPIO_DATA[7]的操作有效潜叛。
同樣的秽褒,首先需要找地址,對(duì)于GPIO5的基地址為:0x121A_0000;GPIO_DATA 的偏移地址為0x3FC,得到GPIO5_5的寄存器地址為0x121A_03FC威兜,如果你想把GPIO5_5寫入值為1時(shí)销斟,則需要把BIT5置1;
himm 0x121A03FC 0x20(二進(jìn)制 0010 0000)
2. 解碼操作
H264解碼實(shí)例走的是HARD DISK->VDEC->VPSS->VO->顯示器的流程牡属,這個(gè)流程一定要熟悉牢記票堵,代碼實(shí)現(xiàn)都是圍繞這條主線來編寫的
H.264視頻解碼實(shí)例走的是HARDDISK->VDEC->VPSS->VO->顯示器的處理流程,這個(gè)過程可以細(xì)分為八大步驟逮栅,這八大步驟在其他類型的音視頻編解碼樣例也類似悴势,可以說這八大步驟是使用海思HIMPP API的靈魂。
下面簡單介紹這個(gè)八大步驟的內(nèi)容:
Step1:初始化HIMPP SYS和通用VB緩沖措伐,包括設(shè)置緩沖區(qū)的大小特纤,緩沖區(qū)塊的數(shù)目。需要注意的是侥加,在設(shè)置通用VB參數(shù)之前捧存,必須確保HIMPP系統(tǒng)已經(jīng)退出,否則設(shè)置失敗担败。
Step2:設(shè)置通用緩沖區(qū)的公共緩沖池屬性昔穴。
Step3:配置解碼器,包括指定解碼類型提前,這里是H.264解碼樣例吗货,當(dāng)然選PT_H264啦,然后指定視頻大小狈网、解碼優(yōu)先級(jí)等等宙搬。然后創(chuàng)建解碼通道笨腥,并是能加收解碼流。
Step4:配置VPSS參數(shù)勇垛,VPSS是對(duì)VDEC解碼后的流進(jìn)行處理脖母,如裁剪、降噪等闲孤,MPEG解碼實(shí)例從簡單應(yīng)用出發(fā)谆级,僅僅按默認(rèn)的方式配置VPSS。
Step5:配置VO參數(shù)崭放,這一步也很關(guān)鍵哨苛,因?yàn)樗付水嬅孑敵觯ǔR姷腍DMI和VGA币砂,主要是配置輸出顯示建峭,圖層屬性設(shè)置、輸出位置等信息决摧。
Step6:綁定VDEC與VPSS亿蒸,實(shí)現(xiàn)H264解碼流程。
Step7:綁定VPSS與VO掌桩,實(shí)現(xiàn)H264解碼流程边锁。
Step8:推送視頻流數(shù)據(jù)亿遂,這一步需要文件讀寫配合使用仙蛉,對(duì)于H264一般做法是先從NALU層中找到視頻I幀,然后將I幀推流至VDEC弄喘,緊接下來就按幀推送就好了则拷,該注意的是H264解碼必須先推送I幀贡蓖,否則會(huì)視頻會(huì)花屏。
/*
**函數(shù)功能:HIMPP系統(tǒng)初始化及配置
**HARDDISK->VDEC->VPSS->VO->顯示器的處理流程
*/
HARDDISK->VDEC->VPSS->VO->顯示器的處理流程
HI_S32 SAMPLE_VDEC_VdhH264(char *filename)
{
VB_CONF_S stVbConf, stModVbConf;
HI_S32 i, s32Ret = HI_SUCCESS;
VdecThreadParam pstVdecSend;
SIZE_S stSize;
VO_PUB_ATTR_S stVoPubAttr;
VO_VIDEO_LAYER_ATTR_S stVoLayerAttr;
stSize.u32Width = HD_WIDTH;
stSize.u32Height = HD_HEIGHT;
/************************************************
step1: HIMPP系統(tǒng)初始化以及通用視頻緩沖池配置
*************************************************/
MPP_SYS_CONF_S stSysConf = {0};
memset(&stVbConf,0,sizeof(stVbConf));
stSize.u32Width = HD_WIDTH; //指定寬度
stSize.u32Height = HD_HEIGHT; //指定高度
stVbConf.u32MaxPoolCnt = 1; //指定最大緩沖池?cái)?shù)量煌茬,我們只創(chuàng)建一路H264解碼
stVbConf.astCommPool[0].u32BlkSize = (stSize.u32Width * stSize.u32Height* 4) >> 1; //指定緩沖池大小斥铺,經(jīng)驗(yàn)值一般為分辨率的1.5倍左右,這里取2倍
stVbConf.astCommPool[0].u32BlkCnt = 3;
memset(stVbConf.astCommPool[0].acMmzName,0,sizeof(stVbConf.astCommPool[0].acMmzName));
HI_MPI_SYS_Exit(); //設(shè)置前先去初始換HIMPP調(diào)用
for(i=0;i<22;i++)
{
HI_MPI_VB_ExitModCommPool(i);
}
for(i=0; i<256; i++)
{
HI_MPI_VB_DestroyPool(i);
}
HI_MPI_VB_Exit();
s32Ret = HI_MPI_VB_SetConf(&stVbConf);//配置緩沖池
if (HI_SUCCESS != s32Ret)
{
hidebug("HI_MPI_VB_SetConf failed!\n");
return HI_FAILURE;
}
s32Ret = HI_MPI_VB_Init();//緩沖池初始化
if (HI_SUCCESS != s32Ret)
{
hidebug("HI_MPI_VB_Init failed!\n");
return HI_FAILURE;
}
stSysConf.u32AlignWidth = 16;
/*set config of mpp system*/
s32Ret = HI_MPI_SYS_SetConf(&stSysConf);//HIMPP配置
if (HI_SUCCESS != s32Ret)
{
hidebug("HI_MPI_SYS_SetConf failed!\n");
return HI_FAILURE;
}
s32Ret = HI_MPI_SYS_Init(); //HIMPP系統(tǒng)初始化
if (HI_SUCCESS != s32Ret)
{
hidebug("HI_MPI_SYS_Init failed!\n");
return HI_FAILURE;
}
/************************************************
step2: 系統(tǒng)緩沖池模塊初始化配置
*************************************************/
memset(&stModVbConf, 0, sizeof(VB_CONF_S));
stModVbConf.u32MaxPoolCnt = 2;
stModVbConf.astCommPool[0].u32BlkSize = (stSize.u32Width * stSize.u32Height* 4) >> 1;;
stModVbConf.astCommPool[0].u32BlkCnt = 5;
stModVbConf.astCommPool[1].u32BlkSize = (stSize.u32Width * stSize.u32Height* 4) >> 1;;
stModVbConf.astCommPool[1].u32BlkCnt = 5;
HI_MPI_VB_ExitModCommPool(VB_UID_VDEC);
HI_MPI_VB_SetModPoolConf(VB_UID_VDEC, &stModVbConf);
HI_MPI_VB_InitModCommPool(VB_UID_VDEC);
/************************************************
step3: 解碼器配置及初始化
*************************************************/
VDEC_CHN_ATTR_S stVdecChnAttr;
stVdecChnAttr.enType = PT_H264; //創(chuàng)建H264類型的解碼器
stVdecChnAttr.u32BufSize = 3 * stSize.u32Width * stSize.u32Height;//指定解碼緩沖區(qū)大小
stVdecChnAttr.u32Priority = 5; //設(shè)置解碼優(yōu)先級(jí)
stVdecChnAttr.u32PicWidth = stSize.u32Width; //解碼寬高
stVdecChnAttr.u32PicHeight =stSize.u32Height;
stVdecChnAttr.stVdecVideoAttr.enMode = VIDEO_MODE_FRAME; //幀式解碼模式
stVdecChnAttr.stVdecVideoAttr.u32RefFrameNum = 2;
stVdecChnAttr.stVdecVideoAttr.bTemporalMvpEnable = 0;
HI_MPI_VDEC_SetChnVBCnt(0, 10);
HI_MPI_VDEC_CreateChn(0, &stVdecChnAttr);
HI_MPI_VDEC_StartRecvStream(0);
/************************************************
step4: VPSS配置及初始化
*************************************************/
VPSS_GRP_PARAM_S stVpssParam = {0};
VPSS_CHN_ATTR_S stChnAttr = {0};
VPSS_GRP_ATTR_S stVpssGrpAttr;
stVpssGrpAttr.enDieMode = VPSS_DIE_MODE_NODIE;
stVpssGrpAttr.bIeEn = HI_FALSE;
stVpssGrpAttr.bDciEn = HI_TRUE;
stVpssGrpAttr.bNrEn = HI_FALSE;
stVpssGrpAttr.bHistEn = HI_FALSE;
stVpssGrpAttr.bEsEn = HI_FALSE;
stVpssGrpAttr.enPixFmt = PIXEL_FORMAT_YUV_SEMIPLANAR_420;//解碼像素格式Y(jié)UV420
stVpssGrpAttr.u32MaxW = stSize.u32Width;
stVpssGrpAttr.u32MaxH = stSize.u32Height;
/*** create vpss group ***/
s32Ret = HI_MPI_VPSS_CreateGrp(0, &stVpssGrpAttr);//創(chuàng)建VPSS Group坛善,在HI3536平臺(tái)一個(gè)Group有4個(gè)VPSS Channel
if (s32Ret != HI_SUCCESS)
{
hidebug("HI_MPI_VPSS_CreateGrp failed!\n");
return HI_FAILURE;
}
/*** set vpss param ***/
s32Ret = HI_MPI_VPSS_GetGrpParam(0, &stVpssParam);//設(shè)置VPSS Group屬性
if(s32Ret != HI_SUCCESS)
{
hidebug("HI_MPI_VPSS_GetGrpParam failed!\n");
return HI_FAILURE;
}
stVpssParam.u32IeStrength = 0;
s32Ret = HI_MPI_VPSS_SetGrpParam(0, &stVpssParam);
if(s32Ret != HI_SUCCESS)
{
hidebug("HI_MPI_VPSS_GetGrpParam failed!\n");
return HI_FAILURE;
}
/*** enable vpss chn, with frame ***/
/* Set Vpss Chn attr */
stChnAttr.bSpEn = HI_FALSE;
stChnAttr.bUVInvert = HI_FALSE;
stChnAttr.bBorderEn = HI_TRUE;
stChnAttr.stBorder.u32Color = 0xffffff;//背景色為黑色
stChnAttr.stBorder.u32LeftWidth = 2;
stChnAttr.stBorder.u32RightWidth = 2;
stChnAttr.stBorder.u32TopWidth = 2;
stChnAttr.stBorder.u32BottomWidth = 2;
s32Ret = HI_MPI_VPSS_SetChnAttr(0, 0, &stChnAttr);
if(s32Ret != HI_SUCCESS)
{
hidebug("HI_MPI_VPSS_SetChnAttr failed!\n");
return HI_FAILURE;
}
s32Ret = HI_MPI_VPSS_EnableChn(0, 0);//由于只有一路H264解碼晾蜘,故只用Group0 及 Channel 0
if(s32Ret != HI_SUCCESS)
{
hidebug("HI_MPI_VPSS_EnableChn failed!\n");
return HI_FAILURE;
}
/*** start vpss group ***/
s32Ret = HI_MPI_VPSS_StartGrp(0);
if(s32Ret != HI_SUCCESS)
{
hidebug("HI_MPI_VPSS_StartGrp failed!\n");
return HI_FAILURE;
}
/************************************************
step5: 配置VO及初始化VO
*************************************************/
VO_CHN_ATTR_S stChnAttr1;
stVoPubAttr.enIntfSync = VO_OUTPUT_1080P60;//VO輸出模式為1080p 60幀,普通顯示器的輸出
stVoPubAttr.enIntfType = VO_INTF_VGA | VO_INTF_HDMI;//啟用VGA及HDMI輸出
s32Ret = HI_MPI_VO_SetPubAttr(0, &stVoPubAttr);
if(s32Ret != HI_SUCCESS)
{
hidebug("HI_MPI_VO_SetPubAttr failed!\n");
return HI_FAILURE;
}
s32Ret = HI_MPI_VO_Enable(0);
if (s32Ret != HI_SUCCESS)
{
hidebug("HI_MPI_VO_Enable failed!\n");
return HI_FAILURE;
}
//設(shè)置VO Layer顯示配置眠屎,如顯示位置剔交,大小,像素類型
stVoLayerAttr.u32DispFrmRt = 60;
stVoLayerAttr.stDispRect.u32Width = 1920;
stVoLayerAttr.stDispRect.u32Height = 1080;
stVoLayerAttr.stImageSize.u32Width = stVoLayerAttr.stDispRect.u32Width;
stVoLayerAttr.stImageSize.u32Height = stVoLayerAttr.stDispRect.u32Height;
stVoLayerAttr.bClusterMode = HI_FALSE;
stVoLayerAttr.bDoubleFrame = HI_FALSE;
stVoLayerAttr.enPixFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_420;
s32Ret = HI_MPI_VO_SetVideoLayerAttr(0, &stVoLayerAttr);
if(s32Ret != HI_SUCCESS)
{
hidebug("HI_MPI_VO_SetVideoLayerAttr failed!\n");
return HI_FAILURE;
}
s32Ret = HI_MPI_VO_EnableVideoLayer(0);
if (s32Ret != HI_SUCCESS)
{
hidebug("HI_MPI_VO_EnableVideoLayer failed!\n");
return HI_FAILURE;
}
/*
if (HI_SUCCESS != SAMPLE_COMM_VO_HdmiStart(stVoPubAttr.enIntfSync))
{
hidebug("Start SAMPLE_COMM_VO_HdmiStart failed!\n");
}
*/
//設(shè)置VO Channel顯示位置改衩,大小
stChnAttr1.stRect.s32X = 0;
stChnAttr1.stRect.s32Y = 0;
stChnAttr1.stRect.u32Width = 1920;
stChnAttr1.stRect.u32Height = 1080;
stChnAttr1.u32Priority = 0;
stChnAttr1.bDeflicker = HI_FALSE;
s32Ret = HI_MPI_VO_SetChnAttr(0, 0, &stChnAttr1);
if (s32Ret != HI_SUCCESS)
{
hidebug("failed with %#x!\n", s32Ret);
}
s32Ret = HI_MPI_VO_EnableChn(0,0);
if (s32Ret != HI_SUCCESS)
{
hidebug("failed with %#x!\n", s32Ret);
}
/************************************************
step6: 解碼器綁定VPSS
*************************************************/
MPP_CHN_S stSrcChn;
MPP_CHN_S stDestChn;
stSrcChn.enModId = HI_ID_VDEC;
stSrcChn.s32DevId = 0;
stSrcChn.s32ChnId = 0;
stDestChn.enModId = HI_ID_VPSS;
stDestChn.s32DevId = 0;
stDestChn.s32ChnId = 0;
s32Ret = HI_MPI_SYS_Bind(&stSrcChn, &stDestChn);
if(s32Ret != HI_SUCCESS)
{
hidebug("HI_MPI_SYS_Bind failed!\n");
return HI_FAILURE;
}
/************************************************
step7: VPSS綁定VO
*************************************************/
stSrcChn.enModId = HI_ID_VPSS;
stSrcChn.s32DevId = 0;
stSrcChn.s32ChnId = 0;
stDestChn.enModId = HI_ID_VOU;
stDestChn.s32DevId = 0;
stDestChn.s32ChnId = 0;
s32Ret = HI_MPI_SYS_Bind(&stSrcChn, &stDestChn);
if(s32Ret != HI_SUCCESS)
{
hidebug("HI_MPI_SYS_Bind failed!\n");
return HI_FAILURE;
}
/************************************************
step8: 發(fā)送解碼流岖常,推送H264流至VDEC
*************************************************/
sprintf(pstVdecSend.cFileName,filename);
pstVdecSend.s32MilliSec = 0;
pstVdecSend.s32ChnId = 0;
pstVdecSend.s32IntervalTime = 1;
pstVdecSend.u64PtsInit = 0;
pstVdecSend.u64PtsIncrease = 0;
pstVdecSend.eCtrlSinal = VDEC_CTRL_START;
pstVdecSend.bLoopSend = HI_TRUE;
pstVdecSend.bManuSend = HI_FALSE;
pstVdecSend.enType = PT_H264;
pstVdecSend.s32MinBufSize = (stVdecChnAttr.u32PicWidth *stVdecChnAttr.u32PicHeight * 3)>>1;
pstVdecSend.s32StreamMode = VIDEO_MODE_FRAME;
SAMPLE_COMM_VDEC_H264_SendStream(&pstVdecSend);
return s32Ret;
}
int main(int argc, char *argv[])
{
if(argc != 2)
{
printf("Usage: h264 filename\n");
exit(0);
}
signal(SIGINT, SAMPLE_VDEC_HandleSig);
signal(SIGTERM, SAMPLE_VDEC_HandleSig);
SAMPLE_VDEC_VdhH264(argv[1]);
return 0;
}