kendryte-freertos-sdk/src/face_detect/ov5640.c

465 lines
13 KiB
C

/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <devices.h>
#include <sys/unistd.h>
#include "ov5640.h"
#include "dvp_camera.h"
#include "ov5640af.h"
#include "ov5640cfg.h"
static uintptr_t file_sccb;
static uintptr_t file_ov5640;
#define REGLENGTH 16
const uint16_t jpeg_size_tbl[][2] = {
{ 160, 120 }, //QQVGA
{ 176, 144 }, //QCIF
{ 320, 240 }, //QVGA
{ 400, 240 }, //WQVGA
{ 352, 288 }, //CIF
};
uint8_t OV5640_WR_Reg(uint16_t reg, uint8_t data)
{
sccb_dev_write_byte(file_ov5640, reg, data);
return 0;
}
uint8_t OV5640_RD_Reg(uint16_t reg)
{
return sccb_dev_read_byte(file_ov5640, reg);
}
void ov5640_file_init()
{
file_sccb = io_open("/dev/sccb0");
file_ov5640 = sccb_get_device(file_sccb, OV5640_ADDR, REGLENGTH);
}
void ov5640_init(void)
{
uint16_t i = 0;
uint16_t reg;
ov5640_file_init();
reg = OV5640_RD_Reg(OV5640_CHIPIDH);
reg <<= 8;
reg |= OV5640_RD_Reg(OV5640_CHIPIDL);
printf("ID: %X \r\n", reg);
if (reg != OV5640_ID)
{
configASSERT(!"ov5640 get id error.");
}
usleep(100 * 1000);
OV5640_WR_Reg(0x3103, 0X11); //system clock from pad, bit[1]
OV5640_WR_Reg(0X3008, 0X82);
usleep(100 * 1000);
for (i = 0; ov5640_config[i][0] != 0; i++)
OV5640_WR_Reg(ov5640_config[i][0], ov5640_config[i][1]);
}
void OV5640_JPEG_Mode(void)
{
uint16_t i = 0;
for (i = 0; i < (sizeof(OV5640_jpeg_reg_tbl) / 4); i++)
{
OV5640_WR_Reg(OV5640_jpeg_reg_tbl[i][0], OV5640_jpeg_reg_tbl[i][1]);
}
}
void OV5640_RGB565_Mode(void)
{
uint16_t i = 0;
for (i = 0; i < (sizeof(ov5640_rgb565_reg_tbl) / 4); i++)
{
OV5640_WR_Reg(ov5640_rgb565_reg_tbl[i][0], ov5640_rgb565_reg_tbl[i][1]);
}
}
const static uint8_t OV5640_EXPOSURE_TBL[7][6] = {
{ 0x10, 0x08, 0x10, 0x08, 0x20, 0x10 }, //-3
{ 0x20, 0x18, 0x41, 0x20, 0x18, 0x10 }, //-2
{ 0x30, 0x28, 0x61, 0x30, 0x28, 0x10 }, //-1
{ 0x38, 0x30, 0x61, 0x38, 0x30, 0x10 }, //0
{ 0x40, 0x38, 0x71, 0x40, 0x38, 0x10 }, //+1
{ 0x50, 0x48, 0x90, 0x50, 0x48, 0x20 }, //+2
{ 0x60, 0x58, 0xa0, 0x60, 0x58, 0x20 }, //+3
};
//exposure: 0 - 6,
void OV5640_Exposure(uint8_t exposure)
{
OV5640_WR_Reg(0x3212, 0x03); //start group 3
OV5640_WR_Reg(0x3a0f, OV5640_EXPOSURE_TBL[exposure][0]);
OV5640_WR_Reg(0x3a10, OV5640_EXPOSURE_TBL[exposure][1]);
OV5640_WR_Reg(0x3a1b, OV5640_EXPOSURE_TBL[exposure][2]);
OV5640_WR_Reg(0x3a1e, OV5640_EXPOSURE_TBL[exposure][3]);
OV5640_WR_Reg(0x3a11, OV5640_EXPOSURE_TBL[exposure][4]);
OV5640_WR_Reg(0x3a1f, OV5640_EXPOSURE_TBL[exposure][5]);
OV5640_WR_Reg(0x3212, 0x13); //end group 3
OV5640_WR_Reg(0x3212, 0xa3); //launch group 3
}
const static uint8_t OV5640_LIGHTMODE_TBL[5][7] = {
{ 0x04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00 }, //Auto
{ 0x06, 0X1C, 0X04, 0X00, 0X04, 0XF3, 0X01 }, //Sunny
{ 0x05, 0X48, 0X04, 0X00, 0X07, 0XCF, 0X01 }, //Office
{ 0x06, 0X48, 0X04, 0X00, 0X04, 0XD3, 0X01 }, //Cloudy
{ 0x04, 0X10, 0X04, 0X00, 0X08, 0X40, 0X01 }, //Home
};
// light mode:
// 0: auto
// 1: sunny
// 2: office
// 3: cloudy
// 4: home
void OV5640_Light_Mode(uint8_t mode)
{
uint8_t i;
OV5640_WR_Reg(0x3212, 0x03); //start group 3
for (i = 0; i < 7; i++)
OV5640_WR_Reg(0x3400 + i, OV5640_LIGHTMODE_TBL[mode][i]);
OV5640_WR_Reg(0x3212, 0x13); //end group 3
OV5640_WR_Reg(0x3212, 0xa3); //launch group 3
}
const static uint8_t OV5640_SATURATION_TBL[7][6] = {
{ 0X0C, 0x30, 0X3D, 0X3E, 0X3D, 0X01 }, //-3
{ 0X10, 0x3D, 0X4D, 0X4E, 0X4D, 0X01 }, //-2
{ 0X15, 0x52, 0X66, 0X68, 0X66, 0X02 }, //-1
{ 0X1A, 0x66, 0X80, 0X82, 0X80, 0X02 }, //+0
{ 0X1F, 0x7A, 0X9A, 0X9C, 0X9A, 0X02 }, //+1
{ 0X24, 0x8F, 0XB3, 0XB6, 0XB3, 0X03 }, //+2
{ 0X2B, 0xAB, 0XD6, 0XDA, 0XD6, 0X04 }, //+3
};
// Color Saturation:
// sat: 0 - 6
void OV5640_Color_Saturation(uint8_t sat)
{
uint8_t i;
OV5640_WR_Reg(0x3212, 0x03); //start group 3
OV5640_WR_Reg(0x5381, 0x1c);
OV5640_WR_Reg(0x5382, 0x5a);
OV5640_WR_Reg(0x5383, 0x06);
for (i = 0; i < 6; i++)
OV5640_WR_Reg(0x5384 + i, OV5640_SATURATION_TBL[sat][i]);
OV5640_WR_Reg(0x538b, 0x98);
OV5640_WR_Reg(0x538a, 0x01);
OV5640_WR_Reg(0x3212, 0x13); //end group 3
OV5640_WR_Reg(0x3212, 0xa3); //launch group 3
}
//Brightness
// bright: 0 - 8
void OV5640_Brightness(uint8_t bright)
{
uint8_t brtval;
if (bright < 4)
brtval = 4 - bright;
else
brtval = bright - 4;
OV5640_WR_Reg(0x3212, 0x03); //start group 3
OV5640_WR_Reg(0x5587, brtval << 4);
if (bright < 4)
OV5640_WR_Reg(0x5588, 0x09);
else
OV5640_WR_Reg(0x5588, 0x01);
OV5640_WR_Reg(0x3212, 0x13); //end group 3
OV5640_WR_Reg(0x3212, 0xa3); //launch group 3
}
//Contrast:
// contrast: 0 - 6
void OV5640_Contrast(uint8_t contrast)
{
uint8_t reg0val = 0X00;
uint8_t reg1val = 0X20;
switch (contrast)
{
case 0: //-3
reg1val = reg0val = 0X14;
break;
case 1: //-2
reg1val = reg0val = 0X18;
break;
case 2: //-1
reg1val = reg0val = 0X1C;
break;
case 4: //1
reg0val = 0X10;
reg1val = 0X24;
break;
case 5: //2
reg0val = 0X18;
reg1val = 0X28;
break;
case 6: //3
reg0val = 0X1C;
reg1val = 0X2C;
break;
}
OV5640_WR_Reg(0x3212, 0x03); //start group 3
OV5640_WR_Reg(0x5585, reg0val);
OV5640_WR_Reg(0x5586, reg1val);
OV5640_WR_Reg(0x3212, 0x13); //end group 3
OV5640_WR_Reg(0x3212, 0xa3); //launch group 3
}
// Sharpness:
// sharp: 0 - 33 (0: close , 33: auto , other: Sharpness)
void OV5640_Sharpness(uint8_t sharp)
{
if (sharp < 33)
{
OV5640_WR_Reg(0x5308, 0x65);
OV5640_WR_Reg(0x5302, sharp);
}
else // auto
{
OV5640_WR_Reg(0x5308, 0x25);
OV5640_WR_Reg(0x5300, 0x08);
OV5640_WR_Reg(0x5301, 0x30);
OV5640_WR_Reg(0x5302, 0x10);
OV5640_WR_Reg(0x5303, 0x00);
OV5640_WR_Reg(0x5309, 0x08);
OV5640_WR_Reg(0x530a, 0x30);
OV5640_WR_Reg(0x530b, 0x04);
OV5640_WR_Reg(0x530c, 0x06);
}
}
const static uint8_t OV5640_EFFECTS_TBL[7][3] =
{
{ 0X06, 0x40, 0X10 }, // normal
{ 0X1E, 0xA0, 0X40 },
{ 0X1E, 0x80, 0XC0 },
{ 0X1E, 0x80, 0X80 },
{ 0X1E, 0x40, 0XA0 },
{ 0X40, 0x40, 0X10 },
{ 0X1E, 0x60, 0X60 },
};
void OV5640_Special_Effects(uint8_t eft)
{
OV5640_WR_Reg(0x3212, 0x03); //start group 3
OV5640_WR_Reg(0x5580, OV5640_EFFECTS_TBL[eft][0]);
OV5640_WR_Reg(0x5583, OV5640_EFFECTS_TBL[eft][1]); // sat U
OV5640_WR_Reg(0x5584, OV5640_EFFECTS_TBL[eft][2]); // sat V
OV5640_WR_Reg(0x5003, 0x08);
OV5640_WR_Reg(0x3212, 0x13); //end group 3
OV5640_WR_Reg(0x3212, 0xa3); //launch group 3
}
// Flash Lamp
// sw: 0: off
// 1: on
void OV5640_Flash_Lamp(uint8_t sw)
{
OV5640_WR_Reg(0x3016, 0X02);
OV5640_WR_Reg(0x301C, 0X02);
if (sw)
OV5640_WR_Reg(0X3019, 0X02);
else
OV5640_WR_Reg(0X3019, 0X00);
}
// set the output size
uint8_t OV5640_OutSize_Set(uint16_t offx, uint16_t offy, uint16_t width, uint16_t height)
{
OV5640_WR_Reg(0X3212, 0X03);
OV5640_WR_Reg(0x3808, width >> 8);
OV5640_WR_Reg(0x3809, width & 0xff);
OV5640_WR_Reg(0x380a, height >> 8);
OV5640_WR_Reg(0x380b, height & 0xff);
OV5640_WR_Reg(0x3810, offx >> 8);
OV5640_WR_Reg(0x3811, offx & 0xff);
OV5640_WR_Reg(0x3812, offy >> 8);
OV5640_WR_Reg(0x3813, offy & 0xff);
OV5640_WR_Reg(0X3212, 0X13);
OV5640_WR_Reg(0X3212, 0Xa3);
return 0;
}
uint8_t OV5640_Focus_Init(void)
{
uint16_t i;
uint16_t addr = 0x8000;
uint8_t state = 0x8F;
OV5640_WR_Reg(0x3000, 0x20); //reset
for (i = 0; i < sizeof(OV5640_AF_Config); i++)
{
OV5640_WR_Reg(addr, OV5640_AF_Config[i]);
addr++;
}
OV5640_WR_Reg(0x3022, 0x00);
OV5640_WR_Reg(0x3023, 0x00);
OV5640_WR_Reg(0x3024, 0x00);
OV5640_WR_Reg(0x3025, 0x00);
OV5640_WR_Reg(0x3026, 0x00);
OV5640_WR_Reg(0x3027, 0x00);
OV5640_WR_Reg(0x3028, 0x00);
OV5640_WR_Reg(0x3029, 0x7f);
OV5640_WR_Reg(0x3000, 0x00);
i = 0;
do
{
state = OV5640_RD_Reg(0x3029);
usleep(5 * 1000);
i++;
if (i > 1000)
return 1;
} while (state != 0x70);
return 0;
}
uint8_t OV5640_Auto_Focus(void)
{
uint8_t temp = 0;
uint16_t retry = 0;
OV5640_WR_Reg(0x3023, 0x01);
OV5640_WR_Reg(0x3022, 0x08);
do
{
temp = OV5640_RD_Reg(0x3023);
retry++;
if (retry > 1000)
return 2;
usleep(5 * 1000);
} while (temp != 0x00);
OV5640_WR_Reg(0x3023, 0x01);
OV5640_WR_Reg(0x3022, 0x04);
retry = 0;
do
{
temp = OV5640_RD_Reg(0x3023);
retry++;
if (retry > 1000)
return 2;
usleep(5 * 1000);
} while (temp != 0x00);
return 0;
}
void jpeg_test(uint8_t jpg_size)
{
// HAL_DCMI_Stop(&hdcmi);
OV5640_JPEG_Mode();
OV5640_OutSize_Set(4, 0, jpeg_size_tbl[jpg_size][0], jpeg_size_tbl[jpg_size][1]);
OV5640_WR_Reg(0x3035, 0X41); // slow down OV5640 clocks
OV5640_WR_Reg(0x3036, 0x68);
//
// /* DCMI DMA DeInit */
// HAL_DMA_DeInit(&hdma_dcmi);
//
// /* DCMI DMA Init */
// /* DCMI Init */
// hdma_dcmi.Instance = DMA2_Stream1;
// hdma_dcmi.Init.Channel = DMA_CHANNEL_1;
// hdma_dcmi.Init.Direction = DMA_PERIPH_TO_MEMORY;
// hdma_dcmi.Init.PeriphInc = DMA_PINC_DISABLE;
// hdma_dcmi.Init.MemInc = DMA_MINC_ENABLE;
// hdma_dcmi.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
// hdma_dcmi.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
// hdma_dcmi.Init.Mode = DMA_CIRCULAR;
// hdma_dcmi.Init.Priority = DMA_PRIORITY_HIGH;
// hdma_dcmi.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
// hdma_dcmi.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
// hdma_dcmi.Init.MemBurst = DMA_MBURST_SINGLE;
// hdma_dcmi.Init.PeriphBurst = DMA_PBURST_SINGLE;
// if (HAL_DMA_Init(&hdma_dcmi) != HAL_OK)
// {
// _Error_Handler(__FILE__, __LINE__);
// }
//
// __HAL_LINKDMA(&hdcmi,DMA_Handle,hdma_dcmi);
//
// __HAL_DCMI_ENABLE_IT(&hdcmi,DCMI_IT_FRAME);
//
// /* Start the Camera capture */
// HAL_DCMI_Start_DMA(&hdcmi, DCMI_MODE_CONTINUOUS, (uint32_t)jpeg_data_buf, jpeg_buf_size/4 );
// jpeg_mode = 1;
//
while (1)
{
}
}
void rgb565_test(void)
{
// HAL_DCMI_Stop(&hdcmi);
//
// jpeg_mode = 0;
OV5640_RGB565_Mode();
OV5640_OutSize_Set(4, 0, XSIZE, YSIZE);
// BSP_LCD_Init();
// BSP_LCD_Clear(LCD_COLOR_BLACK);
//
// /* Set image position */
// ili9325_SetCursor(0, 0);
// /* Prepare to write GRAM (0x22) */
// LCD_IO_WriteReg(LCD_REG_34);
// OV5640_WR_Reg(0x3035,0X51); // slow down OV5640 clocks ,adapt to the refresh rate of the LCD
// OV5640_WR_Reg(0x3036,0X88);
//
// /* DCMI DMA DeInit */
// HAL_DMA_DeInit(&hdma_dcmi);
//
// /* DCMI DMA Init */
// /* DCMI Init */
// hdma_dcmi.Instance = DMA2_Stream1;
// hdma_dcmi.Init.Channel = DMA_CHANNEL_1;
// hdma_dcmi.Init.Direction = DMA_PERIPH_TO_MEMORY;
// hdma_dcmi.Init.PeriphInc = DMA_PINC_DISABLE;
// hdma_dcmi.Init.MemInc = DMA_MINC_DISABLE;
// hdma_dcmi.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
// hdma_dcmi.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
// hdma_dcmi.Init.Mode = DMA_CIRCULAR;
// hdma_dcmi.Init.Priority = DMA_PRIORITY_HIGH;
// hdma_dcmi.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
// hdma_dcmi.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
// hdma_dcmi.Init.MemBurst = DMA_MBURST_SINGLE;
// hdma_dcmi.Init.PeriphBurst = DMA_PBURST_SINGLE;
// if (HAL_DMA_Init(&hdma_dcmi) != HAL_OK)
// {
// _Error_Handler(__FILE__, __LINE__);
// }
//
// __HAL_LINKDMA(&hdcmi,DMA_Handle,hdma_dcmi);
//
// /* Start the Camera capture */
// HAL_DCMI_Start_DMA(&hdcmi, DCMI_MODE_CONTINUOUS, (uint32_t)LCD_GRAM_ADDRESS, 1);
//
// while(1)
// {
// }
}