/** ****************************************************************************** * @file ov5640.c * @author MCD Application Team * @brief This file provides the OV5640 camera driver ****************************************************************************** * @attention * *

© Copyright (c) 2018 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "ov5640.h" /** @addtogroup BSP * @{ */ /** @addtogroup Components * @{ */ /** @addtogroup OV5640 * @brief This file provides a set of functions needed to drive the * OV5640 Camera module. * @{ */ /** @defgroup OV5640_Private_TypesDefinitions * @{ */ /** * @} */ /** @defgroup OV5640_Private_Variables * @{ */ OV5640_CAMERA_Drv_t OV5640_CAMERA_Driver = { OV5640_Init, OV5640_DeInit, OV5640_ReadID, OV5640_GetCapabilities, OV5640_SetLightMode, OV5640_SetColorEffect, OV5640_SetBrightness, OV5640_SetSaturation, OV5640_SetContrast, OV5640_SetHueDegree, OV5640_MirrorFlipConfig, OV5640_ZoomConfig, OV5640_SetResolution, OV5640_GetResolution, OV5640_SetPixelFormat, OV5640_GetPixelFormat, OV5640_NightModeConfig }; /** * @} */ /** @defgroup OV5640_Private_Functions_Prototypes Private Functions Prototypes * @{ */ static int32_t OV5640_ReadRegWrap(void *handle, uint16_t Reg, uint8_t *Data, uint16_t Length); static int32_t OV5640_WriteRegWrap(void *handle, uint16_t Reg, uint8_t *Data, uint16_t Length); static int32_t OV5640_Delay(OV5640_Object_t *pObj, uint32_t Delay); /** * @} */ /** @defgroup OV5640_Exported_Functions OV5640 Exported Functions * @{ */ /** * @brief Register component IO bus * @param Component object pointer * @retval Component status */ int32_t OV5640_RegisterBusIO(OV5640_Object_t *pObj, OV5640_IO_t *pIO) { int32_t ret; if (pObj == NULL) { ret = OV5640_ERROR; } else { pObj->IO.Init = pIO->Init; pObj->IO.DeInit = pIO->DeInit; pObj->IO.Address = pIO->Address; pObj->IO.WriteReg = pIO->WriteReg; pObj->IO.ReadReg = pIO->ReadReg; pObj->IO.GetTick = pIO->GetTick; pObj->Ctx.ReadReg = OV5640_ReadRegWrap; pObj->Ctx.WriteReg = OV5640_WriteRegWrap; pObj->Ctx.handle = pObj; if (pObj->IO.Init != NULL) { ret = pObj->IO.Init(); } else { ret = OV5640_ERROR; } } return ret; } /** * @brief Initializes the OV5640 CAMERA component. * @param pObj pointer to component object * @param Resolution Camera resolution * @param PixelFormat pixel format to be configured * @retval Component status */ int32_t OV5640_Init(OV5640_Object_t *pObj, uint32_t Resolution, uint32_t PixelFormat) { uint32_t index; int32_t ret = OV5640_OK; /* Initialization sequence for OV5640 */ static const uint16_t OV5640_Common[][2] = { {OV5640_SCCB_SYSTEM_CTRL1, 0x11}, {OV5640_SYSTEM_CTROL0, 0x82}, {OV5640_SCCB_SYSTEM_CTRL1, 0x03}, {OV5640_PAD_OUTPUT_ENABLE01, 0xFF}, {OV5640_PAD_OUTPUT_ENABLE02, 0xf3}, {OV5640_SC_PLL_CONTRL0, 0x18}, {OV5640_SYSTEM_CTROL0, 0x02}, {OV5640_SC_PLL_CONTRL1, 0x41}, {OV5640_SC_PLL_CONTRL2, 0x30}, {OV5640_SC_PLL_CONTRL3, 0x13}, {OV5640_SYSTEM_ROOT_DIVIDER, 0x01}, {0x3630, 0x36}, {0x3631, 0x0e}, {0x3632, 0xe2}, {0x3633, 0x12}, {0x3621, 0xe0}, {0x3704, 0xa0}, {0x3703, 0x5a}, {0x3715, 0x78}, {0x3717, 0x01}, {0x370b, 0x60}, {0x3705, 0x1a}, {0x3905, 0x02}, {0x3906, 0x10}, {0x3901, 0x0a}, {0x3731, 0x12}, {0x3600, 0x08}, {0x3601, 0x33}, {0x302d, 0x60}, {0x3620, 0x52}, {0x371b, 0x20}, {0x471c, 0x50}, {OV5640_AEC_CTRL13, 0x43}, {OV5640_AEC_GAIN_CEILING_HIGH, 0x00}, {OV5640_AEC_GAIN_CEILING_LOW, 0xf8}, {0x3635, 0x13}, {0x3636, 0x03}, {0x3634, 0x40}, {0x3622, 0x01}, {OV5640_5060HZ_CTRL01, 0x34}, {OV5640_5060HZ_CTRL04, 0x28}, {OV5640_5060HZ_CTRL05, 0x98}, {OV5640_LIGHTMETER1_TH_HIGH, 0x00}, {OV5640_LIGHTMETER1_TH_LOW, 0x00}, {OV5640_LIGHTMETER2_TH_HIGH, 0x01}, {OV5640_LIGHTMETER2_TH_LOW, 0x2c}, {OV5640_SAMPLE_NUMBER_HIGH, 0x9c}, {OV5640_SAMPLE_NUMBER_LOW, 0x40}, {OV5640_TIMING_TC_REG20, 0x06}, {OV5640_TIMING_TC_REG21, 0x00}, {OV5640_TIMING_X_INC, 0x31}, {OV5640_TIMING_Y_INC, 0x31}, {OV5640_TIMING_HS_HIGH, 0x00}, {OV5640_TIMING_HS_LOW, 0x00}, {OV5640_TIMING_VS_HIGH, 0x00}, {OV5640_TIMING_VS_LOW, 0x04}, {OV5640_TIMING_HW_HIGH, 0x0a}, {OV5640_TIMING_HW_LOW, 0x3f}, {OV5640_TIMING_VH_HIGH, 0x07}, {OV5640_TIMING_VH_LOW, 0x9b}, {OV5640_TIMING_DVPHO_HIGH, 0x03}, {OV5640_TIMING_DVPHO_LOW, 0x20}, {OV5640_TIMING_DVPVO_HIGH, 0x02}, {OV5640_TIMING_DVPVO_LOW, 0x58}, {OV5640_TIMING_HTS_HIGH, 0x06}, {OV5640_TIMING_HTS_LOW, 0x40}, {OV5640_TIMING_VTS_HIGH, 0x03}, {OV5640_TIMING_VTS_LOW, 0xe8}, {OV5640_TIMING_HOFFSET_HIGH, 0x00}, {OV5640_TIMING_HOFFSET_LOW, 0x10}, {OV5640_TIMING_VOFFSET_HIGH, 0x00}, {OV5640_TIMING_VOFFSET_LOW, 0x06}, {0x3618, 0x00}, {0x3612, 0x29}, {0x3708, 0x64}, {0x3709, 0x52}, {0x370c, 0x03}, {OV5640_AEC_CTRL02, 0x03}, {OV5640_AEC_CTRL03, 0xd8}, {OV5640_AEC_B50_STEP_HIGH, 0x01}, {OV5640_AEC_B50_STEP_LOW, 0x27}, {OV5640_AEC_B60_STEP_HIGH, 0x00}, {OV5640_AEC_B60_STEP_LOW, 0xf6}, {OV5640_AEC_CTRL0E, 0x03}, {OV5640_AEC_CTRL0D, 0x04}, {OV5640_AEC_MAX_EXPO_HIGH, 0x03}, {OV5640_AEC_MAX_EXPO_LOW, 0xd8}, {OV5640_BLC_CTRL01, 0x02}, {OV5640_BLC_CTRL04, 0x02}, {OV5640_SYSREM_RESET00, 0x00}, {OV5640_SYSREM_RESET02, 0x1c}, {OV5640_CLOCK_ENABLE00, 0xff}, {OV5640_CLOCK_ENABLE02, 0xc3}, {OV5640_MIPI_CONTROL00, 0x58}, {0x302e, 0x00}, {OV5640_POLARITY_CTRL, 0x22}, {OV5640_FORMAT_CTRL00, 0x6F}, {OV5640_FORMAT_MUX_CTRL, 0x01}, {OV5640_JPG_MODE_SELECT, 0x03}, {OV5640_JPEG_CTRL07, 0x04}, {0x440e, 0x00}, {0x460b, 0x35}, {0x460c, 0x23}, {OV5640_PCLK_PERIOD, 0x22}, {0x3824, 0x02}, {OV5640_ISP_CONTROL00, 0xa7}, {OV5640_ISP_CONTROL01, 0xa3}, {OV5640_AWB_CTRL00, 0xff}, {OV5640_AWB_CTRL01, 0xf2}, {OV5640_AWB_CTRL02, 0x00}, {OV5640_AWB_CTRL03, 0x14}, {OV5640_AWB_CTRL04, 0x25}, {OV5640_AWB_CTRL05, 0x24}, {OV5640_AWB_CTRL06, 0x09}, {OV5640_AWB_CTRL07, 0x09}, {OV5640_AWB_CTRL08, 0x09}, {OV5640_AWB_CTRL09, 0x75}, {OV5640_AWB_CTRL10, 0x54}, {OV5640_AWB_CTRL11, 0xe0}, {OV5640_AWB_CTRL12, 0xb2}, {OV5640_AWB_CTRL13, 0x42}, {OV5640_AWB_CTRL14, 0x3d}, {OV5640_AWB_CTRL15, 0x56}, {OV5640_AWB_CTRL16, 0x46}, {OV5640_AWB_CTRL17, 0xf8}, {OV5640_AWB_CTRL18, 0x04}, {OV5640_AWB_CTRL19, 0x70}, {OV5640_AWB_CTRL20, 0xf0}, {OV5640_AWB_CTRL21, 0xf0}, {OV5640_AWB_CTRL22, 0x03}, {OV5640_AWB_CTRL23, 0x01}, {OV5640_AWB_CTRL24, 0x04}, {OV5640_AWB_CTRL25, 0x12}, {OV5640_AWB_CTRL26, 0x04}, {OV5640_AWB_CTRL27, 0x00}, {OV5640_AWB_CTRL28, 0x06}, {OV5640_AWB_CTRL29, 0x82}, {OV5640_AWB_CTRL30, 0x38}, {OV5640_CMX1, 0x1e}, {OV5640_CMX2, 0x5b}, {OV5640_CMX3, 0x08}, {OV5640_CMX4, 0x0a}, {OV5640_CMX5, 0x7e}, {OV5640_CMX6, 0x88}, {OV5640_CMX7, 0x7c}, {OV5640_CMX8, 0x6c}, {OV5640_CMX9, 0x10}, {OV5640_CMXSIGN_HIGH, 0x01}, {OV5640_CMXSIGN_LOW, 0x98}, {OV5640_CIP_SHARPENMT_TH1, 0x08}, {OV5640_CIP_SHARPENMT_TH2, 0x30}, {OV5640_CIP_SHARPENMT_OFFSET1, 0x10}, {OV5640_CIP_SHARPENMT_OFFSET2, 0x00}, {OV5640_CIP_DNS_TH1, 0x08}, {OV5640_CIP_DNS_TH2, 0x30}, {OV5640_CIP_DNS_OFFSET1, 0x08}, {OV5640_CIP_DNS_OFFSET2, 0x16}, {OV5640_CIP_CTRL, 0x08}, {OV5640_CIP_SHARPENTH_TH1, 0x30}, {OV5640_CIP_SHARPENTH_TH2, 0x04}, {OV5640_CIP_SHARPENTH_OFFSET1, 0x06}, {OV5640_GAMMA_CTRL00, 0x01}, {OV5640_GAMMA_YST00, 0x08}, {OV5640_GAMMA_YST01, 0x14}, {OV5640_GAMMA_YST02, 0x28}, {OV5640_GAMMA_YST03, 0x51}, {OV5640_GAMMA_YST04, 0x65}, {OV5640_GAMMA_YST05, 0x71}, {OV5640_GAMMA_YST06, 0x7d}, {OV5640_GAMMA_YST07, 0x87}, {OV5640_GAMMA_YST08, 0x91}, {OV5640_GAMMA_YST09, 0x9a}, {OV5640_GAMMA_YST0A, 0xaa}, {OV5640_GAMMA_YST0B, 0xb8}, {OV5640_GAMMA_YST0C, 0xcd}, {OV5640_GAMMA_YST0D, 0xdd}, {OV5640_GAMMA_YST0E, 0xea}, {OV5640_GAMMA_YST0F, 0x1d}, {OV5640_SDE_CTRL0, 0x02}, {OV5640_SDE_CTRL3, 0x40}, {OV5640_SDE_CTRL4, 0x10}, {OV5640_SDE_CTRL9, 0x10}, {OV5640_SDE_CTRL10, 0x00}, {OV5640_SDE_CTRL11, 0xf8}, {OV5640_GMTRX00, 0x23}, {OV5640_GMTRX01, 0x14}, {OV5640_GMTRX02, 0x0f}, {OV5640_GMTRX03, 0x0f}, {OV5640_GMTRX04, 0x12}, {OV5640_GMTRX05, 0x26}, {OV5640_GMTRX10, 0x0c}, {OV5640_GMTRX11, 0x08}, {OV5640_GMTRX12, 0x05}, {OV5640_GMTRX13, 0x05}, {OV5640_GMTRX14, 0x08}, {OV5640_GMTRX15, 0x0d}, {OV5640_GMTRX20, 0x08}, {OV5640_GMTRX21, 0x03}, {OV5640_GMTRX22, 0x00}, {OV5640_GMTRX23, 0x00}, {OV5640_GMTRX24, 0x03}, {OV5640_GMTRX25, 0x09}, {OV5640_GMTRX30, 0x07}, {OV5640_GMTRX31, 0x03}, {OV5640_GMTRX32, 0x00}, {OV5640_GMTRX33, 0x01}, {OV5640_GMTRX34, 0x03}, {OV5640_GMTRX35, 0x08}, {OV5640_GMTRX40, 0x0d}, {OV5640_GMTRX41, 0x08}, {OV5640_GMTRX42, 0x05}, {OV5640_GMTRX43, 0x06}, {OV5640_GMTRX44, 0x08}, {OV5640_GMTRX45, 0x0e}, {OV5640_GMTRX50, 0x29}, {OV5640_GMTRX51, 0x17}, {OV5640_GMTRX52, 0x11}, {OV5640_GMTRX53, 0x11}, {OV5640_GMTRX54, 0x15}, {OV5640_GMTRX55, 0x28}, {OV5640_BRMATRX00, 0x46}, {OV5640_BRMATRX01, 0x26}, {OV5640_BRMATRX02, 0x08}, {OV5640_BRMATRX03, 0x26}, {OV5640_BRMATRX04, 0x64}, {OV5640_BRMATRX05, 0x26}, {OV5640_BRMATRX06, 0x24}, {OV5640_BRMATRX07, 0x22}, {OV5640_BRMATRX08, 0x24}, {OV5640_BRMATRX09, 0x24}, {OV5640_BRMATRX20, 0x06}, {OV5640_BRMATRX21, 0x22}, {OV5640_BRMATRX22, 0x40}, {OV5640_BRMATRX23, 0x42}, {OV5640_BRMATRX24, 0x24}, {OV5640_BRMATRX30, 0x26}, {OV5640_BRMATRX31, 0x24}, {OV5640_BRMATRX32, 0x22}, {OV5640_BRMATRX33, 0x22}, {OV5640_BRMATRX34, 0x26}, {OV5640_BRMATRX40, 0x44}, {OV5640_BRMATRX41, 0x24}, {OV5640_BRMATRX42, 0x26}, {OV5640_BRMATRX43, 0x28}, {OV5640_BRMATRX44, 0x42}, {OV5640_LENC_BR_OFFSET, 0xce}, {0x5025, 0x00}, {OV5640_AEC_CTRL0F, 0x30}, {OV5640_AEC_CTRL10, 0x28}, {OV5640_AEC_CTRL1B, 0x30}, {OV5640_AEC_CTRL1E, 0x26}, {OV5640_AEC_CTRL11, 0x60}, {OV5640_AEC_CTRL1F, 0x14}, {OV5640_SYSTEM_CTROL0, 0x02}, }; uint8_t tmp; if (pObj->IsInitialized == 0U) { /* Check if resolution is supported */ if ((Resolution > OV5640_R800x480) || ((PixelFormat != OV5640_RGB565) && (PixelFormat != OV5640_YUV422) && (PixelFormat != OV5640_RGB888) && (PixelFormat != OV5640_Y8) && (PixelFormat != OV5640_JPEG))) { ret = OV5640_ERROR; } else { /* Set common parameters for all resolutions */ for (index = 0; index < (sizeof(OV5640_Common) / 4U) ; index++) { if (ret != OV5640_ERROR) { tmp = (uint8_t)OV5640_Common[index][1]; if (ov5640_write_reg(&pObj->Ctx, OV5640_Common[index][0], &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } } if (ret == OV5640_OK) { /* Set specific parameters for each resolution */ if (OV5640_SetResolution(pObj, Resolution) != OV5640_OK) { ret = OV5640_ERROR; }/* Set specific parameters for each pixel format */ else if (OV5640_SetPixelFormat(pObj, PixelFormat) != OV5640_OK) { ret = OV5640_ERROR; }/* Set PixelClock, Href and VSync Polarity */ else if (OV5640_SetPolarities(pObj, OV5640_POLARITY_PCLK_HIGH, OV5640_POLARITY_HREF_HIGH, OV5640_POLARITY_VSYNC_HIGH) != OV5640_OK) { ret = OV5640_ERROR; } else { pObj->IsInitialized = 1U; } } } } return ret; } /** * @brief De-initializes the camera sensor. * @param pObj pointer to component object * @retval Component status */ int32_t OV5640_DeInit(OV5640_Object_t *pObj) { if (pObj->IsInitialized == 1U) { /* De-initialize camera sensor interface */ pObj->IsInitialized = 0U; } return OV5640_OK; } /** * @brief Set OV5640 camera Pixel Format. * @param pObj pointer to component object * @param PixelFormat pixel format to be configured * @retval Component status */ int32_t OV5640_SetPixelFormat(OV5640_Object_t *pObj, uint32_t PixelFormat) { int32_t ret = OV5640_OK; uint32_t index; uint8_t tmp; /* Initialization sequence for RGB565 pixel format */ static const uint16_t OV5640_PF_RGB565[][2] = { /* SET PIXEL FORMAT: RGB565 */ {OV5640_FORMAT_CTRL00, 0x6F}, {OV5640_FORMAT_MUX_CTRL, 0x01}, }; /* Initialization sequence for YUV422 pixel format */ static const uint16_t OV5640_PF_YUV422[][2] = { /* SET PIXEL FORMAT: YUV422 */ {OV5640_FORMAT_CTRL00, 0x30}, {OV5640_FORMAT_MUX_CTRL, 0x00}, }; /* Initialization sequence for RGB888 pixel format */ static const uint16_t OV5640_PF_RGB888[][2] = { /* SET PIXEL FORMAT: RGB888 (RGBRGB)*/ {OV5640_FORMAT_CTRL00, 0x23}, {OV5640_FORMAT_MUX_CTRL, 0x01}, }; /* Initialization sequence for Monochrome 8bits pixel format */ static const uint16_t OV5640_PF_Y8[][2] = { /* SET PIXEL FORMAT: Y 8bits */ {OV5640_FORMAT_CTRL00, 0x10}, {OV5640_FORMAT_MUX_CTRL, 0x00}, }; /* Initialization sequence for JPEG format */ static const uint16_t OV5640_PF_JPEG[][2] = { /* SET PIXEL FORMAT: JPEG */ {OV5640_FORMAT_CTRL00, 0x30}, {OV5640_FORMAT_MUX_CTRL, 0x00}, }; /* Check if PixelFormat is supported */ if ((PixelFormat != OV5640_RGB565) && (PixelFormat != OV5640_YUV422) && (PixelFormat != OV5640_RGB888) && (PixelFormat != OV5640_Y8) && (PixelFormat != OV5640_JPEG)) { /* Pixel format not supported */ ret = OV5640_ERROR; } else { /* Set specific parameters for each PixelFormat */ switch (PixelFormat) { case OV5640_YUV422: for (index = 0; index < (sizeof(OV5640_PF_YUV422) / 4U); index++) { if (ret != OV5640_ERROR) { tmp = (uint8_t)OV5640_PF_YUV422[index][1]; if (ov5640_write_reg(&pObj->Ctx, OV5640_PF_YUV422[index][0], &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { (void)OV5640_Delay(pObj, 1); } } } break; case OV5640_RGB888: for (index = 0; index < (sizeof(OV5640_PF_RGB888) / 4U); index++) { if (ret != OV5640_ERROR) { tmp = (uint8_t)OV5640_PF_RGB888[index][1]; if (ov5640_write_reg(&pObj->Ctx, OV5640_PF_RGB888[index][0], &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { (void)OV5640_Delay(pObj, 1); } } } break; case OV5640_Y8: for (index = 0; index < (sizeof(OV5640_PF_Y8) / 4U); index++) { if (ret != OV5640_ERROR) { tmp = (uint8_t)OV5640_PF_Y8[index][1]; if (ov5640_write_reg(&pObj->Ctx, OV5640_PF_Y8[index][0], &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { (void)OV5640_Delay(pObj, 1); } } } break; case OV5640_JPEG: for (index = 0; index < (sizeof(OV5640_PF_JPEG) / 4U); index++) { if (ret != OV5640_ERROR) { tmp = (uint8_t)OV5640_PF_JPEG[index][1]; if (ov5640_write_reg(&pObj->Ctx, OV5640_PF_JPEG[index][0], &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { (void)OV5640_Delay(pObj, 1); } } } break; case OV5640_RGB565: default: for (index = 0; index < (sizeof(OV5640_PF_RGB565) / 4U); index++) { if (ret != OV5640_ERROR) { tmp = (uint8_t)OV5640_PF_RGB565[index][1]; if (ov5640_write_reg(&pObj->Ctx, OV5640_PF_RGB565[index][0], &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { (void)OV5640_Delay(pObj, 1); } } } break; } if (PixelFormat == OV5640_JPEG) { if (ov5640_read_reg(&pObj->Ctx, OV5640_TIMING_TC_REG21, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { tmp |= (1 << 5); if (ov5640_write_reg(&pObj->Ctx, OV5640_TIMING_TC_REG21, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { if (ov5640_read_reg(&pObj->Ctx, OV5640_SYSREM_RESET02, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { tmp &= ~((1 << 4) | (1 << 3) | (1 << 2)); if (ov5640_write_reg(&pObj->Ctx, OV5640_SYSREM_RESET02, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { if (ov5640_read_reg(&pObj->Ctx, OV5640_CLOCK_ENABLE02, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { tmp |= ((1 << 5) | (1 << 3)); if (ov5640_write_reg(&pObj->Ctx, OV5640_CLOCK_ENABLE02, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } } } } } } } return ret; } /** * @brief Set OV5640 camera Pixel Format. * @param pObj pointer to component object * @param PixelFormat pixel format to be configured * @retval Component status */ int32_t OV5640_GetPixelFormat(OV5640_Object_t *pObj, uint32_t *PixelFormat) { (void)(pObj); (void)(PixelFormat); return OV5640_ERROR; } /** * @brief Get OV5640 camera resolution. * @param pObj pointer to component object * @param Resolution Camera resolution * @retval Component status */ int32_t OV5640_SetResolution(OV5640_Object_t *pObj, uint32_t Resolution) { int32_t ret = OV5640_OK; uint32_t index; uint8_t tmp; /* Initialization sequence for WVGA resolution (800x480)*/ static const uint16_t OV5640_WVGA[][2] = { {OV5640_TIMING_DVPHO_HIGH, 0x03}, {OV5640_TIMING_DVPHO_LOW, 0x20}, {OV5640_TIMING_DVPVO_HIGH, 0x01}, {OV5640_TIMING_DVPVO_LOW, 0xE0}, }; /* Initialization sequence for VGA resolution (640x480)*/ static const uint16_t OV5640_VGA[][2] = { {OV5640_TIMING_DVPHO_HIGH, 0x02}, {OV5640_TIMING_DVPHO_LOW, 0x80}, {OV5640_TIMING_DVPVO_HIGH, 0x01}, {OV5640_TIMING_DVPVO_LOW, 0xE0}, }; /* Initialization sequence for 480x272 resolution */ static const uint16_t OV5640_480x272[][2] = { {OV5640_TIMING_DVPHO_HIGH, 0x01}, {OV5640_TIMING_DVPHO_LOW, 0xE0}, {OV5640_TIMING_DVPVO_HIGH, 0x01}, {OV5640_TIMING_DVPVO_LOW, 0x10}, }; /* Initialization sequence for QVGA resolution (320x240) */ static const uint16_t OV5640_QVGA[][2] = { {OV5640_TIMING_DVPHO_HIGH, 0x01}, {OV5640_TIMING_DVPHO_LOW, 0x40}, {OV5640_TIMING_DVPVO_HIGH, 0x00}, {OV5640_TIMING_DVPVO_LOW, 0xF0}, }; /* Initialization sequence for QQVGA resolution (160x120) */ static const uint16_t OV5640_QQVGA[][2] = { {OV5640_TIMING_DVPHO_HIGH, 0x00}, {OV5640_TIMING_DVPHO_LOW, 0xA0}, {OV5640_TIMING_DVPVO_HIGH, 0x00}, {OV5640_TIMING_DVPVO_LOW, 0x78}, }; /* Check if resolution is supported */ if (Resolution > OV5640_R800x480) { ret = OV5640_ERROR; } else { /* Initialize OV5640 */ switch (Resolution) { case OV5640_R160x120: for (index = 0; index < (sizeof(OV5640_QQVGA) / 4U); index++) { if (ret != OV5640_ERROR) { tmp = (uint8_t)OV5640_QQVGA[index][1]; if (ov5640_write_reg(&pObj->Ctx, OV5640_QQVGA[index][0], &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } } break; case OV5640_R320x240: for (index = 0; index < (sizeof(OV5640_QVGA) / 4U); index++) { if (ret != OV5640_ERROR) { tmp = (uint8_t)OV5640_QVGA[index][1]; if (ov5640_write_reg(&pObj->Ctx, OV5640_QVGA[index][0], &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } } break; case OV5640_R480x272: for (index = 0; index < (sizeof(OV5640_480x272) / 4U); index++) { if (ret != OV5640_ERROR) { tmp = (uint8_t)OV5640_480x272[index][1]; if (ov5640_write_reg(&pObj->Ctx, OV5640_480x272[index][0], &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } } break; case OV5640_R640x480: for (index = 0; index < (sizeof(OV5640_VGA) / 4U); index++) { if (ret != OV5640_ERROR) { tmp = (uint8_t)OV5640_VGA[index][1]; if (ov5640_write_reg(&pObj->Ctx, OV5640_VGA[index][0], &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } } break; case OV5640_R800x480: for (index = 0; index < (sizeof(OV5640_WVGA) / 4U); index++) { if (ret != OV5640_ERROR) { tmp = (uint8_t)OV5640_WVGA[index][1]; if (ov5640_write_reg(&pObj->Ctx, OV5640_WVGA[index][0], &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } } break; default: ret = OV5640_ERROR; break; } } return ret; } /** * @brief Get OV5640 camera resolution. * @param pObj pointer to component object * @param Resolution Camera resolution * @retval Component status */ int32_t OV5640_GetResolution(OV5640_Object_t *pObj, uint32_t *Resolution) { int32_t ret; uint16_t x_size; uint16_t y_size; uint8_t tmp; if (ov5640_read_reg(&pObj->Ctx, OV5640_TIMING_DVPHO_HIGH, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { x_size = (uint16_t)tmp << 8U; if (ov5640_read_reg(&pObj->Ctx, OV5640_TIMING_DVPHO_LOW, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { x_size |= tmp; if (ov5640_read_reg(&pObj->Ctx, OV5640_TIMING_DVPVO_HIGH, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { y_size = (uint16_t)tmp << 8U; if (ov5640_read_reg(&pObj->Ctx, OV5640_TIMING_DVPVO_LOW, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { y_size |= tmp; if ((x_size == 800U) && (y_size == 480U)) { *Resolution = OV5640_R800x480; ret = OV5640_OK; } else if ((x_size == 640U) && (y_size == 480U)) { *Resolution = OV5640_R640x480; ret = OV5640_OK; } else if ((x_size == 480U) && (y_size == 272U)) { *Resolution = OV5640_R480x272; ret = OV5640_OK; } else if ((x_size == 320U) && (y_size == 240U)) { *Resolution = OV5640_R320x240; ret = OV5640_OK; } else if ((x_size == 160U) && (y_size == 120U)) { *Resolution = OV5640_R160x120; ret = OV5640_OK; } else { ret = OV5640_ERROR; } } } } } return ret; } /** * @brief Set OV5640 camera PCLK, HREF and VSYNC Polarities * @param pObj pointer to component object * @param PclkPolarity Polarity of the PixelClock * @param HrefPolarity Polarity of the Href * @param VsyncPolarity Polarity of the Vsync * @retval Component status */ int32_t OV5640_SetPolarities(OV5640_Object_t *pObj, uint32_t PclkPolarity, uint32_t HrefPolarity, uint32_t VsyncPolarity) { uint8_t tmp; int32_t ret = OV5640_OK; if ((pObj == NULL) || ((PclkPolarity != OV5640_POLARITY_PCLK_LOW) && (PclkPolarity != OV5640_POLARITY_PCLK_HIGH)) || ((HrefPolarity != OV5640_POLARITY_HREF_LOW) && (HrefPolarity != OV5640_POLARITY_HREF_HIGH)) || ((VsyncPolarity != OV5640_POLARITY_VSYNC_LOW) && (VsyncPolarity != OV5640_POLARITY_VSYNC_HIGH))) { ret = OV5640_ERROR; } else { tmp = (uint8_t)(PclkPolarity << 5U) | (HrefPolarity << 1U) | VsyncPolarity; if (ov5640_write_reg(&pObj->Ctx, OV5640_POLARITY_CTRL, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } return ret; } /** * @brief get OV5640 camera PCLK, HREF and VSYNC Polarities * @param pObj pointer to component object * @param PclkPolarity Polarity of the PixelClock * @param HrefPolarity Polarity of the Href * @param VsyncPolarity Polarity of the Vsync * @retval Component status */ int32_t OV5640_GetPolarities(OV5640_Object_t *pObj, uint32_t *PclkPolarity, uint32_t *HrefPolarity, uint32_t *VsyncPolarity) { uint8_t tmp; int32_t ret = OV5640_OK; if ((pObj == NULL) || (PclkPolarity == NULL) || (HrefPolarity == NULL) || (VsyncPolarity == NULL)) { ret = OV5640_ERROR; } else if (ov5640_read_reg(&pObj->Ctx, OV5640_POLARITY_CTRL, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { *PclkPolarity = (tmp >> 5U) & 0x01U; *HrefPolarity = (tmp >> 1U) & 0x01U; *VsyncPolarity = tmp & 0x01; } return ret; } /** * @brief Read the OV5640 Camera identity. * @param pObj pointer to component object * @param Id pointer to component ID * @retval Component status */ int32_t OV5640_ReadID(OV5640_Object_t *pObj, uint32_t *Id) { int32_t ret; uint8_t tmp; /* Initialize I2C */ pObj->IO.Init(); /* Prepare the camera to be configured */ tmp = 0x80; if (ov5640_write_reg(&pObj->Ctx, OV5640_SYSTEM_CTROL0, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { (void)OV5640_Delay(pObj, 500); if (ov5640_read_reg(&pObj->Ctx, OV5640_CHIP_ID_HIGH_BYTE, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { *Id = (uint32_t)tmp << 8U; if (ov5640_read_reg(&pObj->Ctx, OV5640_CHIP_ID_LOW_BYTE, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { *Id |= tmp; ret = OV5640_OK; } } } /* Component status */ return ret; } /** * @brief Read the OV5640 Camera Capabilities. * @param pObj pointer to component object * @param Capabilities pointer to component Capabilities * @retval Component status */ int32_t OV5640_GetCapabilities(OV5640_Object_t *pObj, OV5640_Capabilities_t *Capabilities) { int32_t ret; if (pObj == NULL) { ret = OV5640_ERROR; } else { Capabilities->Config_Brightness = 1; Capabilities->Config_Contrast = 1; Capabilities->Config_HueDegree = 1; Capabilities->Config_LightMode = 1; Capabilities->Config_MirrorFlip = 1; Capabilities->Config_NightMode = 1; Capabilities->Config_Resolution = 1; Capabilities->Config_Saturation = 1; Capabilities->Config_SpecialEffect = 1; Capabilities->Config_Zoom = 1; ret = OV5640_OK; } return ret; } /** * @brief Set the OV5640 camera Light Mode. * @param pObj pointer to component object * @param Effect Effect to be configured * @retval Component status */ int32_t OV5640_SetLightMode(OV5640_Object_t *pObj, uint32_t LightMode) { int32_t ret; uint32_t index; uint8_t tmp; /* OV5640 Light Mode setting */ static const uint16_t OV5640_LightModeAuto[][2] = { {OV5640_AWB_MANUAL_CONTROL, 0x00}, {OV5640_AWB_R_GAIN_MSB, 0x04}, {OV5640_AWB_R_GAIN_LSB, 0x00}, {OV5640_AWB_G_GAIN_MSB, 0x04}, {OV5640_AWB_G_GAIN_LSB, 0x00}, {OV5640_AWB_B_GAIN_MSB, 0x04}, {OV5640_AWB_B_GAIN_LSB, 0x00}, }; static const uint16_t OV5640_LightModeCloudy[][2] = { {OV5640_AWB_MANUAL_CONTROL, 0x01}, {OV5640_AWB_R_GAIN_MSB, 0x06}, {OV5640_AWB_R_GAIN_LSB, 0x48}, {OV5640_AWB_G_GAIN_MSB, 0x04}, {OV5640_AWB_G_GAIN_LSB, 0x00}, {OV5640_AWB_B_GAIN_MSB, 0x04}, {OV5640_AWB_B_GAIN_LSB, 0xD3}, }; static const uint16_t OV5640_LightModeOffice[][2] = { {OV5640_AWB_MANUAL_CONTROL, 0x01}, {OV5640_AWB_R_GAIN_MSB, 0x05}, {OV5640_AWB_R_GAIN_LSB, 0x48}, {OV5640_AWB_G_GAIN_MSB, 0x04}, {OV5640_AWB_G_GAIN_LSB, 0x00}, {OV5640_AWB_B_GAIN_MSB, 0x07}, {OV5640_AWB_B_GAIN_LSB, 0xCF}, }; static const uint16_t OV5640_LightModeHome[][2] = { {OV5640_AWB_MANUAL_CONTROL, 0x01}, {OV5640_AWB_R_GAIN_MSB, 0x04}, {OV5640_AWB_R_GAIN_LSB, 0x10}, {OV5640_AWB_G_GAIN_MSB, 0x04}, {OV5640_AWB_G_GAIN_LSB, 0x00}, {OV5640_AWB_B_GAIN_MSB, 0x08}, {OV5640_AWB_B_GAIN_LSB, 0xB6}, }; static const uint16_t OV5640_LightModeSunny[][2] = { {OV5640_AWB_MANUAL_CONTROL, 0x01}, {OV5640_AWB_R_GAIN_MSB, 0x06}, {OV5640_AWB_R_GAIN_LSB, 0x1C}, {OV5640_AWB_G_GAIN_MSB, 0x04}, {OV5640_AWB_G_GAIN_LSB, 0x00}, {OV5640_AWB_B_GAIN_MSB, 0x04}, {OV5640_AWB_B_GAIN_LSB, 0xF3}, }; tmp = 0x00; ret = ov5640_write_reg(&pObj->Ctx, OV5640_AWB_MANUAL_CONTROL, &tmp, 1); if (ret == OV5640_OK) { tmp = 0x46; ret = ov5640_write_reg(&pObj->Ctx, OV5640_AWB_CTRL16, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0xF8; ret = ov5640_write_reg(&pObj->Ctx, OV5640_AWB_CTRL17, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x04; ret = ov5640_write_reg(&pObj->Ctx, OV5640_AWB_CTRL18, &tmp, 1); } if (ret == OV5640_OK) { switch (LightMode) { case OV5640_LIGHT_SUNNY: for (index = 0; index < (sizeof(OV5640_LightModeSunny) / 4U) ; index++) { if (ret != OV5640_ERROR) { tmp = (uint8_t)OV5640_LightModeSunny[index][1]; if (ov5640_write_reg(&pObj->Ctx, OV5640_LightModeSunny[index][0], &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } } break; case OV5640_LIGHT_OFFICE: for (index = 0; index < (sizeof(OV5640_LightModeOffice) / 4U) ; index++) { if (ret != OV5640_ERROR) { tmp = (uint8_t)OV5640_LightModeOffice[index][1]; if (ov5640_write_reg(&pObj->Ctx, OV5640_LightModeOffice[index][0], &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } } break; case OV5640_LIGHT_CLOUDY: for (index = 0; index < (sizeof(OV5640_LightModeCloudy) / 4U) ; index++) { if (ret != OV5640_ERROR) { tmp = (uint8_t)OV5640_LightModeCloudy[index][1]; if (ov5640_write_reg(&pObj->Ctx, OV5640_LightModeCloudy[index][0], &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } } break; case OV5640_LIGHT_HOME: for (index = 0; index < (sizeof(OV5640_LightModeHome) / 4U) ; index++) { if (ret != OV5640_ERROR) { tmp = (uint8_t)OV5640_LightModeHome[index][1]; if (ov5640_write_reg(&pObj->Ctx, OV5640_LightModeHome[index][0], &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } } break; case OV5640_LIGHT_AUTO: default : for (index = 0; index < (sizeof(OV5640_LightModeAuto) / 4U) ; index++) { if (ret != OV5640_ERROR) { tmp = (uint8_t)OV5640_LightModeAuto[index][1]; if (ov5640_write_reg(&pObj->Ctx, OV5640_LightModeAuto[index][0], &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } } break; } } return ret; } /** * @brief Set the OV5640 camera Special Effect. * @param pObj pointer to component object * @param Effect Effect to be configured * @retval Component status */ int32_t OV5640_SetColorEffect(OV5640_Object_t *pObj, uint32_t Effect) { int32_t ret; uint8_t tmp; switch (Effect) { case OV5640_COLOR_EFFECT_BLUE: tmp = 0xFF; ret = ov5640_write_reg(&pObj->Ctx, OV5640_ISP_CONTROL01, &tmp, 1); if (ret == OV5640_OK) { tmp = 0x18; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL0, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0xA0; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL3, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x40; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL4, &tmp, 1); } if (ret != OV5640_OK) { ret = OV5640_ERROR; } break; case OV5640_COLOR_EFFECT_RED: tmp = 0xFF; ret = ov5640_write_reg(&pObj->Ctx, OV5640_ISP_CONTROL01, &tmp, 1); if (ret == OV5640_OK) { tmp = 0x18; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL0, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x80; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL3, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0xC0; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL4, &tmp, 1); } if (ret != OV5640_OK) { ret = OV5640_ERROR; } break; case OV5640_COLOR_EFFECT_GREEN: tmp = 0xFF; ret = ov5640_write_reg(&pObj->Ctx, OV5640_ISP_CONTROL01, &tmp, 1); if (ret == OV5640_OK) { tmp = 0x18; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL0, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x60; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL3, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x60; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL4, &tmp, 1); } if (ret != OV5640_OK) { ret = OV5640_ERROR; } break; case OV5640_COLOR_EFFECT_BW: tmp = 0xFF; ret = ov5640_write_reg(&pObj->Ctx, OV5640_ISP_CONTROL01, &tmp, 1); if (ret == OV5640_OK) { tmp = 0x18; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL0, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x80; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL3, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x80; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL4, &tmp, 1); } if (ret != OV5640_OK) { ret = OV5640_ERROR; } break; case OV5640_COLOR_EFFECT_SEPIA: tmp = 0xFF; ret = ov5640_write_reg(&pObj->Ctx, OV5640_ISP_CONTROL01, &tmp, 1); if (ret == OV5640_OK) { tmp = 0x18; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL0, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x40; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL3, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0xA0; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL4, &tmp, 1); } if (ret != OV5640_OK) { ret = OV5640_ERROR; } break; case OV5640_COLOR_EFFECT_NEGATIVE: tmp = 0xFF; ret = ov5640_write_reg(&pObj->Ctx, OV5640_ISP_CONTROL01, &tmp, 1); if (ret == OV5640_OK) { tmp = 0x40; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL0, &tmp, 1); } if (ret != OV5640_OK) { ret = OV5640_ERROR; } break; case OV5640_COLOR_EFFECT_NONE: default : tmp = 0x7F; ret = ov5640_write_reg(&pObj->Ctx, OV5640_ISP_CONTROL01, &tmp, 1); if (ret == OV5640_OK) { tmp = 0x00; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL0, &tmp, 1); } if (ret != OV5640_OK) { ret = OV5640_ERROR; } break; } return ret; } /** * @brief Set the OV5640 camera Brightness Level. * @note The brightness of OV5640 could be adjusted. Higher brightness will * make the picture more bright. The side effect of higher brightness * is the picture looks foggy. * @param pObj pointer to component object * @param Level Value to be configured * @retval Component status */ int32_t OV5640_SetBrightness(OV5640_Object_t *pObj, int32_t Level) { int32_t ret; const uint8_t brightness_level[] = {0x40U, 0x30U, 0x20U, 0x10U, 0x00U, 0x10U, 0x20U, 0x30U, 0x40U}; uint8_t tmp; tmp = 0xFF; ret = ov5640_write_reg(&pObj->Ctx, OV5640_ISP_CONTROL01, &tmp, 1); if (ret == OV5640_OK) { tmp = brightness_level[Level + 4]; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL7, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x04; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL0, &tmp, 1); } if (ret == OV5640_OK) { if (Level < 0) { tmp = 0x01; if (ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL8, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } else { tmp = 0x09; if (ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL8, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } } return ret; } /** * @brief Set the OV5640 camera Saturation Level. * @note The color saturation of OV5640 could be adjusted. High color saturation * would make the picture looks more vivid, but the side effect is the * bigger noise and not accurate skin color. * @param pObj pointer to component object * @param Level Value to be configured * @retval Component status */ int32_t OV5640_SetSaturation(OV5640_Object_t *pObj, int32_t Level) { int32_t ret; const uint8_t saturation_level[] = {0x00U, 0x10U, 0x20U, 0x30U, 0x80U, 0x70U, 0x60U, 0x50U, 0x40U}; uint8_t tmp; tmp = 0xFF; ret = ov5640_write_reg(&pObj->Ctx, OV5640_ISP_CONTROL01, &tmp, 1); if (ret == OV5640_OK) { tmp = saturation_level[Level + 4]; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL3, &tmp, 1); } if (ret == OV5640_OK) { ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL4, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x02; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL0, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x41; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL8, &tmp, 1); } if (ret != OV5640_OK) { ret = OV5640_ERROR; } return ret; } /** * @brief Set the OV5640 camera Contrast Level. * @note The contrast of OV5640 could be adjusted. Higher contrast will make * the picture sharp. But the side effect is losing dynamic range. * @param pObj pointer to component object * @param Level Value to be configured * @retval Component status */ int32_t OV5640_SetContrast(OV5640_Object_t *pObj, int32_t Level) { int32_t ret; const uint8_t contrast_level[] = {0x10U, 0x14U, 0x18U, 0x1CU, 0x20U, 0x24U, 0x28U, 0x2CU, 0x30U}; uint8_t tmp; tmp = 0xFF; ret = ov5640_write_reg(&pObj->Ctx, OV5640_ISP_CONTROL01, &tmp, 1); if (ret == OV5640_OK) { tmp = 0x04; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL0, &tmp, 1); } if (ret == OV5640_OK) { tmp = contrast_level[Level + 4]; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL6, &tmp, 1); } if (ret == OV5640_OK) { ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL5, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x41; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL8, &tmp, 1); } if (ret != OV5640_OK) { ret = OV5640_ERROR; } return ret; } /** * @brief Set the OV5640 camera Hue degree. * @param pObj pointer to component object * @param Level Value to be configured * @retval Component status */ int32_t OV5640_SetHueDegree(OV5640_Object_t *pObj, int32_t Degree) { int32_t ret; const uint8_t hue_degree_ctrl1[] = {0x80U, 0x6FU, 0x40U, 0x00U, 0x40U, 0x6FU, 0x80U, 0x6FU, 0x40U, 0x00U, 0x40U, 0x6FU }; const uint8_t hue_degree_ctrl2[] = {0x00U, 0x40U, 0x6FU, 0x80U, 0x6FU, 0x40U, 0x00U, 0x40U, 0x6FU, 0x80U, 0x6FU, 0x40U }; const uint8_t hue_degree_ctrl8[] = {0x32U, 0x32U, 0x32U, 0x02U, 0x02U, 0x02U, 0x01U, 0x01U, 0x01U, 0x31U, 0x31U, 0x31U }; uint8_t tmp; tmp = 0xFF; ret = ov5640_write_reg(&pObj->Ctx, OV5640_ISP_CONTROL01, &tmp, 1); if (ret == OV5640_OK) { tmp = 0x01; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL0, &tmp, 1); } if (ret == OV5640_OK) { tmp = hue_degree_ctrl1[Degree + 6]; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL1, &tmp, 1); } if (ret == OV5640_OK) { tmp = hue_degree_ctrl2[Degree + 6]; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL2, &tmp, 1); } if (ret == OV5640_OK) { tmp = hue_degree_ctrl8[Degree + 6]; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL8, &tmp, 1); } if (ret != OV5640_OK) { ret = OV5640_ERROR; } return ret; } /** * @brief Control OV5640 camera mirror/vflip. * @param pObj pointer to component object * @param Config To configure mirror, flip, both or none * @retval Component status */ int32_t OV5640_MirrorFlipConfig(OV5640_Object_t *pObj, uint32_t Config) { int32_t ret; uint8_t tmp3820 = 0; uint8_t tmp3821; if (ov5640_read_reg(&pObj->Ctx, OV5640_TIMING_TC_REG20, &tmp3820, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { tmp3820 &= 0xF9U; if (ov5640_read_reg(&pObj->Ctx, OV5640_TIMING_TC_REG21, &tmp3821, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { ret = OV5640_OK; tmp3821 &= 0xF9U; switch (Config) { case OV5640_MIRROR: if (ov5640_write_reg(&pObj->Ctx, OV5640_TIMING_TC_REG20, &tmp3820, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { tmp3821 |= 0x06U; if (ov5640_write_reg(&pObj->Ctx, OV5640_TIMING_TC_REG21, &tmp3821, 1) != OV5640_OK) { ret = OV5640_ERROR; } } break; case OV5640_FLIP: tmp3820 |= 0x06U; if (ov5640_write_reg(&pObj->Ctx, OV5640_TIMING_TC_REG20, &tmp3820, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { if (ov5640_write_reg(&pObj->Ctx, OV5640_TIMING_TC_REG21, &tmp3821, 1) != OV5640_OK) { ret = OV5640_ERROR; } } break; case OV5640_MIRROR_FLIP: tmp3820 |= 0x06U; if (ov5640_write_reg(&pObj->Ctx, OV5640_TIMING_TC_REG20, &tmp3820, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { tmp3821 |= 0x06U; if (ov5640_write_reg(&pObj->Ctx, OV5640_TIMING_TC_REG21, &tmp3821, 1) != OV5640_OK) { ret = OV5640_ERROR; } } break; case OV5640_MIRROR_FLIP_NONE: default: if (ov5640_write_reg(&pObj->Ctx, OV5640_TIMING_TC_REG20, &tmp3820, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { if (ov5640_write_reg(&pObj->Ctx, OV5640_TIMING_TC_REG21, &tmp3821, 1) != OV5640_OK) { ret = OV5640_ERROR; } } break; } } } return ret; } /** * @brief Control OV5640 camera zooming. * @param pObj pointer to component object * @param Zoom Zoom to be configured * @retval Component status */ int32_t OV5640_ZoomConfig(OV5640_Object_t *pObj, uint32_t Zoom) { int32_t ret = OV5640_OK; uint32_t res; uint32_t zoom; uint8_t tmp; /* Get camera resolution */ if (OV5640_GetResolution(pObj, &res) != OV5640_OK) { ret = OV5640_ERROR; } else { zoom = Zoom; if (zoom == OV5640_ZOOM_x1) { tmp = 0x10; if (ov5640_write_reg(&pObj->Ctx, OV5640_SCALE_CTRL0, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } else { switch (res) { case OV5640_R320x240: case OV5640_R480x272: zoom = zoom >> 1U; break; case OV5640_R640x480: zoom = zoom >> 2U; break; default: break; } tmp = 0x00; if (ov5640_write_reg(&pObj->Ctx, OV5640_SCALE_CTRL0, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { tmp = (uint8_t)zoom; if (ov5640_write_reg(&pObj->Ctx, OV5640_SCALE_CTRL1, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } } } return ret; } /** * @brief Enable/disable the OV5640 camera night mode. * @param pObj pointer to component object * @param Cmd Enable disable night mode * @retval Component status */ int32_t OV5640_NightModeConfig(OV5640_Object_t *pObj, uint32_t Cmd) { int32_t ret; uint8_t tmp = 0; if (Cmd == NIGHT_MODE_ENABLE) { /* Auto Frame Rate: 15fps ~ 3.75fps night mode for 60/50Hz light environment, 24Mhz clock input,24Mhz PCLK*/ ret = ov5640_write_reg(&pObj->Ctx, OV5640_SC_PLL_CONTRL4, &tmp, 1); if (ret == OV5640_OK) { ret = ov5640_write_reg(&pObj->Ctx, OV5640_SC_PLL_CONTRL5, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x7C; ret = ov5640_write_reg(&pObj->Ctx, OV5640_AEC_CTRL00, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x01; ret = ov5640_write_reg(&pObj->Ctx, OV5640_AEC_B50_STEP_HIGH, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x27; ret = ov5640_write_reg(&pObj->Ctx, OV5640_AEC_B50_STEP_LOW, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x00; ret = ov5640_write_reg(&pObj->Ctx, OV5640_AEC_B60_STEP_HIGH, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0xF6; ret = ov5640_write_reg(&pObj->Ctx, OV5640_AEC_B60_STEP_LOW, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x04; ret = ov5640_write_reg(&pObj->Ctx, OV5640_AEC_CTRL0D, &tmp, 1); } if (ret == OV5640_OK) { ret = ov5640_write_reg(&pObj->Ctx, OV5640_AEC_CTRL0E, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x0B; ret = ov5640_write_reg(&pObj->Ctx, OV5640_AEC_CTRL02, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x88; ret = ov5640_write_reg(&pObj->Ctx, OV5640_AEC_CTRL03, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x0B; ret = ov5640_write_reg(&pObj->Ctx, OV5640_AEC_MAX_EXPO_HIGH, &tmp, 1); } if (ret == OV5640_OK) { tmp = 0x88; ret = ov5640_write_reg(&pObj->Ctx, OV5640_AEC_MAX_EXPO_LOW, &tmp, 1); } if (ret != OV5640_OK) { ret = OV5640_ERROR; } } else { if (ov5640_read_reg(&pObj->Ctx, OV5640_AEC_CTRL00, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } else { ret = OV5640_OK; tmp &= 0xFBU; /* Set Bit 2 to 0 */ if (ov5640_write_reg(&pObj->Ctx, OV5640_AEC_CTRL00, &tmp, 1) != OV5640_OK) { ret = OV5640_ERROR; } } } return ret; } /** * @brief Configure Embedded Synchronization mode. * @param pObj pointer to component object * @param pSyncCodes pointer to Embedded Codes * @retval Component status */ int32_t OV5640_EmbeddedSynchroConfig(OV5640_Object_t *pObj, OV5640_SyncCodes_t *pSyncCodes) { uint8_t tmp; int32_t ret = OV5640_ERROR; /*[7] : SYNC code from reg 0x4732-0x4732, [1]: Enable Clip ,[0]: Enable CCIR656 */ tmp = 0x83; if (ov5640_write_reg(&pObj->Ctx, OV5640_CCIR656_CTRL00, &tmp, 1) == OV5640_OK) { tmp = pSyncCodes->FrameStartCode; if (ov5640_write_reg(&pObj->Ctx, OV5640_CCIR656_FS, &tmp, 1) == OV5640_OK) { tmp = pSyncCodes->FrameEndCode; if (ov5640_write_reg(&pObj->Ctx, OV5640_CCIR656_FE, &tmp, 1) != OV5640_OK) { return OV5640_ERROR; } tmp = pSyncCodes->LineStartCode; if (ov5640_write_reg(&pObj->Ctx, OV5640_CCIR656_LS, &tmp, 1) == OV5640_OK) { tmp = pSyncCodes->LineEndCode; if (ov5640_write_reg(&pObj->Ctx, OV5640_CCIR656_LE, &tmp, 1) == OV5640_OK) { /*Adding 1 dummy line */ tmp = 0x01; if (ov5640_write_reg(&pObj->Ctx, OV5640_656_DUMMY_LINE, &tmp, 1) == OV5640_OK) { ret = OV5640_OK; } } } } } /* max clip value[9:8], to avoid SYNC code clipping */ tmp = 0x2; if (ret == OV5640_OK) { ret = ov5640_write_reg(&pObj->Ctx, 0x4302, &tmp, 1); } if (ret == OV5640_OK) { ret = ov5640_write_reg(&pObj->Ctx, 0x4306, &tmp, 1); } if (ret == OV5640_OK) { ret = ov5640_write_reg(&pObj->Ctx, 0x430A, &tmp, 1); } return ret; } /** * @brief Enable/disable the OV5640 color bar mode. * @param pObj pointer to component object * @param Cmd Enable disable colorbar * @retval Component status */ int32_t OV5640_ColorbarModeConfig(OV5640_Object_t *pObj, uint32_t Cmd) { int32_t ret; uint8_t tmp = 0x40; if ((Cmd == COLORBAR_MODE_ENABLE) || (Cmd == COLORBAR_MODE_GRADUALV)) { ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL4, &tmp, 1); if (ret == OV5640_OK) { tmp = (Cmd == COLORBAR_MODE_GRADUALV ? 0x8c : 0x80); ret = ov5640_write_reg(&pObj->Ctx, OV5640_PRE_ISP_TEST_SETTING1, &tmp, 1); } if (ret != OV5640_OK) { ret = OV5640_ERROR; } } else { tmp = 0x10; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL4, &tmp, 1); if (ret == OV5640_OK) { tmp = 0x00; ret = ov5640_write_reg(&pObj->Ctx, OV5640_PRE_ISP_TEST_SETTING1, &tmp, 1); } if (ret != OV5640_OK) { ret = OV5640_ERROR; } } return ret; } /** * @brief Set the camera pixel clock * @param pObj pointer to component object * @param ClockValue Can be OV5640_PCLK_24M, OV5640_PCLK_12M, OV5640_PCLK_9M * OV5640_PCLK_8M, OV5640_PCLK_7M * @retval Component status */ int32_t OV5640_SetPCLK(OV5640_Object_t *pObj, uint32_t ClockValue) { int32_t ret; uint8_t tmp; switch(ClockValue) { case OV5640_PCLK_7M: tmp = 0x38; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SC_PLL_CONTRL2, &tmp, 1); tmp = 0x16; ret += ov5640_write_reg(&pObj->Ctx, OV5640_SC_PLL_CONTRL3, &tmp, 1); break; case OV5640_PCLK_8M: tmp = 0x40; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SC_PLL_CONTRL2, &tmp, 1); tmp = 0x16; ov5640_write_reg(&pObj->Ctx, OV5640_SC_PLL_CONTRL3, &tmp, 1); break; case OV5640_PCLK_9M: ret = ov5640_write_reg(&pObj->Ctx, OV5640_SC_PLL_CONTRL2, &tmp, 1); tmp = 0x18; ret += ov5640_write_reg(&pObj->Ctx, OV5640_SC_PLL_CONTRL3, &tmp, 1); break; case OV5640_PCLK_12M: ret = ov5640_write_reg(&pObj->Ctx, OV5640_SC_PLL_CONTRL2, &tmp, 1); tmp = 0x16; ret += ov5640_write_reg(&pObj->Ctx, OV5640_SC_PLL_CONTRL3, &tmp, 1); break; case OV5640_PCLK_24M: default: tmp = 0x60; ret = ov5640_write_reg(&pObj->Ctx, OV5640_SC_PLL_CONTRL2, &tmp, 1); tmp = 0x13; ret += ov5640_write_reg(&pObj->Ctx, OV5640_SC_PLL_CONTRL3, &tmp, 1); break; } if (ret != OV5640_OK) { ret = OV5640_ERROR; } return ret; } /** * @} */ /** @defgroup OV5640_Private_Functions Private Functions * @{ */ /** * @brief This function provides accurate delay (in milliseconds) * @param pObj pointer to component object * @param Delay specifies the delay time length, in milliseconds * @retval OV5640_OK */ static int32_t OV5640_Delay(OV5640_Object_t *pObj, uint32_t Delay) { uint32_t tickstart; tickstart = pObj->IO.GetTick(); while ((pObj->IO.GetTick() - tickstart) < Delay) { } return OV5640_OK; } /** * @brief Wrap component ReadReg to Bus Read function * @param handle Component object handle * @param Reg The target register address to write * @param pData The target register value to be written * @param Length buffer size to be written * @retval error status */ static int32_t OV5640_ReadRegWrap(void *handle, uint16_t Reg, uint8_t *pData, uint16_t Length) { OV5640_Object_t *pObj = (OV5640_Object_t *)handle; return pObj->IO.ReadReg(pObj->IO.Address, Reg, pData, Length); } /** * @brief Wrap component WriteReg to Bus Write function * @param handle Component object handle * @param Reg The target register address to write * @param pData The target register value to be written * @param Length buffer size to be written * @retval error status */ static int32_t OV5640_WriteRegWrap(void *handle, uint16_t Reg, uint8_t *pData, uint16_t Length) { OV5640_Object_t *pObj = (OV5640_Object_t *)handle; return pObj->IO.WriteReg(pObj->IO.Address, Reg, pData, Length); } /** * @} */ /** * @} */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/