浏览代码

[add] dcmi and ov2640 driver.

thread-liu 4 年之前
父节点
当前提交
2fa563f164

+ 51 - 17
bsp/stm32/stm32h743-atk-apollo/board/Kconfig

@@ -41,6 +41,13 @@ menu "Onboard Peripheral Drivers"
         select RT_USING_DFS_ELMFAT
         default n
 
+    config BSP_USING_OV2640
+        bool "Enable camera (ov2640)"
+        select BSP_USING_DCMI
+        select BSP_USING_I2C
+        select BSP_USING_I2C2
+        default n
+
 endmenu
 
 menu "On-chip Peripheral Drivers"
@@ -98,28 +105,55 @@ menu "On-chip Peripheral Drivers"
         select RT_USING_SPI
         default n
 
-    menuconfig BSP_USING_I2C1
-        bool "Enable I2C1 BUS (software simulation)"
-        default n
-        select RT_USING_I2C
-        select RT_USING_I2C_BITOPS
-        select RT_USING_PIN
-        if BSP_USING_I2C1
-            comment "Notice: PH4 --> 116; PH5 --> 117"
-            config BSP_I2C1_SCL_PIN
-                int "i2c1 scl pin number"
-                range 1 176
-                default 116
-            config BSP_I2C1_SDA_PIN
-                int "I2C1 sda pin number"
-                range 1 176
-                default 117
-        endif
+    menuconfig BSP_USING_I2C
+    bool "Enable I2C BUS (software simulation)"
+    select RT_USING_I2C
+    select RT_USING_I2C_BITOPS
+    select RT_USING_PIN
+    default n
+    if BSP_USING_I2C
+        menuconfig BSP_USING_I2C1
+            bool "Enable I2C1 BUS (software simulation)"
+            default n
+            if BSP_USING_I2C1
+                comment "Notice: PH4 --> 116; PH5 --> 117"
+                config BSP_I2C1_SCL_PIN
+                    int "i2c1 scl pin number"
+                    range 1 176
+                    default 116
+                config BSP_I2C1_SDA_PIN
+                    int "I2C1 sda pin number"
+                    range 1 176
+                    default 117
+                        menuconfig BSP_USING_I2C2
+                    bool "Enable I2C2 BUS (software simulation)"
+                    default n
+            endif
+
+            menuconfig BSP_USING_I2C2
+            bool "Enable I2C2 BUS (software simulation)"
+            default n
+            if BSP_USING_I2C2
+                comment "Notice: PH13 --> 125; PH15 --> 127"
+                config BSP_I2C2_SCL_PIN
+                    int "i2c2 scl pin number"
+                    range 1 176
+                    default 127
+                config BSP_I2C2_SDA_PIN
+                    int "I2C2 sda pin number"
+                    range 1 176
+                    default 125
+            endif
+    endif
 
     config BSP_USING_ON_CHIP_FLASH
         bool "Enable on-chip FLASH"
         default n
 
+    config BSP_USING_DCMI
+        bool "Enable DCMI"
+        default n
+
     menuconfig BSP_USING_ONCHIP_RTC
         bool "Enable RTC"
         select RT_USING_RTC

+ 4 - 0
bsp/stm32/stm32h743-atk-apollo/board/SConscript

@@ -17,6 +17,10 @@ if GetDepend(['BSP_USING_QSPI_FLASH']):
     src += Glob('ports/drv_qspi_flash.c')
 if GetDepend(['BSP_USING_SDMMC']):
     src += Glob('ports/drv_sdio.c')
+if GetDepend(['BSP_USING_DCMI']):
+    src += Glob('ports/drv_dcmi.c')
+if GetDepend(['BSP_USING_OV2640']):
+    src += Glob('ports/drv_ov2640.c')
 
 path = [cwd]
 path += [cwd + '/CubeMX_Config/Inc']

+ 223 - 0
bsp/stm32/stm32h743-atk-apollo/board/ports/drv_dcmi.c

@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author            Notes
+ * 2020-07-27     thread-liu        the first version
+ */
+
+#include "board.h"
+
+#if defined(BSP_USING_DCMI)
+
+#include <drv_dcmi.h>
+
+#define DRV_DEBUG
+#define LOG_TAG             "drv.dcmi"
+#include <drv_log.h>
+
+struct stm32_dcmi
+{
+    DCMI_HandleTypeDef DCMI_Handle;
+    struct rt_dcmi_device dev;
+};
+static struct stm32_dcmi rt_dcmi = {0};
+
+DMA_HandleTypeDef hdma_dcmi;
+
+static void rt_hw_dcmi_dma_init(void)
+{
+    __HAL_RCC_DMA2_CLK_ENABLE();
+
+    hdma_dcmi.Instance                 = DMA2_Stream1;
+    hdma_dcmi.Init.Request             = DMA_REQUEST_DCMI;
+    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;
+
+    HAL_DMA_DeInit(&hdma_dcmi);
+    HAL_DMA_Init(&hdma_dcmi);
+
+    __HAL_LINKDMA(&rt_dcmi.DCMI_Handle, DMA_Handle, hdma_dcmi);
+
+    HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0x00, 0x00);
+    HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);;
+}
+
+void rt_hw_dcmi_dma_config(rt_uint32_t dst_addr1, rt_uint32_t dst_addr2, rt_uint32_t len)
+{
+    __HAL_UNLOCK(&hdma_dcmi);
+
+    HAL_DMAEx_MultiBufferStart(&hdma_dcmi, (rt_uint32_t)&DCMI->DR, dst_addr1, dst_addr2, len);
+
+    __HAL_DMA_ENABLE_IT(&hdma_dcmi, DMA_IT_TC);
+}
+
+static rt_err_t rt_hw_dcmi_init(DCMI_HandleTypeDef *device)
+{
+    RT_ASSERT(device != RT_NULL);
+
+    device->Instance               = DCMI;
+    device->Init.SynchroMode       = DCMI_SYNCHRO_HARDWARE;
+    device->Init.PCKPolarity       = DCMI_PCKPOLARITY_RISING;
+    device->Init.VSPolarity        = DCMI_VSPOLARITY_LOW;
+    device->Init.HSPolarity        = DCMI_HSPOLARITY_LOW;
+    device->Init.CaptureRate       = DCMI_CR_ALL_FRAME;
+    device->Init.ExtendedDataMode  = DCMI_EXTEND_DATA_8B;
+    device->Init.JPEGMode          = DCMI_JPEG_ENABLE;
+    device->Init.ByteSelectMode    = DCMI_BSM_ALL;
+    device->Init.ByteSelectStart   = DCMI_OEBS_ODD;
+    device->Init.LineSelectMode    = DCMI_LSM_ALL;
+    device->Init.LineSelectStart   = DCMI_OELS_ODD;
+
+    if (HAL_DCMI_Init(device) != HAL_OK)
+    {
+        LOG_E("dcmi init error!");
+        return RT_ERROR;
+    }
+
+    DCMI->IER = 0x0;
+
+    __HAL_DCMI_ENABLE_IT(device, DCMI_IT_FRAME);
+    __HAL_DCMI_ENABLE(device);
+
+    return RT_EOK;
+}
+
+void DCMI_IRQHandler(void)
+{
+    /* enter interrupt */
+    rt_interrupt_enter();
+
+    HAL_DCMI_IRQHandler(&rt_dcmi.DCMI_Handle);
+
+    /* leave interrupt */
+    rt_interrupt_leave();
+}
+
+void DCMI_Start(void)
+{
+    __HAL_DMA_ENABLE(&hdma_dcmi);
+    DCMI->CR |= DCMI_CR_CAPTURE;
+}
+
+void DCMI_Stop(void)
+{
+    DCMI->CR &= ~(DCMI_CR_CAPTURE);
+    while (DCMI->CR & 0x01);
+    __HAL_DMA_DISABLE(&hdma_dcmi);
+}
+
+/* Capture a frame of the image */
+void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
+{
+    extern void camera_frame_data_process(void);
+    /* enter interrupt */
+    rt_interrupt_enter();
+    /* move frame data to buffer */
+    camera_frame_data_process();
+
+    __HAL_DCMI_ENABLE_IT(&rt_dcmi.DCMI_Handle, DCMI_IT_FRAME);
+
+    /* leave interrupt */
+    rt_interrupt_leave();
+}
+
+void DMA2_Stream1_IRQHandler(void)
+{
+    extern void camera_dma_data_process(void);
+    /* enter interrupt */
+    rt_interrupt_enter();
+
+    if (__HAL_DMA_GET_FLAG(&hdma_dcmi, DMA_FLAG_TCIF1_5) != RESET)
+    {
+        __HAL_DMA_CLEAR_FLAG(&hdma_dcmi, DMA_FLAG_TCIF1_5);
+        /* move dma data to buffer */
+        camera_dma_data_process();
+    }
+
+    /* leave interrupt */
+    rt_interrupt_leave();
+}
+
+static rt_err_t rt_dcmi_init(rt_device_t dev)
+{
+    RT_ASSERT(dev != RT_NULL);
+    rt_err_t result = RT_EOK;
+
+    result = rt_hw_dcmi_init(&rt_dcmi.DCMI_Handle);
+    if (result != RT_EOK)
+    {
+        return result;
+    }
+
+    rt_hw_dcmi_dma_init();
+
+    return result;
+}
+
+static rt_err_t rt_dcmi_open(rt_device_t dev, rt_uint16_t oflag)
+{
+    RT_ASSERT(dev != RT_NULL);
+
+    return RT_EOK;
+}
+
+static rt_err_t rt_dcmi_close(rt_device_t dev)
+{
+    RT_ASSERT(dev != RT_NULL);
+
+    return RT_EOK;
+}
+
+static rt_err_t rt_dcmi_control(rt_device_t dev, int cmd, void *args)
+{
+    RT_ASSERT(dev != RT_NULL);
+
+    return RT_EOK;
+}
+
+static rt_size_t rt_dcmi_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+    RT_ASSERT(dev != RT_NULL);
+
+    return RT_EOK;
+}
+
+static rt_size_t rt_dcmi_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+    RT_ASSERT(dev != RT_NULL);
+
+    return RT_EOK;
+}
+
+int dcmi_init(void)
+{
+    rt_dcmi.dev.parent.type      = RT_Device_Class_Miscellaneous;
+    rt_dcmi.dev.parent.init      = rt_dcmi_init;
+    rt_dcmi.dev.parent.open      = rt_dcmi_open;
+    rt_dcmi.dev.parent.close     = rt_dcmi_close;
+    rt_dcmi.dev.parent.read      = rt_dcmi_read;
+    rt_dcmi.dev.parent.write     = rt_dcmi_write;
+    rt_dcmi.dev.parent.control   = rt_dcmi_control;
+    rt_dcmi.dev.parent.user_data = RT_NULL;
+
+    rt_device_register(&rt_dcmi.dev.parent, "dcmi", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
+
+    LOG_I("dcmi init success!");
+
+    return RT_EOK;
+}
+INIT_BOARD_EXPORT(dcmi_init);
+
+#endif

+ 34 - 0
bsp/stm32/stm32h743-atk-apollo/board/ports/drv_dcmi.h

@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author            Notes
+ * 2020-07-27     thread-liu        the first version
+ */
+
+#ifndef __DRV_DCMI_H__
+#define __DRV_DCMI_H__
+
+#include "board.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rt_dcmi_device
+{
+    struct rt_device parent;
+};
+
+extern DMA_HandleTypeDef hdma_dcmi;
+extern void rt_hw_dcmi_dma_config(rt_uint32_t dst_addr1, rt_uint32_t dst_addr2, rt_uint32_t len);
+extern void DCMI_Start(void);
+extern void DCMI_Stop(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 751 - 0
bsp/stm32/stm32h743-atk-apollo/board/ports/drv_ov2640.c

@@ -0,0 +1,751 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author            Notes
+ * 2020-08-03     thread-liu        the first version
+ */
+
+#include "board.h"
+
+#if defined(BSP_USING_OV2640)
+
+#include <dfs_posix.h>
+#include <drv_ov2640.h>
+#include <drv_dcmi.h>
+#include "pcf8574.h"
+
+#define DRV_DEBUG
+//#define CAMERA_DUMP
+#define LOG_TAG     "drv.ov2640"
+#include <drv_log.h>
+
+#define DEV_ADDRESS      0x30 /* OV2640 address */
+#define I2C_NAME        "i2c2"
+
+#define RESET_PIN        GET_PIN(A, 15) /* camera reset pin */
+
+/* camera PWDN pin */
+#define DCMI_PWDN_IO    2 /* pcf8574 (0-7) */
+
+volatile rt_uint32_t jpeg_data_len = 0;
+volatile rt_uint8_t  jpeg_data_ok  = 0;
+struct rt_i2c_bus_device *i2c_bus  = RT_NULL;
+
+#define JPEG_BUF_SIZE   32 * 1024
+#define JPEG_LINE_SIZE  1 * 1024
+
+static pcf8574_device_t pcf_dev = RT_NULL;
+   
+static rt_uint32_t *jpeg_data_buf = RT_NULL;
+static rt_uint32_t JPEG_LINE0_BUF[JPEG_LINE_SIZE];
+static rt_uint32_t JPEG_LINE1_BUF[JPEG_LINE_SIZE];
+
+#if defined(CAMERA_DUMP)
+#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
+static void dump_hex(const rt_uint8_t *ptr, rt_size_t buflen)
+{
+    unsigned char *buf = (unsigned char *)ptr;
+    int i, j;
+
+    for (i = 0; i < buflen; i += 16)
+    {
+        rt_kprintf("%08x:", i);
+
+        for (j = 0; j < 16; j++)
+        {
+            if (i + j < buflen)
+            {
+                rt_kprintf("%02x", buf[i + j]);
+            }
+            else
+            {
+                rt_kprintf(" ");
+            }
+        }
+        rt_kprintf(" ");
+
+        for (j = 0; j < 16; j++)
+        {
+            if (i + j < buflen)
+            {
+                rt_kprintf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
+            }
+        }
+        rt_kprintf("\n");
+    }
+}
+#endif
+
+static rt_err_t read_reg(struct rt_i2c_bus_device *bus, rt_uint8_t reg, rt_uint8_t len, rt_uint8_t *buf)
+{
+    struct rt_i2c_msg msg[2];
+
+    RT_ASSERT(bus != RT_NULL);
+
+    msg[0].addr  = DEV_ADDRESS;
+    msg[0].flags = RT_I2C_WR;
+    msg[0].buf   = &reg;
+    msg[0].len   = 2;
+
+    msg[1].addr  = DEV_ADDRESS;
+    msg[1].flags = RT_I2C_RD;
+    msg[1].len   = len;
+    msg[1].buf   = buf;
+
+    if (rt_i2c_transfer(bus, msg, 2) == 2)
+    {
+        return RT_EOK;
+    }
+
+    return RT_ERROR;
+}
+
+/* i2c write reg */
+static rt_err_t write_reg(struct rt_i2c_bus_device *bus, rt_uint8_t reg, rt_uint8_t data)
+{
+    rt_uint8_t buf[2];
+    struct rt_i2c_msg msgs;
+
+    RT_ASSERT(bus != RT_NULL);
+
+    buf[0] = reg ;
+    buf[1] = data;
+
+    msgs.addr = DEV_ADDRESS;
+    msgs.flags = RT_I2C_WR;
+    msgs.buf = buf;
+    msgs.len = 2;
+
+    if (rt_i2c_transfer(bus, &msgs, 1) == 1)
+    {
+        return RT_EOK;
+    }
+
+    return RT_ERROR;
+}
+
+static rt_err_t ov2640_read_id(struct rt_i2c_bus_device *bus)
+{
+    rt_uint8_t read_value[2];
+    rt_uint16_t id = 0;
+    read_reg(bus, OV2640_SENSOR_MIDH, 1, &read_value[0]);
+    read_reg(bus, OV2640_SENSOR_MIDL, 1, &read_value[1]);
+    id = ((rt_uint16_t)(read_value[0] << 8) & 0xFF00);
+    id |= ((rt_uint16_t)(read_value[1]) & 0x00FF);
+
+    if (id != OV2640_MID)
+    {
+        LOG_E("ov2640 init error, mid: 0x%04x", id);
+        return RT_ERROR;
+    }
+
+    LOG_I("ov2640 read mid success, mid: 0x%04x", id);
+
+    read_reg(bus, OV2640_SENSOR_PIDH, 1, &read_value[0]);
+    read_reg(bus, OV2640_SENSOR_PIDL, 1, &read_value[1]);
+    id = ((rt_uint16_t)(read_value[0] << 8) & 0xFF00);
+    id |= ((rt_uint16_t)(read_value[1]) & 0x00FF);
+
+    if (id != OV2640_PID)
+    {
+        LOG_E("ov2640 init error, pid: 0x%04x", id);
+        return RT_ERROR;
+    }
+
+    LOG_I("ov2640 read hid success, pid: 0x%04x", id);
+
+    return RT_EOK;
+}
+
+/* change ov2640 to jpeg mode */
+void ov2640_jpeg_mode(void)
+{
+    rt_uint16_t i=0;
+    /* set yun422 mode */
+    for (i = 0; i < (sizeof(ov2640_yuv422_reg_tbl) / 2); i++)
+    {
+        write_reg(i2c_bus, ov2640_yuv422_reg_tbl[i][0],ov2640_yuv422_reg_tbl[i][1]);
+    }
+
+    /* set jpeg mode */
+    for(i=0;i<(sizeof(ov2640_jpeg_reg_tbl)/2);i++)
+    {
+        write_reg(i2c_bus, ov2640_jpeg_reg_tbl[i][0],ov2640_jpeg_reg_tbl[i][1]);
+    }
+}
+
+/* change ov2640 to rgb565 mode */
+void ov2640_rgb565_mode(void)
+{
+    rt_uint16_t i=0;
+    for (i = 0; i < (sizeof(ov2640_rgb565_reg_tbl) / 2); i++)
+    {
+        write_reg(i2c_bus, ov2640_rgb565_reg_tbl[i][0],ov2640_rgb565_reg_tbl[i][1]);
+    }
+}
+
+/* set auto exposure */
+void ov2640_set_auto_exposure(rt_uint8_t level)
+{
+    rt_uint8_t i = 0;
+    rt_uint8_t *p = (rt_uint8_t*)OV2640_AUTOEXPOSURE_LEVEL[level];
+    for (i = 0; i < 4; i++)
+    {
+        write_reg(i2c_bus, p[i*2],p[i*2+1]);
+    }
+}
+
+/* set light mode
+ * 0: auto
+ * 1: sunny
+ * 2: cloudy
+ * 3: office
+ * 4: home
+ * */
+void ov2640_set_light_mode(rt_uint8_t mode)
+{
+    rt_uint8_t regccval, regcdval, regceval;
+
+    switch(mode)
+    {
+        case 0:
+            write_reg(i2c_bus, 0xFF, 0x00);
+            write_reg(i2c_bus, 0xC7, 0x10);
+            return;
+
+        case 2:
+            regccval = 0x65;
+            regcdval = 0x41;
+            regceval = 0x4F;
+            break;
+
+        case 3:
+            regccval = 0x52;
+            regcdval = 0x41;
+            regceval = 0x66;
+            break;
+
+        case 4:
+            regccval = 0x42;
+            regcdval = 0x3F;
+            regceval = 0x71;
+            break;
+
+        default:
+            regccval = 0x5E;
+            regcdval = 0x41;
+            regceval = 0x54;
+            break;
+    }
+
+    write_reg(i2c_bus, 0xFF, 0x00);
+    write_reg(i2c_bus, 0xC7, 0x40);
+    write_reg(i2c_bus, 0xCC, regccval);
+    write_reg(i2c_bus, 0xCD, regcdval);
+    write_reg(i2c_bus, 0xCE, regceval);
+}
+
+/* set color saturation
+ * 0: -2
+ * 1: -1
+ * 2: 0
+ * 3: +1
+ * 4: +2
+ * */
+void ov2640_set_color_saturation(rt_uint8_t sat)
+{
+    rt_uint8_t reg7dval = ((sat+2)<<4) | 0x08;
+    write_reg(i2c_bus, 0xFF, 0X00);
+    write_reg(i2c_bus, 0x7C, 0X00);
+    write_reg(i2c_bus, 0x7D, 0X02);
+    write_reg(i2c_bus, 0x7C, 0X03);
+    write_reg(i2c_bus, 0x7D, reg7dval);
+    write_reg(i2c_bus, 0x7D, reg7dval);
+}
+
+/* set brightness
+ * 0: -2
+ * 1: -1
+ * 2: 0
+ * 3: 1
+ * 4: 2
+ * */
+void ov2640_set_brightness(rt_uint8_t bright)
+{
+  write_reg(i2c_bus, 0xff, 0x00);
+  write_reg(i2c_bus, 0x7c, 0x00);
+  write_reg(i2c_bus, 0x7d, 0x04);
+  write_reg(i2c_bus, 0x7c, 0x09);
+  write_reg(i2c_bus, 0x7d, bright << 4);
+  write_reg(i2c_bus, 0x7d, 0x00);
+}
+
+/* set contrast
+ * 0: -2
+ * 1: -1
+ * 2: 0
+ * 3: 1
+ * 4: 2
+ * */
+void ov2640_set_contrast(rt_uint8_t contrast)
+{
+    rt_uint8_t reg7d0val, reg7d1val;
+
+    switch(contrast)
+    {
+        case 0:
+            reg7d0val = 0x18;
+            reg7d1val = 0x34;
+            break;
+
+        case 1:
+            reg7d0val = 0x1C;
+            reg7d1val = 0x2A;
+            break;
+
+        case 3:
+            reg7d0val = 0x24;
+            reg7d1val = 0x16;
+            break;
+
+        case 4:
+            reg7d0val = 0x28;
+            reg7d1val = 0x0C;
+            break;
+
+        default:
+            reg7d0val = 0x20;
+            reg7d1val = 0x20;
+            break;
+    }
+    write_reg(i2c_bus, 0xff, 0x00);
+    write_reg(i2c_bus, 0x7c, 0x00);
+    write_reg(i2c_bus, 0x7d, 0x04);
+    write_reg(i2c_bus, 0x7c, 0x07);
+    write_reg(i2c_bus, 0x7d, 0x20);
+    write_reg(i2c_bus, 0x7d, reg7d0val);
+    write_reg(i2c_bus, 0x7d, reg7d1val);
+    write_reg(i2c_bus, 0x7d, 0x06);
+}
+
+/* set special effects
+ * 0: noraml
+ * 1: negative film
+ * 2: black-and-white
+ * 3: the red
+ * 4: the green
+ * 5: the blue
+ * 6: Retro
+*/
+void ov2640_set_special_effects(rt_uint8_t eft)
+{
+    rt_uint8_t reg7d0val, reg7d1val, reg7d2val;
+
+    switch(eft)
+    {
+        case 1:
+            reg7d0val = 0x40;
+            break;
+        case 2:
+            reg7d0val = 0x18;
+            break;
+        case 3:
+            reg7d0val = 0x18;
+            reg7d1val = 0x40;
+            reg7d2val = 0xC0;
+            break;
+        case 4:
+            reg7d0val = 0x18;
+            reg7d1val = 0x40;
+            reg7d2val = 0x40;
+            break;
+        case 5:
+            reg7d0val = 0x18;
+            reg7d1val = 0xA0;
+            reg7d2val = 0x40;
+            break;
+        case 6:
+            reg7d0val = 0x18;
+            reg7d1val = 0x40;
+            reg7d2val = 0xA6;
+            break;
+        default:
+            reg7d0val = 0x00;
+            reg7d1val = 0x80;
+            reg7d2val = 0x80;
+            break;
+    }
+    write_reg(i2c_bus, 0xff, 0x00);
+    write_reg(i2c_bus, 0x7c, 0x00);
+    write_reg(i2c_bus, 0x7d, reg7d0val);
+    write_reg(i2c_bus, 0x7c, 0x05);
+    write_reg(i2c_bus, 0x7d, reg7d1val);
+    write_reg(i2c_bus, 0x7d, reg7d2val);
+}
+
+/* set the image output window */
+void ov2640_set_window_size(rt_uint16_t sx,rt_uint16_t sy,rt_uint16_t width,rt_uint16_t height)
+{
+    rt_uint16_t endx;
+    rt_uint16_t endy;
+    rt_uint8_t temp;
+    endx = sx + width / 2;
+    endy = sy + height / 2;
+
+    write_reg(i2c_bus, 0xFF, 0x01);
+    read_reg(i2c_bus, 0x03, 1, &temp);
+    temp &= 0xF0;
+    temp |= ((endy & 0x03) << 2) | (sy & 0x03);
+    write_reg(i2c_bus, 0x03, temp);
+    write_reg(i2c_bus, 0x19, sy>>2);
+    write_reg(i2c_bus, 0x1A, endy>>2);
+
+    read_reg(i2c_bus, 0x32, 1, &temp);
+    temp &= 0xC0;
+    temp |= ((endx & 0x07) << 3) | (sx & 0x07);
+    write_reg(i2c_bus, 0x32, temp);
+    write_reg(i2c_bus, 0x17, sx>>3);
+    write_reg(i2c_bus, 0x18, endx>>3);
+}
+
+/* set the image output size */
+rt_uint8_t ov2640_set_image_out_size(rt_uint16_t width,rt_uint16_t height)
+{
+    rt_uint16_t outh, outw;
+    rt_uint8_t temp;
+
+    if(width%4)return 1;
+    if(height%4)return 2;
+    outw = width / 4;
+    outh = height / 4;
+    write_reg(i2c_bus, 0xFF, 0x00);
+    write_reg(i2c_bus, 0xE0, 0x04);
+    write_reg(i2c_bus, 0x5A, outw & 0XFF);
+    write_reg(i2c_bus, 0x5B, outh & 0XFF);
+    temp = (outw >> 8) & 0x03;
+    temp |= (outh >> 6) & 0x04;
+    write_reg(i2c_bus, 0x5C, temp);
+    write_reg(i2c_bus, 0xE0, 0X00);
+
+    return RT_EOK;
+}
+
+/* set the image window size */
+rt_uint8_t ov2640_set_image_window_size(rt_uint16_t offx, rt_uint16_t offy, rt_uint16_t width, rt_uint16_t height)
+{
+    rt_uint16_t hsize, vsize;
+    rt_uint8_t temp;
+    if ((width % 4) || (height%4))
+    {
+        return RT_ERROR;
+    }
+    hsize = width / 4;
+    vsize = height / 4;
+   write_reg(i2c_bus, 0XFF,0X00);
+   write_reg(i2c_bus, 0XE0,0X04);
+   write_reg(i2c_bus, 0X51,hsize&0XFF);
+   write_reg(i2c_bus, 0X52,vsize&0XFF);
+   write_reg(i2c_bus, 0X53,offx&0XFF);
+   write_reg(i2c_bus, 0X54,offy&0XFF);
+   temp=(vsize>>1)&0X80;
+   temp|=(offy>>4)&0X70;
+   temp|=(hsize>>5)&0X08;
+   temp|=(offx>>8)&0X07;
+   write_reg(i2c_bus, 0X55,temp); 
+   write_reg(i2c_bus, 0X57,(hsize>>2)&0X80);
+   write_reg(i2c_bus, 0XE0,0X00);
+   return 0;
+}
+
+/* set output resolution */
+rt_uint8_t ov2640_set_image_size(rt_uint16_t width ,rt_uint16_t height)
+{
+   rt_uint8_t temp;
+   write_reg(i2c_bus, 0xFF, 0x00);
+   write_reg(i2c_bus, 0xE0, 0x04);
+   write_reg(i2c_bus, 0xC0, (width >>3) & 0xFF);
+   write_reg(i2c_bus, 0xC1, (height >> 3) & 0xFF);
+   temp = (width & 0x07) << 3;
+   temp |= height & 0x07;
+   temp |= (width >> 4) & 0x80;
+   write_reg(i2c_bus, 0x8C, temp);
+   write_reg(i2c_bus, 0xE0, 0x00);
+
+   return RT_EOK;
+}
+
+void camera_dma_data_process(void)
+{
+   rt_uint16_t i;
+   rt_uint32_t *pbuf;
+   pbuf = jpeg_data_buf + jpeg_data_len;
+
+   if (DMA2_Stream1->CR & (1<<19))
+   {
+       for (i = 0; i < JPEG_LINE_SIZE; i++)
+       {
+           pbuf[i] = JPEG_LINE0_BUF[i];
+       }
+       jpeg_data_len += JPEG_LINE_SIZE;
+   }
+   else
+   {
+       for (i = 0; i < JPEG_LINE_SIZE; i++)
+       {
+           pbuf[i] = JPEG_LINE1_BUF[i];
+       }
+       jpeg_data_len += JPEG_LINE_SIZE;
+   }
+   SCB_CleanInvalidateDCache();
+}
+
+/* After a frame of picture data has been collected. */
+void camera_frame_data_process(void)
+{
+   rt_uint16_t i, rlen;
+   rt_uint32_t *pbuf = RT_NULL;
+
+   if (jpeg_data_ok == 0)
+   {
+       DMA2_Stream1->CR &= ~(1<<0);
+       while(DMA2_Stream1->CR & 0x01);
+
+       rlen = JPEG_LINE_SIZE - DMA2_Stream1->NDTR;
+       pbuf = jpeg_data_buf + jpeg_data_len;
+
+       if (DMA2_Stream1->CR & (1<<19))
+       {
+           for (i = 0; i < rlen; i++)
+           {
+               pbuf[i] = JPEG_LINE1_BUF[i];
+           }
+       }
+       else
+       {
+           for (i = 0; i < rlen; i++)
+           {
+               pbuf[i] = JPEG_LINE0_BUF[i];
+           }
+       }
+       jpeg_data_len += rlen;
+       jpeg_data_ok   = 1;
+   }
+   if (jpeg_data_ok==2)
+   {
+       DMA2_Stream1->NDTR = JPEG_LINE_SIZE;
+       DMA2_Stream1->CR  |= 1<<0;
+       jpeg_data_ok  = 0;
+       jpeg_data_len = 0;
+   }
+}
+
+int ov2640_pwdn_set(rt_uint8_t sta)
+{
+    if (pcf_dev == RT_NULL)
+    {
+       LOG_E("can't find pcf8574 device!");
+        return -1;
+    }
+    pcf8574_pin_write(pcf_dev, DCMI_PWDN_IO, sta);
+    
+    return 0;
+}
+
+void sw_ov2640_mode(void)
+{  
+    GPIO_InitTypeDef GPIO_Initure = {0};
+    
+    ov2640_pwdn_set(0);
+    
+    GPIO_Initure.Pin       = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_11;  
+    GPIO_Initure.Mode      = GPIO_MODE_AF_PP; 
+    GPIO_Initure.Pull      = GPIO_PULLUP;     
+    GPIO_Initure.Speed     = GPIO_SPEED_HIGH; 
+    GPIO_Initure.Alternate = GPIO_AF13_DCMI;    
+    HAL_GPIO_Init(GPIOC,&GPIO_Initure);  
+} 
+
+void sw_sdcard_mode(void)
+{
+    GPIO_InitTypeDef GPIO_Initure = {0};
+    
+    ov2640_pwdn_set(1); /* OV2640 Power Down */ 
+
+    GPIO_Initure.Pin       = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_11;  
+    GPIO_Initure.Mode      = GPIO_MODE_AF_PP; 
+    GPIO_Initure.Pull      = GPIO_PULLUP;
+    GPIO_Initure.Speed     = GPIO_SPEED_HIGH; 
+    GPIO_Initure.Alternate = GPIO_AF12_SDMMC1;   
+    HAL_GPIO_Init(GPIOC, &GPIO_Initure);   
+}
+
+int rt_ov2640_init(void)
+{
+    rt_uint16_t i = 0;
+    rt_err_t result = RT_EOK;
+    rt_device_t dcmi_dev = RT_NULL;
+    
+    sw_ov2640_mode();
+    pcf_dev = pcf8574_init("i2c1", RT_NULL);
+    if (pcf_dev == RT_NULL)
+    {
+        LOG_E("can't find pcf8574, please check it");
+        return -RT_ERROR;
+    }
+    
+    ov2640_pwdn_set(0);
+	rt_thread_delay(20);
+    
+    /* ov2640 hard reset */
+    rt_pin_mode(RESET_PIN, PIN_MODE_OUTPUT);
+    rt_pin_write(RESET_PIN, PIN_LOW);
+    rt_thread_delay(20);
+    rt_pin_write(RESET_PIN, PIN_HIGH);
+    rt_thread_delay(20);
+    
+    i2c_bus = rt_i2c_bus_device_find(I2C_NAME);
+    if (i2c_bus == RT_NULL)
+    {
+        LOG_E("can't find %s deivce", I2C_NAME);
+        return RT_ERROR;
+    }
+    /* Prepare the camera to be configured */
+    result = write_reg(i2c_bus, OV2640_DSP_RA_DLMT, 0x01);
+    if (result != RT_EOK )
+    {
+        LOG_E("ov2640 write reg error!");
+        return RT_ERROR;
+    }
+    rt_thread_delay(10);
+    result = write_reg(i2c_bus, OV2640_SENSOR_COM7, 0x80);
+    if (result != RT_EOK)
+    {
+        LOG_E("ov2640 soft reset error!");
+        return RT_ERROR;
+    }
+    rt_thread_delay(20);
+
+    result = ov2640_read_id(i2c_bus);
+    if (result != RT_EOK )
+    {
+        LOG_E("ov2640 read id error!");
+        return RT_ERROR;
+    }
+
+    for (i = 0; i < sizeof(ov2640_svga_init_reg_tbl) / 2; i++)
+    {
+        write_reg(i2c_bus, ov2640_svga_init_reg_tbl[i][0], ov2640_svga_init_reg_tbl[i][1]);
+    }
+
+    ov2640_rgb565_mode();
+    ov2640_set_light_mode(0);
+    ov2640_set_color_saturation(3);
+    ov2640_set_brightness(4);
+    ov2640_set_contrast(3);
+    ov2640_jpeg_mode();
+    ov2640_set_image_window_size(0, 0, 320, 240);
+    ov2640_set_image_out_size(320, 240);
+
+    dcmi_dev = rt_device_find("dcmi");
+    if (dcmi_dev == RT_NULL)
+    {
+        LOG_E("can't find dcmi device!");
+        return RT_ERROR;
+    }
+    rt_device_open(dcmi_dev, RT_DEVICE_FLAG_RDWR);
+
+   jpeg_data_buf = rt_malloc(JPEG_BUF_SIZE);
+   if (RT_NULL == jpeg_data_buf)
+   {
+       rt_kprintf("jpeg data buf malloc error!\n");
+       return RT_ERROR;
+   }
+
+    /* start dcmi capture */
+    rt_hw_dcmi_dma_config((rt_uint32_t)JPEG_LINE0_BUF, (rt_uint32_t)JPEG_LINE1_BUF, JPEG_LINE_SIZE);
+
+    rt_kprintf("camera init success!\n");
+
+    return RT_EOK;
+}
+INIT_APP_EXPORT(rt_ov2640_init);
+
+int camera_sample(int argc, char **argv)
+{
+   rt_err_t result = RT_EOK;
+   int fd = -1;
+   rt_uint32_t i, jpg_start, jpg_len;
+   rt_uint8_t jpg_head = 0;
+   rt_uint8_t *p = RT_NULL;
+
+   if (argc != 2)
+   {
+       rt_kprintf("Usage:\n");
+       rt_kprintf("camera_sample file.jpg\n");
+       return -1;
+   }
+   
+   sw_ov2640_mode();
+   DCMI_Start();
+
+   while (1)
+   {
+       while (jpeg_data_ok != 1);
+       jpeg_data_ok = 2;
+       while (jpeg_data_ok != 1);
+       DCMI_Stop();
+
+       p = (rt_uint8_t *)jpeg_data_buf;
+       jpg_len  = 0;
+       jpg_head = 0;
+       for (i = 0; i < jpeg_data_len * 4; i++)
+       {
+           /* jpg head */
+           if ((p[i] == 0xFF) && (p[i + 1] == 0xD8))
+           {
+               jpg_start = i;
+               jpg_head = 1;
+           }
+           /* jpg end */
+           if ((p[i] == 0xFF) && (p[i + 1] == 0xD9) && jpg_head)
+           {
+               jpg_len = i - jpg_start + 2; /* a picture len */
+               break;
+           }
+       }
+       if (jpg_len)
+       {
+           p += jpg_start;
+           sw_sdcard_mode();
+           fd = open(argv[1], O_WRONLY | O_CREAT);
+           if (fd < 0)
+           {
+               rt_kprintf("open file for recording failed!\n");
+               result = -RT_ERROR;
+               goto _exit;
+           }
+           else
+           {
+               write(fd, p, jpg_len);
+               close(fd);
+               rt_kprintf("%s picture capture complate!\n", argv[1]);
+               break;
+           }
+       }
+       else
+       {
+           rt_kprintf("jpg_len error!\n");
+           result = -RT_ERROR;
+           goto _exit;
+       }
+   }
+
+_exit:
+    return result;;
+}
+MSH_CMD_EXPORT(camera_sample, record picture to a jpg file);
+
+#endif

+ 778 - 0
bsp/stm32/stm32h743-atk-apollo/board/ports/drv_ov2640.h

@@ -0,0 +1,778 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-07-27     thread-liu   first version
+ */
+
+#ifndef __DRV_OV2640_H__
+#define __DRV_OV2640_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <board.h>
+
+#define OV2640_MID              0X7FA2
+#define OV2640_PID              0X2642
+
+
+//褰撻�夋嫨DSP鍦板潃(0XFF=0X00)鏃�,OV2640鐨凞SP瀵勫瓨鍣ㄥ湴鍧�鏄犲皠琛�
+#define OV2640_DSP_R_BYPASS     0x05
+#define OV2640_DSP_Qs           0x44
+#define OV2640_DSP_CTRL         0x50
+#define OV2640_DSP_HSIZE1       0x51
+#define OV2640_DSP_VSIZE1       0x52
+#define OV2640_DSP_XOFFL        0x53
+#define OV2640_DSP_YOFFL        0x54
+#define OV2640_DSP_VHYX         0x55
+#define OV2640_DSP_DPRP         0x56
+#define OV2640_DSP_TEST         0x57
+#define OV2640_DSP_ZMOW         0x5A
+#define OV2640_DSP_ZMOH         0x5B
+#define OV2640_DSP_ZMHH         0x5C
+#define OV2640_DSP_BPADDR       0x7C
+#define OV2640_DSP_BPDATA       0x7D
+#define OV2640_DSP_CTRL2        0x86
+#define OV2640_DSP_CTRL3        0x87
+#define OV2640_DSP_SIZEL        0x8C
+#define OV2640_DSP_HSIZE2       0xC0
+#define OV2640_DSP_VSIZE2       0xC1
+#define OV2640_DSP_CTRL0        0xC2
+#define OV2640_DSP_CTRL1        0xC3
+#define OV2640_DSP_R_DVP_SP     0xD3
+#define OV2640_DSP_IMAGE_MODE   0xDA
+#define OV2640_DSP_RESET        0xE0
+#define OV2640_DSP_MS_SP        0xF0
+#define OV2640_DSP_SS_ID        0x7F
+#define OV2640_DSP_SS_CTRL      0xF8
+#define OV2640_DSP_MC_BIST      0xF9
+#define OV2640_DSP_MC_AL        0xFA
+#define OV2640_DSP_MC_AH        0xFB
+#define OV2640_DSP_MC_D         0xFC
+#define OV2640_DSP_P_STATUS     0xFE
+#define OV2640_DSP_RA_DLMT      0xFF
+
+//褰撻�夋嫨浼犳劅鍣ㄥ湴鍧�(0XFF=0X01)鏃�,OV2640鐨凞SP瀵勫瓨鍣ㄥ湴鍧�鏄犲皠琛�
+#define OV2640_SENSOR_GAIN       0x00
+#define OV2640_SENSOR_COM1       0x03
+#define OV2640_SENSOR_REG04      0x04
+#define OV2640_SENSOR_REG08      0x08
+#define OV2640_SENSOR_COM2       0x09
+#define OV2640_SENSOR_PIDH       0x0A
+#define OV2640_SENSOR_PIDL       0x0B
+#define OV2640_SENSOR_COM3       0x0C
+#define OV2640_SENSOR_COM4       0x0D
+#define OV2640_SENSOR_AEC        0x10
+#define OV2640_SENSOR_CLKRC      0x11
+#define OV2640_SENSOR_COM7       0x12
+#define OV2640_SENSOR_COM8       0x13
+#define OV2640_SENSOR_COM9       0x14
+#define OV2640_SENSOR_COM10      0x15
+#define OV2640_SENSOR_HREFST     0x17
+#define OV2640_SENSOR_HREFEND    0x18
+#define OV2640_SENSOR_VSTART     0x19
+#define OV2640_SENSOR_VEND       0x1A
+#define OV2640_SENSOR_MIDH       0x1C
+#define OV2640_SENSOR_MIDL       0x1D
+#define OV2640_SENSOR_AEW        0x24
+#define OV2640_SENSOR_AEB        0x25
+#define OV2640_SENSOR_W          0x26
+#define OV2640_SENSOR_REG2A      0x2A
+#define OV2640_SENSOR_FRARL      0x2B
+#define OV2640_SENSOR_ADDVSL     0x2D
+#define OV2640_SENSOR_ADDVHS     0x2E
+#define OV2640_SENSOR_YAVG       0x2F
+#define OV2640_SENSOR_REG32      0x32
+#define OV2640_SENSOR_ARCOM2     0x34
+#define OV2640_SENSOR_REG45      0x45
+#define OV2640_SENSOR_FLL        0x46
+#define OV2640_SENSOR_FLH        0x47
+#define OV2640_SENSOR_COM19      0x48
+#define OV2640_SENSOR_ZOOMS      0x49
+#define OV2640_SENSOR_COM22      0x4B
+#define OV2640_SENSOR_COM25      0x4E
+#define OV2640_SENSOR_BD50       0x4F
+#define OV2640_SENSOR_BD60       0x50
+#define OV2640_SENSOR_REG5D      0x5D
+#define OV2640_SENSOR_REG5E      0x5E
+#define OV2640_SENSOR_REG5F      0x5F
+#define OV2640_SENSOR_REG60      0x60
+#define OV2640_SENSOR_HISTO_LOW  0x61
+#define OV2640_SENSOR_HISTO_HIGH 0x62
+
+/* Automatic exposure setting parameters table, support 5 levels */
+const rt_uint8_t OV2640_AUTOEXPOSURE_LEVEL[5][8]=
+{
+    {
+        0xFF,0x01,
+        0x24,0x20,
+        0x25,0x18,
+        0x26,0x60,
+    },
+    {
+        0xFF,0x01,
+        0x24,0x34,
+        0x25,0x1c,
+        0x26,0x00,
+    },
+    {
+        0xFF,0x01,
+        0x24,0x3e,
+        0x25,0x38,
+        0x26,0x81,
+    },
+    {
+        0xFF,0x01,
+        0x24,0x48,
+        0x25,0x40,
+        0x26,0x81,
+    },
+    {
+        0xFF,0x01,
+        0x24,0x58,
+        0x25,0x50,
+        0x26,0x92,
+    },
+};
+
+const rt_uint8_t ov2640_sxga_init_reg_tbl[][2]=
+{
+    {0xff, 0x00},
+    {0x2c, 0xff},
+    {0x2e, 0xdf},
+    {0xff, 0x01},
+    {0x3c, 0x32},
+    {0x11, 0x00},
+    {0x09, 0x02},
+    {0x04, 0xD8},
+    {0x13, 0xe5},
+    {0x14, 0x48},
+    {0x2c, 0x0c},
+    {0x33, 0x78},
+    {0x3a, 0x33},
+    {0x3b, 0xfB},
+    {0x3e, 0x00},
+    {0x43, 0x11},
+    {0x16, 0x10},
+    {0x39, 0x92},
+    {0x35, 0xda},
+    {0x22, 0x1a},
+    {0x37, 0xc3},
+    {0x23, 0x00},
+    {0x34, 0xc0},
+    {0x36, 0x1a},
+    {0x06, 0x88},
+    {0x07, 0xc0},
+    {0x0d, 0x87},
+    {0x0e, 0x41},
+    {0x4c, 0x00},
+    {0x48, 0x00},
+    {0x5B, 0x00},
+    {0x42, 0x03},
+    {0x4a, 0x81},
+    {0x21, 0x99},
+    {0x24, 0x40},
+    {0x25, 0x38},
+    {0x26, 0x82},
+    {0x5c, 0x00},
+    {0x63, 0x00},
+    {0x46, 0x00},
+    {0x0c, 0x3c},
+    {0x61, 0x70},
+    {0x62, 0x80},
+    {0x7c, 0x05},
+    {0x20, 0x80},
+    {0x28, 0x30},
+    {0x6c, 0x00},
+    {0x6d, 0x80},
+    {0x6e, 0x00},
+    {0x70, 0x02},
+    {0x71, 0x94},
+    {0x73, 0xc1},
+    {0x3d, 0x34},
+    {0x5a, 0x57},
+    {0x12, 0x00},
+    {0x17, 0x11},
+    {0x18, 0x75},
+    {0x19, 0x01},
+    {0x1a, 0x97},
+    {0x32, 0x36},
+    {0x03, 0x0f},
+    {0x37, 0x40},
+    {0x4f, 0xca},
+    {0x50, 0xa8},
+    {0x5a, 0x23},
+    {0x6d, 0x00},
+    {0x6d, 0x38},
+    {0xff, 0x00},
+    {0xe5, 0x7f},
+    {0xf9, 0xc0},
+    {0x41, 0x24},
+    {0xe0, 0x14},
+    {0x76, 0xff},
+    {0x33, 0xa0},
+    {0x42, 0x20},
+    {0x43, 0x18},
+    {0x4c, 0x00},
+    {0x87, 0xd5},
+    {0x88, 0x3f},
+    {0xd7, 0x03},
+    {0xd9, 0x10},
+    {0xd3, 0x82},
+    {0xc8, 0x08},
+    {0xc9, 0x80},
+    {0x7c, 0x00},
+    {0x7d, 0x00},
+    {0x7c, 0x03},
+    {0x7d, 0x48},
+    {0x7d, 0x48},
+    {0x7c, 0x08},
+    {0x7d, 0x20},
+    {0x7d, 0x10},
+    {0x7d, 0x0e},
+    {0x90, 0x00},
+    {0x91, 0x0e},
+    {0x91, 0x1a},
+    {0x91, 0x31},
+    {0x91, 0x5a},
+    {0x91, 0x69},
+    {0x91, 0x75},
+    {0x91, 0x7e},
+    {0x91, 0x88},
+    {0x91, 0x8f},
+    {0x91, 0x96},
+    {0x91, 0xa3},
+    {0x91, 0xaf},
+    {0x91, 0xc4},
+    {0x91, 0xd7},
+    {0x91, 0xe8},
+    {0x91, 0x20},
+    {0x92, 0x00},
+    {0x93, 0x06},
+    {0x93, 0xe3},
+    {0x93, 0x05},
+    {0x93, 0x05},
+    {0x93, 0x00},
+    {0x93, 0x04},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x96, 0x00},
+    {0x97, 0x08},
+    {0x97, 0x19},
+    {0x97, 0x02},
+    {0x97, 0x0c},
+    {0x97, 0x24},
+    {0x97, 0x30},
+    {0x97, 0x28},
+    {0x97, 0x26},
+    {0x97, 0x02},
+    {0x97, 0x98},
+    {0x97, 0x80},
+    {0x97, 0x00},
+    {0x97, 0x00},
+    {0xc3, 0xef},
+    {0xa4, 0x00},
+    {0xa8, 0x00},
+    {0xc5, 0x11},
+    {0xc6, 0x51},
+    {0xbf, 0x80},
+    {0xc7, 0x10},
+    {0xb6, 0x66},
+    {0xb8, 0xA5},
+    {0xb7, 0x64},
+    {0xb9, 0x7C},
+    {0xb3, 0xaf},
+    {0xb4, 0x97},
+    {0xb5, 0xFF},
+    {0xb0, 0xC5},
+    {0xb1, 0x94},
+    {0xb2, 0x0f},
+    {0xc4, 0x5c},
+    {0xc0, 0xc8},
+    {0xc1, 0x96},
+    {0x8c, 0x00},
+    {0x86, 0x3d},
+    {0x50, 0x00},
+    {0x51, 0x90},
+    {0x52, 0x2c},
+    {0x53, 0x00},
+    {0x54, 0x00},
+    {0x55, 0x88},
+    {0x5a, 0x90},
+    {0x5b, 0x2C},
+    {0x5c, 0x05},
+    {0xd3, 0x02},
+    {0xc3, 0xed},
+    {0x7f, 0x00},
+    {0xda, 0x09},
+    {0xe5, 0x1f},
+    {0xe1, 0x67},
+    {0xe0, 0x00},
+    {0xdd, 0x7f},
+    {0x05, 0x00},
+};
+
+/* SVGA 800*600 */
+const rt_uint8_t ov2640_svga_init_reg_tbl[][2]=
+{
+    {0xff, 0x00},
+    {0x2c, 0xff},
+    {0x2e, 0xdf},
+    {0xff, 0x01},
+    {0x3c, 0x32},
+    {0x11, 0x00},
+    {0x09, 0x02},
+    {0x04, 0xD8},
+    {0x13, 0xe5},
+    {0x14, 0x48},
+    {0x2c, 0x0c},
+    {0x33, 0x78},
+    {0x3a, 0x33},
+    {0x3b, 0xfB},
+    {0x3e, 0x00},
+    {0x43, 0x11},
+    {0x16, 0x10},
+    {0x39, 0x92},
+    {0x35, 0xda},
+    {0x22, 0x1a},
+    {0x37, 0xc3},
+    {0x23, 0x00},
+    {0x34, 0xc0},
+    {0x36, 0x1a},
+    {0x06, 0x88},
+    {0x07, 0xc0},
+    {0x0d, 0x87},
+    {0x0e, 0x41},
+    {0x4c, 0x00},
+    {0x48, 0x00},
+    {0x5B, 0x00},
+    {0x42, 0x03},
+    {0x4a, 0x81},
+    {0x21, 0x99},
+    {0x24, 0x40},
+    {0x25, 0x38},
+    {0x26, 0x82},
+    {0x5c, 0x00},
+    {0x63, 0x00},
+    {0x46, 0x22},
+    {0x0c, 0x3c},
+    {0x61, 0x70},
+    {0x62, 0x80},
+    {0x7c, 0x05},
+    {0x20, 0x80},
+    {0x28, 0x30},
+    {0x6c, 0x00},
+    {0x6d, 0x80},
+    {0x6e, 0x00},
+    {0x70, 0x02},
+    {0x71, 0x94},
+    {0x73, 0xc1},
+    {0x3d, 0x34},
+    {0x5a, 0x57},
+    {0x12, 0x40},
+    {0x17, 0x11},
+    {0x18, 0x43},
+    {0x19, 0x00},
+    {0x1a, 0x4b},
+    {0x32, 0x09},
+    {0x37, 0xc0},
+    {0x4f, 0xca},
+    {0x50, 0xa8},
+    {0x5a, 0x23},
+    {0x6d, 0x00},
+    {0x3d, 0x38},
+    {0xff, 0x00},
+    {0xe5, 0x7f},
+    {0xf9, 0xc0},
+    {0x41, 0x24},
+    {0xe0, 0x14},
+    {0x76, 0xff},
+    {0x33, 0xa0},
+    {0x42, 0x20},
+    {0x43, 0x18},
+    {0x4c, 0x00},
+    {0x87, 0xd5},
+    {0x88, 0x3f},
+    {0xd7, 0x03},
+    {0xd9, 0x10},
+    {0xd3, 0x82},
+    {0xc8, 0x08},
+    {0xc9, 0x80},
+    {0x7c, 0x00},
+    {0x7d, 0x00},
+    {0x7c, 0x03},
+    {0x7d, 0x48},
+    {0x7d, 0x48},
+    {0x7c, 0x08},
+    {0x7d, 0x20},
+    {0x7d, 0x10},
+    {0x7d, 0x0e},
+    {0x90, 0x00},
+    {0x91, 0x0e},
+    {0x91, 0x1a},
+    {0x91, 0x31},
+    {0x91, 0x5a},
+    {0x91, 0x69},
+    {0x91, 0x75},
+    {0x91, 0x7e},
+    {0x91, 0x88},
+    {0x91, 0x8f},
+    {0x91, 0x96},
+    {0x91, 0xa3},
+    {0x91, 0xaf},
+    {0x91, 0xc4},
+    {0x91, 0xd7},
+    {0x91, 0xe8},
+    {0x91, 0x20},
+    {0x92, 0x00},
+    {0x93, 0x06},
+    {0x93, 0xe3},
+    {0x93, 0x05},
+    {0x93, 0x05},
+    {0x93, 0x00},
+    {0x93, 0x04},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x96, 0x00},
+    {0x97, 0x08},
+    {0x97, 0x19},
+    {0x97, 0x02},
+    {0x97, 0x0c},
+    {0x97, 0x24},
+    {0x97, 0x30},
+    {0x97, 0x28},
+    {0x97, 0x26},
+    {0x97, 0x02},
+    {0x97, 0x98},
+    {0x97, 0x80},
+    {0x97, 0x00},
+    {0x97, 0x00},
+    {0xc3, 0xed},
+    {0xa4, 0x00},
+    {0xa8, 0x00},
+    {0xc5, 0x11},
+    {0xc6, 0x51},
+    {0xbf, 0x80},
+    {0xc7, 0x10},
+    {0xb6, 0x66},
+    {0xb8, 0xA5},
+    {0xb7, 0x64},
+    {0xb9, 0x7C},
+    {0xb3, 0xaf},
+    {0xb4, 0x97},
+    {0xb5, 0xFF},
+    {0xb0, 0xC5},
+    {0xb1, 0x94},
+    {0xb2, 0x0f},
+    {0xc4, 0x5c},
+    {0xc0, 0x64},
+    {0xc1, 0x4B},
+    {0x8c, 0x00},
+    {0x86, 0x3D},
+    {0x50, 0x00},
+    {0x51, 0xC8},
+    {0x52, 0x96},
+    {0x53, 0x00},
+    {0x54, 0x00},
+    {0x55, 0x00},
+    {0x5a, 0xC8},
+    {0x5b, 0x96},
+    {0x5c, 0x00},
+    {0xd3, 0x02},
+    {0xc3, 0xed},
+    {0x7f, 0x00},
+    {0xda, 0x09},
+    {0xe5, 0x1f},
+    {0xe1, 0x67},
+    {0xe0, 0x00},
+    {0xdd, 0x7f},
+    {0x05, 0x00},
+};
+
+/* Initialization sequence for QVGA resolution (320x240) */
+const unsigned char OV2640_QVGA[][2]=
+{
+    {0xff, 0x00},
+    {0x2c, 0xff},
+    {0x2e, 0xdf},
+    {0xff, 0x01},
+    {0x3c, 0x32},
+    {0x11, 0x00},
+    {0x09, 0x02},
+    {0x04, 0xA8},
+    {0x13, 0xe5},
+    {0x14, 0x48},
+    {0x2c, 0x0c},
+    {0x33, 0x78},
+    {0x3a, 0x33},
+    {0x3b, 0xfB},
+    {0x3e, 0x00},
+    {0x43, 0x11},
+    {0x16, 0x10},
+    {0x4a, 0x81},
+    {0x21, 0x99},
+    {0x24, 0x40},
+    {0x25, 0x38},
+    {0x26, 0x82},
+    {0x5c, 0x00},
+    {0x63, 0x00},
+    {0x46, 0x3f},
+    {0x0c, 0x3c},
+    {0x61, 0x70},
+    {0x62, 0x80},
+    {0x7c, 0x05},
+    {0x20, 0x80},
+    {0x28, 0x30},
+    {0x6c, 0x00},
+    {0x6d, 0x80},
+    {0x6e, 0x00},
+    {0x70, 0x02},
+    {0x71, 0x94},
+    {0x73, 0xc1},
+    {0x3d, 0x34},
+    {0x5a, 0x57},
+    {0x12, 0x00},
+    {0x11, 0x00},
+    {0x17, 0x11},
+    {0x18, 0x75},
+    {0x19, 0x01},
+    {0x1a, 0x97},
+    {0x32, 0x36},
+    {0x03, 0x0f},
+    {0x37, 0x40},
+    {0x4f, 0xbb},
+    {0x50, 0x9c},
+    {0x5a, 0x57},
+    {0x6d, 0x80},
+    {0x6d, 0x38},
+    {0x39, 0x02},
+    {0x35, 0x88},
+    {0x22, 0x0a},
+    {0x37, 0x40},
+    {0x23, 0x00},
+    {0x34, 0xa0},
+    {0x36, 0x1a},
+    {0x06, 0x02},
+    {0x07, 0xc0},
+    {0x0d, 0xb7},
+    {0x0e, 0x01},
+    {0x4c, 0x00},
+    {0xff, 0x00},
+    {0xe5, 0x7f},
+    {0xf9, 0xc0},
+    {0x41, 0x24},
+    {0xe0, 0x14},
+    {0x76, 0xff},
+    {0x33, 0xa0},
+    {0x42, 0x20},
+    {0x43, 0x18},
+    {0x4c, 0x00},
+    {0x87, 0xd0},
+    {0x88, 0x3f},
+    {0xd7, 0x03},
+    {0xd9, 0x10},
+    {0xd3, 0x82},
+    {0xc8, 0x08},
+    {0xc9, 0x80},
+    {0x7d, 0x00},
+    {0x7c, 0x03},
+    {0x7d, 0x48},
+    {0x7c, 0x08},
+    {0x7d, 0x20},
+    {0x7d, 0x10},
+    {0x7d, 0x0e},
+    {0x90, 0x00},
+    {0x91, 0x0e},
+    {0x91, 0x1a},
+    {0x91, 0x31},
+    {0x91, 0x5a},
+    {0x91, 0x69},
+    {0x91, 0x75},
+    {0x91, 0x7e},
+    {0x91, 0x88},
+    {0x91, 0x8f},
+    {0x91, 0x96},
+    {0x91, 0xa3},
+    {0x91, 0xaf},
+    {0x91, 0xc4},
+    {0x91, 0xd7},
+    {0x91, 0xe8},
+    {0x91, 0x20},
+    {0x92, 0x00},
+    {0x93, 0x06},
+    {0x93, 0xe3},
+    {0x93, 0x02},
+    {0x93, 0x02},
+    {0x93, 0x00},
+    {0x93, 0x04},
+    {0x93, 0x00},
+    {0x93, 0x03},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x96, 0x00},
+    {0x97, 0x08},
+    {0x97, 0x19},
+    {0x97, 0x02},
+    {0x97, 0x0c},
+    {0x97, 0x24},
+    {0x97, 0x30},
+    {0x97, 0x28},
+    {0x97, 0x26},
+    {0x97, 0x02},
+    {0x97, 0x98},
+    {0x97, 0x80},
+    {0x97, 0x00},
+    {0x97, 0x00},
+    {0xc3, 0xef},
+    {0xff, 0x00},
+    {0xba, 0xdc},
+    {0xbb, 0x08},
+    {0xb6, 0x24},
+    {0xb8, 0x33},
+    {0xb7, 0x20},
+    {0xb9, 0x30},
+    {0xb3, 0xb4},
+    {0xb4, 0xca},
+    {0xb5, 0x43},
+    {0xb0, 0x5c},
+    {0xb1, 0x4f},
+    {0xb2, 0x06},
+    {0xc7, 0x00},
+    {0xc6, 0x51},
+    {0xc5, 0x11},
+    {0xc4, 0x9c},
+    {0xbf, 0x00},
+    {0xbc, 0x64},
+    {0xa6, 0x00},
+    {0xa7, 0x1e},
+    {0xa7, 0x6b},
+    {0xa7, 0x47},
+    {0xa7, 0x33},
+    {0xa7, 0x00},
+    {0xa7, 0x23},
+    {0xa7, 0x2e},
+    {0xa7, 0x85},
+    {0xa7, 0x42},
+    {0xa7, 0x33},
+    {0xa7, 0x00},
+    {0xa7, 0x23},
+    {0xa7, 0x1b},
+    {0xa7, 0x74},
+    {0xa7, 0x42},
+    {0xa7, 0x33},
+    {0xa7, 0x00},
+    {0xa7, 0x23},
+    {0xc0, 0xc8},
+    {0xc1, 0x96},
+    {0x8c, 0x00},
+    {0x86, 0x3d},
+    {0x50, 0x92},
+    {0x51, 0x90},
+    {0x52, 0x2c},
+    {0x53, 0x00},
+    {0x54, 0x00},
+    {0x55, 0x88},
+    {0x5a, 0x50},
+    {0x5b, 0x3c},
+    {0x5c, 0x00},
+    {0xd3, 0x04},
+    {0x7f, 0x00},
+    {0xda, 0x00},
+    {0xe5, 0x1f},
+    {0xe1, 0x67},
+    {0xe0, 0x00},
+    {0xdd, 0x7f},
+    {0x05, 0x00},
+    {0xff, 0x00},
+    {0xe0, 0x04},
+    {0xc0, 0xc8},
+    {0xc1, 0x96},
+    {0x86, 0x3d},
+    {0x50, 0x92},
+    {0x51, 0x90},
+    {0x52, 0x2c},
+    {0x53, 0x00},
+    {0x54, 0x00},
+    {0x55, 0x88},
+    {0x57, 0x00},
+    {0x5a, 0x50},
+    {0x5b, 0x3C},
+    {0x5c, 0x00},
+    {0xd3, 0x08},
+    {0xe0, 0x00},
+    {0xFF, 0x00},
+    {0x05, 0x00},
+    {0xDA, 0x08},
+    {0xda, 0x09},
+    {0x98, 0x00},
+    {0x99, 0x00},
+    {0x00, 0x00},
+};
+
+const rt_uint8_t ov2640_jpeg_reg_tbl[][2]=
+{
+    {0xff, 0x01},
+    {0xe0, 0x14},
+    {0xe1, 0x77},
+    {0xe5, 0x1f},
+    {0xd7, 0x03},
+    {0xda, 0x10},
+    {0xe0, 0x00},
+};
+
+const rt_uint8_t ov2640_rgb565_reg_tbl[][2]=
+{
+    {0xFF, 0x00},
+    {0xDA, 0x09},
+    {0xD7, 0x03},
+    {0xDF, 0x02},
+    {0x33, 0xa0},
+    {0x3C, 0x00},
+    {0xe1, 0x67},
+
+    {0xff, 0x01},
+    {0xe0, 0x00},
+    {0xe1, 0x00},
+    {0xe5, 0x00},
+    {0xd7, 0x00},
+    {0xda, 0x00},
+    {0xe0, 0x00},
+};
+const rt_uint8_t ov2640_yuv422_reg_tbl[][2] =
+{
+    {0xFF, 0x00},
+    {0xDA, 0x10},
+    {0xD7, 0x03},
+    {0xDF, 0x00},
+    {0x33, 0x80},
+    {0x3C, 0x40},
+    {0xe1, 0x77},
+    {0x00, 0x00},
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif