好记心不如烂笔头,为方便以后查看代码及代码重复利用,这里贴出S3C2440 Camera驱动代码。使用友善MINI2440开发板,开发环境为RealView MDK 4.22。
原始工程下载地址:点击打开链接
最初,本人在网上下载了许多mini2440 camera驱动的代码,但结果都不尽人意,因为这些代码看起来都比较晦涩难懂,都是直接对寄存器进行位与位或操作,且有的代码排版布局很乱,对初学者来说难度较大。由于本人接触了STM32开发后,觉得STM32的库函数给初学者提供了很大帮助,仅仅通过函数名及变量名就能知道当前操作的是哪个寄存器,这样在阅读代码时就能很容易明白代码的含义了,增强了程序的可读性。由此启发,本人也仿照STM32库函数的风格,写了一个基于S3C2440 CAMIF的库函数,这样当以后自己回过头来再看自己写的代码时就能很快理解代码的含义,也能帮助其他学习2440
camera的初学者,让他们能更容易理解代码的思路。
结构体定义:
typedef struct { //SOURCE FORMAT REGISTER u32 ITU601_656n; u32 UVOffset; u32 SourceHsize; u32 Order422; u32 SourceVsize; //WINDOW OPTION REGISTER u32 WinOfsEn; u32 WinHorOfst; u32 WinVerOfst; //GLOBAL CONTROL REGISTER u32 TestPattern; u32 InvPolCAMPCLK; u32 InvPolCAMVSYNC; u32 InvPolCAMHREF; }CAMIF_InitTypeDef; typedef struct { //Y START ADDRESS REGISTER u32 YStartAddr1; u32 YStartAddr2; u32 YStartAddr3; u32 YStartAddr4; //Cb START ADDRESS REGISTER u32 CbStartAddr1; u32 CbStartAddr2; u32 CbStartAddr3; u32 CbStartAddr4; //Cr START ADDRESS REGISTER u32 CrStartAddr1; u32 CrStartAddr2; u32 CrStartAddr3; u32 CrStartAddr4; //CODEC TARGET FORMAT REGISTER u32 In422_Co; u32 Out422_Co; u32 TargetHsize_Co; u32 FlipMd_Co; u32 TargetVsize_Co; //CODEC DMA CONTROL REGISTER u32 Yburst1_Co; u32 Yburst2_Co; u32 Cburst1_Co; u32 Cburst2_Co; //CODEC PRE-SCALER CONTROL REGISTER u32 SHfactor_Co; u32 PreHorRatio_Co; u32 PreVerRatio_Co; u32 PreDstWidth_Co; u32 PreDstHeight_Co; //CODEC MAIN-SCALER CONTROL REGISTER u32 ScalerBypass_Co; u32 ScaleUpDown_Co; u32 MainHorRatio_Co; u32 MainVerRatio_Co; //CODEC DMA TARGET AREA REGISTER u32 TargetArea_Co; }CAMIF_CodecInitTypeDef; typedef struct { //RGB START ADDRESS REGISTER u32 RGBStartAddr1; u32 RGBStartAddr2; u32 RGBStartAddr3; u32 RGBStartAddr4; //PREVIEW TARGET FORMAT REGISTER u32 TargetHsize_Pr; u32 FlipMd_Pr; u32 TargetVsize_Pr; //PREVIEW DMA CONTROL REGISTER u32 RGBburst1_Pr; u32 RGBburst2_Pr; //PREVIEW PRE-SCALER CONTROL REGISTER u32 SHfactor_Pr; u32 PreHorRatio_Pr; u32 PreVerRatio_Pr; u32 PreDstWidth_Pr; u32 PreDstHeight_Pr; //PREVIEW MAIN-SCALER CONTROL REGISTER u32 RGBformat_Pr; u32 ScaleUpDown_Pr; u32 MainHorRatio_Pr; u32 MainVerRatio_Pr; //PREVIEW DMA TARGET AREA REGISTER u32 TargetArea_Pr; }CAMIF_PreviewInitTypeDef;
CAMIF接口的配置(主要寄存器的配置):
void CAMIF_Config(unsigned int HorOfst, unsigned int VerOfst) { CAMIF_InitTypeDef CAMIF_InitStruct; CAMIF_CodecInitTypeDef CAMIF_CoInitStruct; CAMIF_PreviewInitTypeDef CAMIF_PrInitStruct; unsigned int mainburst, remainburst; unsigned int H_Shift, V_Shift; unsigned int PreHorRatio, PreVerRatio; unsigned int MainHorRatio, MainVerRatio; unsigned int SRC_Width, SRC_Height; unsigned int DST_Width, DST_Height; /*********************** global parameters ****************************/ CAMIF_InitStruct.ITU601_656n = ITU_601; CAMIF_InitStruct.UVOffset = UVOffest_0; CAMIF_InitStruct.Order422 = Order_YCbYCr; CAMIF_InitStruct.SourceHsize = CAM_XSIZE; CAMIF_InitStruct.SourceVsize = CAM_YSIZE; CAMIF_InitStruct.WinOfsEn = (HorOfst || VerOfst) ? 1 : 0; CAMIF_InitStruct.WinHorOfst = HorOfst; CAMIF_InitStruct.WinVerOfst = VerOfst; CAMIF_InitStruct.TestPattern = Pattern_Normal; CAMIF_InitStruct.InvPolCAMPCLK = ENABLE; CAMIF_InitStruct.InvPolCAMHREF = DISABLE; CAMIF_InitStruct.InvPolCAMVSYNC = DISABLE; CAMIF_Init(&CAMIF_InitStruct); /*********************** preview scaler parameters ********************/ CAMIF_PrInitStruct.RGBStartAddr1 = (u32)LCD_BUFFER; CAMIF_PrInitStruct.RGBStartAddr2 = (u32)LCD_BUFFER; CAMIF_PrInitStruct.RGBStartAddr3 = (u32)LCD_BUFFER; CAMIF_PrInitStruct.RGBStartAddr4 = (u32)LCD_BUFFER; CAMIF_PrInitStruct.RGBformat_Pr = RGBformat_16; CAMIF_PrInitStruct.FlipMd_Pr = FlipMode_Xmirror; CAMIF_PrInitStruct.TargetHsize_Pr = LCD_XSIZE; CAMIF_PrInitStruct.TargetVsize_Pr = LCD_YSIZE; CAMIF_PrInitStruct.TargetArea_Pr = LCD_XSIZE * LCD_YSIZE; CalcBurstSize(LCD_XSIZE * 2, &mainburst, &remainburst); CAMIF_PrInitStruct.RGBburst1_Pr = mainburst; CAMIF_PrInitStruct.RGBburst2_Pr = remainburst; SRC_Width = CAM_XSIZE - (2 * HorOfst); SRC_Height = CAM_YSIZE - (2 * VerOfst); DST_Width = LCD_XSIZE; DST_Height = LCD_YSIZE; CalcPrescaleParam(SRC_Width, DST_Width, &PreHorRatio, &H_Shift); CalcPrescaleParam(SRC_Height, DST_Height, &PreVerRatio, &V_Shift); CAMIF_PrInitStruct.SHfactor_Pr = 10 - H_Shift - V_Shift; CAMIF_PrInitStruct.PreHorRatio_Pr = PreHorRatio; CAMIF_PrInitStruct.PreVerRatio_Pr = PreVerRatio; CAMIF_PrInitStruct.PreDstWidth_Pr = SRC_Width / PreHorRatio; CAMIF_PrInitStruct.PreDstHeight_Pr = SRC_Height / PreVerRatio; MainHorRatio=(SRC_Width << 8) / (DST_Width << H_Shift); MainVerRatio=(SRC_Height << 8) / (DST_Height << V_Shift); CAMIF_PrInitStruct.MainHorRatio_Pr = MainHorRatio; CAMIF_PrInitStruct.MainVerRatio_Pr = MainVerRatio; CAMIF_PrInitStruct.ScaleUpDown_Pr = (SRC_Width <= DST_Width) ? ScaleUp : ScaleDown; CAMIF_PreviewInit(&CAMIF_PrInitStruct); /******************* codec scaler parameters **************************/ CAMIF_CoInitStruct.YStartAddr1 = (u32)CaptureY_Buf; CAMIF_CoInitStruct.YStartAddr2 = (u32)CaptureY_Buf; CAMIF_CoInitStruct.YStartAddr3 = (u32)CaptureY_Buf; CAMIF_CoInitStruct.YStartAddr4 = (u32)CaptureY_Buf; CAMIF_CoInitStruct.CbStartAddr1 = (u32)CaptureCb_Buf; CAMIF_CoInitStruct.CbStartAddr2 = (u32)CaptureCb_Buf; CAMIF_CoInitStruct.CbStartAddr3 = (u32)CaptureCb_Buf; CAMIF_CoInitStruct.CbStartAddr4 = (u32)CaptureCb_Buf; CAMIF_CoInitStruct.CrStartAddr1 = (u32)CaptureCr_Buf; CAMIF_CoInitStruct.CrStartAddr2 = (u32)CaptureCr_Buf; CAMIF_CoInitStruct.CrStartAddr3 = (u32)CaptureCr_Buf; CAMIF_CoInitStruct.CrStartAddr4 = (u32)CaptureCr_Buf; CAMIF_CoInitStruct.In422_Co = YCbCr_422; CAMIF_CoInitStruct.Out422_Co = YCbCr_422; CAMIF_CoInitStruct.FlipMd_Co = FlipMode_Xmirror; CAMIF_CoInitStruct.TargetHsize_Co = LCD_XSIZE; CAMIF_CoInitStruct.TargetVsize_Co = LCD_YSIZE; CAMIF_CoInitStruct.TargetArea_Co = LCD_XSIZE * LCD_YSIZE; CalcBurstSize(LCD_XSIZE, &mainburst, &remainburst); CAMIF_CoInitStruct.Yburst1_Co = mainburst; CAMIF_CoInitStruct.Yburst2_Co = remainburst; CalcBurstSize(LCD_YSIZE/2, &mainburst, &remainburst); CAMIF_CoInitStruct.Cburst1_Co = mainburst; CAMIF_CoInitStruct.Cburst2_Co = remainburst; SRC_Width = CAM_XSIZE - (2 * HorOfst); SRC_Height = CAM_YSIZE - (2 * VerOfst); DST_Width = LCD_XSIZE; DST_Height = LCD_YSIZE; CalcPrescaleParam(SRC_Width, DST_Width, &PreHorRatio, &H_Shift); CalcPrescaleParam(SRC_Height, DST_Height, &PreVerRatio, &V_Shift); CAMIF_CoInitStruct.SHfactor_Co = 10 - H_Shift - V_Shift; CAMIF_CoInitStruct.PreHorRatio_Co = PreHorRatio; CAMIF_CoInitStruct.PreVerRatio_Co = PreVerRatio; CAMIF_CoInitStruct.PreDstWidth_Co = SRC_Width / PreHorRatio; CAMIF_CoInitStruct.PreDstHeight_Co = SRC_Height / PreVerRatio; MainHorRatio=(SRC_Width << 8) / (DST_Width << H_Shift); MainVerRatio=(SRC_Height << 8) / (DST_Height << V_Shift); CAMIF_CoInitStruct.MainHorRatio_Co = MainHorRatio; CAMIF_CoInitStruct.MainVerRatio_Co = MainVerRatio; CAMIF_CoInitStruct.ScaleUpDown_Co = (SRC_Width <= DST_Width) ? ScaleUp : ScaleDown; CAMIF_CoInitStruct.ScalerBypass_Co = DISABLE; CAMIF_CodecInit(&CAMIF_CoInitStruct); }
CAMIF_Init函数,实现对全局参数寄存器的配置:
void CAMIF_Init(CAMIF_InitTypeDef *pInitStruct) { //SOURCE FORMAT REGISTER rCISRCFMT &= ~(0x1FFF << 0); rCISRCFMT |= (pInitStruct->SourceVsize << 0); rCISRCFMT &= ~(3 << 14); rCISRCFMT |= (pInitStruct->Order422 << 14); rCISRCFMT &= ~(0x1FFF << 16); rCISRCFMT |= (pInitStruct->SourceHsize << 16); rCISRCFMT &= ~(1 << 30); rCISRCFMT |= (pInitStruct->UVOffset << 30); rCISRCFMT &= ~(1 << 31); rCISRCFMT |= (pInitStruct->ITU601_656n << 31); //WINDOW OPTION REGISTER rCIWDOFST &= ~(0x7FF << 0); rCIWDOFST |= (pInitStruct->WinVerOfst << 0); rCIWDOFST &= ~(0x7FF << 16); rCIWDOFST |= (pInitStruct->WinHorOfst << 16); rCIWDOFST &= ~(1 << 31); rCIWDOFST |= (pInitStruct->WinOfsEn << 31); //GLOBAL CONTROL REGISTER rCIGCTRL &= ~(1 << 24); rCIGCTRL |= (pInitStruct->InvPolCAMVSYNC << 24); rCIGCTRL &= ~(1 << 25); rCIGCTRL |= (pInitStruct->InvPolCAMHREF << 25); rCIGCTRL &= ~(1 << 26); rCIGCTRL |= (pInitStruct->InvPolCAMPCLK << 26); rCIGCTRL &= ~(3 << 27); rCIGCTRL |= (pInitStruct->TestPattern << 27); rCIGCTRL |= (1 << 29); }
CAMIF_PreviewInit函数,实现对Preview参数寄存器的配置:
void CAMIF_PreviewInit(CAMIF_PreviewInitTypeDef *pPreInitStruct) { //RGB START ADDRESS REGISTER rCIPRCLRSA1 = pPreInitStruct->RGBStartAddr1; rCIPRCLRSA2 = pPreInitStruct->RGBStartAddr2; rCIPRCLRSA3 = pPreInitStruct->RGBStartAddr3; rCIPRCLRSA4 = pPreInitStruct->RGBStartAddr4; //PREVIEW TARGET FORMAT REGISTER rCIPRTRGFMT &= ~(0x1FFF << 0); rCIPRTRGFMT |= (pPreInitStruct->TargetVsize_Pr << 0); rCIPRTRGFMT &= ~(3 << 14); rCIPRTRGFMT |= (pPreInitStruct->FlipMd_Pr << 14); rCIPRTRGFMT &= ~(0x1FFF << 16); rCIPRTRGFMT |= (pPreInitStruct->TargetHsize_Pr << 16); //PREVIEW DMA CONTROL REGISTER rCIPRCTRL &= ~(1 << 2); rCIPRCTRL &= ~(0x1F << 14); rCIPRCTRL |= (pPreInitStruct->RGBburst2_Pr << 14); rCIPRCTRL &= ~(0x1F << 19); rCIPRCTRL |= (pPreInitStruct->RGBburst1_Pr << 19); //PREVIEW PRE-SCALER CONTROL REGISTER rCIPRSCPRERATIO &= ~(0x7F << 0); rCIPRSCPRERATIO |= (pPreInitStruct->PreVerRatio_Pr << 0); rCIPRSCPRERATIO &= ~(0x7F << 16); rCIPRSCPRERATIO |= (pPreInitStruct->PreHorRatio_Pr << 16); rCIPRSCPRERATIO &= ~(0xF << 28); rCIPRSCPRERATIO |= (pPreInitStruct->SHfactor_Pr << 28); rCIPRSCPREDST &= ~(0xFFF << 0); rCIPRSCPREDST |= (pPreInitStruct->PreDstHeight_Pr << 0); rCIPRSCPREDST &= ~(0xFFF << 16); rCIPRSCPREDST |= (pPreInitStruct->PreDstWidth_Pr << 16); //PREVIEW MAIN-SCALER CONTROL REGISTER rCIPRSCCTRL &= ~(0x1FF << 0); rCIPRSCCTRL |= (pPreInitStruct->MainVerRatio_Pr << 0); rCIPRSCCTRL &= ~(1 << 15); rCIPRSCCTRL &= ~(0x1FF << 16); rCIPRSCCTRL |= (pPreInitStruct->MainHorRatio_Pr << 16); rCIPRSCCTRL &= ~(3 << 28); rCIPRSCCTRL |= (pPreInitStruct->ScaleUpDown_Pr << 28); rCIPRSCCTRL &= ~(1 << 30); rCIPRSCCTRL |= (pPreInitStruct->RGBformat_Pr << 30); rCIPRSCCTRL |= (1 << 31); //PREVIEW DMA TARGET AREA REGISTER rCIPRTAREA = pPreInitStruct->TargetArea_Pr; }
CAMIF_CodecInit函数,实现对Codec参数寄存器的配置:
void CAMIF_CodecInit(CAMIF_CodecInitTypeDef *pCoInitStruct) { //Y START ADDRESS REGISTER rCICOYSA1 = (u32)pCoInitStruct->YStartAddr1; rCICOYSA2 = (u32)pCoInitStruct->YStartAddr2; rCICOYSA3 = (u32)pCoInitStruct->YStartAddr3; rCICOYSA4 = (u32)pCoInitStruct->YStartAddr4; //CB START ADDRESS REGISTER rCICOCBSA1 = (u32)pCoInitStruct->CbStartAddr1; rCICOCBSA2 = (u32)pCoInitStruct->CbStartAddr2; rCICOCBSA3 = (u32)pCoInitStruct->CbStartAddr3; rCICOCBSA4 = (u32)pCoInitStruct->CbStartAddr4; //CR START ADDRESS REGISTER rCICOCRSA1 = (u32)pCoInitStruct->CrStartAddr1; rCICOCRSA2 = (u32)pCoInitStruct->CrStartAddr2; rCICOCRSA3 = (u32)pCoInitStruct->CrStartAddr3; rCICOCRSA4 = (u32)pCoInitStruct->CrStartAddr4; //CODEC TARGET FORMAT REGISTER rCICOTRGFMT &= ~(0x1FFF << 0); rCICOTRGFMT |= (pCoInitStruct->TargetVsize_Co << 0); rCICOTRGFMT &= ~(3 << 14); rCICOTRGFMT |= (pCoInitStruct->FlipMd_Co << 14); rCICOTRGFMT &= ~(0x1FFF << 16); rCICOTRGFMT |= (pCoInitStruct->TargetHsize_Co << 16); rCICOTRGFMT &= ~(1 << 30); rCICOTRGFMT |= (pCoInitStruct->Out422_Co << 30); rCICOTRGFMT &= ~(1 << 31); rCICOTRGFMT |= (pCoInitStruct->In422_Co << 31); //CODEC DMA CONTROL REGISTER rCICOCTRL &= ~(1 << 2); rCICOCTRL &= ~(0x1F << 4); rCICOCTRL |= (pCoInitStruct->Cburst2_Co << 4); rCICOCTRL &= ~(0x1F << 9); rCICOCTRL |= (pCoInitStruct->Cburst1_Co << 9); rCICOCTRL &= ~(0x1F << 14); rCICOCTRL |= (pCoInitStruct->Yburst2_Co << 14); rCICOCTRL &= ~(0x1F << 19); rCICOCTRL |= (pCoInitStruct->Yburst1_Co << 19); //CODEC PRE-SCALER CONTROL REGISTER rCICOSCPRERATIO &= ~(0x7F << 0); rCICOSCPRERATIO |= (pCoInitStruct->PreVerRatio_Co << 0); rCICOSCPRERATIO &= ~(0x7F << 16); rCICOSCPRERATIO |= (pCoInitStruct->PreHorRatio_Co << 16); rCICOSCPRERATIO &= ~(0xF << 28); rCICOSCPRERATIO |= (pCoInitStruct->SHfactor_Co << 28); rCICOSCPREDST &= ~(0xFFF << 0); rCICOSCPREDST |= (pCoInitStruct->PreDstHeight_Co << 0); rCICOSCPREDST &= ~(0xFFF << 16); rCICOSCPREDST |= (pCoInitStruct->PreDstWidth_Co << 16); //CODEC MAIN-SCALER CONTROL REGISTER rCICOSCCTRL &= ~(0x1FF << 0); rCICOSCCTRL |= (pCoInitStruct->MainVerRatio_Co << 0); rCICOSCCTRL &= ~(1 << 15); rCICOSCCTRL &= ~(0x1FF << 16); rCICOSCCTRL |= (pCoInitStruct->MainHorRatio_Co << 16); rCICOSCCTRL &= ~(3 << 29); rCICOSCCTRL |= (pCoInitStruct->ScaleUpDown_Co << 29); rCICOSCCTRL &= ~(1 << 31); rCICOSCCTRL |= (pCoInitStruct->ScalerBypass_Co << 31); //CODEC DMA TARGET AREA REGISTER rCICOTAREA = pCoInitStruct->TargetArea_Co; }
开启Preview:
void CAMIF_StartPreview(void) { rCIPRSCCTRL |= (1 << 15); rCIIMGCPT |= (1 << 29); rCIIMGCPT |= (1 << 31); }
开启Codec:
void CAMIF_StartCapture(void) { rCICOSCCTRL |= (1 << 15); rCIIMGCPT |= (1 << 30); rCIIMGCPT |= (1 << 31); }
Camera sensor模块初始化时调用顺序:
void OV9650_Init(void) { CAMIF_Clock_Init(); CAMIF_GPIO_Config(); CAMIF_ResetIF(); CAMIF_ResetMoudle(); CAMIF_Config(0, 0); SCCB_Init(); OV9650_CheckPID(); OV9650_Config(); CAMIF_StartPreview(); CAMIF_StartCapture(); }
执行到这里,你的LCD上就能显示预览的图像了。关于更详细的代码,请下载源码工程自行研究。
时间: 2024-10-15 14:39:33