David Fletcher / Mbed 2 deprecated cc3100_Test_websock_Camera_CM4F

Dependencies:   mbed

camera_app/mt9d111/mt9d111.cpp

Committer:
dflet
Date:
2015-09-15
Revision:
22:f9b5e0b80bf2
Parent:
21:38c6b11aa348

File content as of revision 22:f9b5e0b80bf2:

//*****************************************************************************
//  MT9D111.c
//
// Micron MT9D111 camera sensor driver
//
// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
//
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions
//  are met:
//
//    Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
//    Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the
//    distribution.
//
//    Neither the name of Texas Instruments Incorporated nor the names of
//    its contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
//  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
//  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
//  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
//  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
//  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//*****************************************************************************
//*****************************************************************************
//
//! \addtogroup mt9d111
//! @{
//
//*****************************************************************************
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include "mbed.h"
#include "cc3100_sl_common.h"
#include "mt9d111.h"

#include "i2cconfig.h"
#include "cli_uart.h"
#include "HttpDebug.h"
#include "app_config.h"

#define RET_OK                  0
#define RET_ERROR               -1
#define SENSOR_PAGE_REG         0xF0
#define CAM_I2C_SLAVE_WRITE     0xBA//Write
#define CAM_I2C_SLAVE_READ      0xBB//Read

#ifdef MT9D111_CAM
DigitalOut standby(PA_3);
#endif

extern DCMI_HandleTypeDef phdcmi;

/* Soft Reset Sequence */
static const s_RegList soft_reset_cmd_list[]= {
    {0, 0x65, 0xA000    },  // Bypass the PLL
    {1, 0xC3, 0x0501    },  // Perform MCU reset
    {0, 0x0D, 0x0021    },  // Enable soft reset
    {100, 0x00, 0x0032  },  // Delay = 50ms
    {0, 0x0D, 0x0000    },  // Disable soft reset
    {100, 0x00, 0x01f4  },  // Delay = 500ms
};

#ifndef ENABLE_JPEG
static const s_RegList preview_on_cmd_list[]= {
    {1, 0xC6, 0xA103    },  // SEQ_CMD
    {1, 0xC8, 0x0001    },  // SEQ_CMD, Do Preview
    {1, 0xC6, 0xA104    },  // SEQ_CMD
    {111, 0xC8, 0x0003  },  // SEQ_CMD, Do Preview
    {1, 0xC6, 0xA103    },  // SEQ_CMD-refresh
    {1, 0xC8, 0x0005    },  // SEQ_CMD-refresh
    {1, 0xC6, 0xA103    },  // SEQ_CMD-refresh
    {1, 0xC8, 0x0006    },  // SEQ_CMD-refresh
    {1, 0xC6, 0xA104    },  // SEQ_CMD
    {111, 0xC8, 0x0003  },  // SEQ_CMD, Do Preview
    {100, 0x00, 0x01f4  },  // Delay = 500ms
};

static  const s_RegList freq_setup_cmd_List[]= {
    {1, 0xC6, 0x276D    },  // MODE_FIFO_CONF1_A
    {1, 0xC8, 0xE4E2    },  // MODE_FIFO_CONF1_A =(58594)
    {1, 0xC6, 0xA76F    },  // MODE_FIFO_CONF2_A
    {1, 0xC8, 0x00E8    },  // MODE_FIFO_CONF2_A =(232)
    (1, 0xC6, 0x2774    ),  // MODE_FIFO_CONF1_B **
    (1, 0xC8, 0xE4E2    ),  // MODE_FIFO_CONF1_B ** =(58594)
    (1, 0xC6, 0xA776    ),  // MODE_FIFO_CONF2_B **
    (1, 0xC8, 0x00E8    ),  // MODE_FIFO_CONF2_B ** =(232)
    {1, 0xC6, 0xA103    },  // SEQ_CMD
    {1, 0xC8, 0x0005    },  // SEQ_CMD (Refresh)
    // Set maximum integration time to get a minimum of 15 fps at 45MHz
    {1, 0xC6, 0xA20E    },  // AE_MAX_INDEX
    {1, 0xC8, 0x0004    },  // AE_MAX_INDEX
    {1, 0xC6, 0xA102    },  // SEQ_MODE
    {1, 0xC8, 0x0001    },  // SEQ_MODE
    {1, 0xC6, 0xA102    },  // SEQ_MODE
    {1, 0xC8, 0x0005    },  // SEQ_MODE
    // Set minimum integration time to get a maximum of 15 fps at 45MHz
    {1, 0xC6, 0xA20D    },  // AE_MAX_INDEX
    {1, 0xC8, 0x0004    },  // AE_MAX_INDEX
    {1, 0xC6, 0xA103    },  // SEQ_CMD
    {1, 0xC8, 0x0005    },  // SEQ_CMD (Refresh)
    {100, 0x00, 0x01f4  },  // Delay = 500ms
};

static  const s_RegList image_size_240_320_preview_cmds_list[]= {
    {0, 0x07, 0x00FE    },  // HORZ_BLANK_A
    {0, 0x08, 0x02A0    },  // VERT_BLANK_A
    {0, 0x20, 0x0303    },  // READ_MODE_B (Image flip settings)
    {0, 0x21, 0x8400    },  // READ_MODE_A (1ADC)
    {1, 0xC6, 0x2703    },  // MODE_OUTPUT_WIDTH_A
    {1, 0xC8, 0x00F0    },  // MODE_OUTPUT_WIDTH_A = 0xF0 (240)
    {1, 0xC6, 0x2705    },  // MODE_OUTPUT_HEIGHT_A
    {1, 0xC8, 0x0140    },  // MODE_OUTPUT_HEIGHT_A = 0x0140 (320)
    {1, 0xC6, 0x2727    },  // MODE_CROP_X0_A
    {1, 0xC8, 0x0000    },  // MODE_CROP_X0_A = 0x00
    {1, 0xC6, 0x2729    },  // MODE_CROP_X1_A
    {1, 0xC8, 0x00F0    },  // MODE_CROP_X1_A = 0xF0
    {1, 0xC6, 0x272B    },  // MODE_CROP_Y0_A
    {1, 0xC8, 0x0000    },  // MODE_CROP_Y0_A = 0xF0
    {1, 0xC6, 0x272D    },  // MODE_CROP_Y1_A
    {1, 0xC8, 0x0140    },  // MODE_CROP_Y1_A = 0x0140
    {1, 0xC6, 0x270F    },  // MODE_SENSOR_ROW_START_A
    {1, 0xC8, 0x001C    },  // MODE_SENSOR_ROW_START_A = 0x001C (28)
    {1, 0xC6, 0x2711    },  // MODE_SENSOR_COL_START_A
    {1, 0xC8, 0x003C    },  // MODE_SENSOR_COL_START_A = 0x003C (60)
    {1, 0xC6, 0x2713    },  // MODE_SENSOR_ROW_HEIGHT_A
    {1, 0xC8, 0x0280    },  // MODE_SENSOR_ROW_HEIGHT_A = 0x0280 (640)
    {1, 0xC6, 0x2715    },  // MODE_SENSOR_COL_WIDTH_A
    {1, 0xC8, 0x03C0    },  // MODE_SENSOR_COL_WIDTH_A = 0x03C0 (960)
    {1, 0xC6, 0x2717    },  // MODE_SENSOR_X_DELAY_A
    {1, 0xC8, 0x0088    },  // MODE_SENSOR_X_DELAY_A = 0x0088
    {1, 0xC6, 0x2719    },  // MODE_SENSOR_ROW_SPEED_A
    {1, 0xC8, 0x0011    },  // MODE_SENSOR_ROW_SPEED_A = 0x0011
    {1, 0xC6, 0xA103    },  // SEQ_CMD
    {1, 0xC8, 0x0005    },  // SEQ_CMD = 0x0005
    {1, 0xC6, 0xA103    },  // SEQ_CMD
    {1, 0xC8, 0x0006    },  // SEQ_CMD = 0x0006
    {100, 0x00, 0x01f4  },  // Delay = 500ms
};

static  const s_RegList preview_cmds_list[]= {

    {1, 0xC6, 0xA77D    },  // MODE_OUTPUT_FORMAT_A
    {1, 0xC8, 0x0020    },  // MODE_OUTPUT_FORMAT_A; RGB565 = 0x0020
    {1, 0xC6, 0x270B    },  // MODE_CONFIG
    {1, 0xC8, 0x0030    },  // MODE_CONFIG, JPEG disabled for A and B = 0x0030
    {1, 0xC6, 0xA103    },  // SEQ_CMD
    {1, 0xC8, 0x0005    },  // SEQ_CMD, refresh = 0x0005
    {100, 0x00, 0x01f4  },  // Delay = 500ms
};
#else
static const s_RegList pll_cmds_list[]= {
    {0, 0x65, 0xA000    },  // Disable PLL
//    {100, 0x00, 0x0064  },  // Delay =100ms
    {0, 0x65, 0xE000    },  // Power DOWN PLL
    {100, 0x00, 0x01F4  },  // Delay =500ms
    {0,  0x66,  0x3003  },  // M = 48 N = 3 PLL  fIN = 8MHz fOUT = 24MHz
//    {0,  0x66,  0x7801  },  // M = 120 N = 1 PLL  fIN = 8MHz fOUT = 60MHz
    {0,  0x67,  0x0501  },  // P = 1
    {0, 0x65,   0xA000  },  // Disable PLL
    {100, 0x00, 0x01F4  },  // Delay =500ms
    {0,  0x65,  0x2000  },  // Enable PLL
    {100, 0x00, 0x01F4  },  // Delay =500ms
};

static  const s_RegList capture_cmds_list[]= {

    {0, 0x20, 0x0000    },  // READ_MODE_B (Image flip settings)
    {100, 0x00, 0x00FA  },  // Delay =250ms
    {1, 0xC6, 0xA102    },  // SEQ_MODE
    {1, 0xC8, 0x0001    },  // SEQ_MODE
    {1, 0xC6, 0xA102    },  // SEQ_MODE
    {1, 0xC8, 0x0005    },  // SEQ_MODE
    {1,  0xC6, 0xA120   },  // Enable Capture video
    {1,  0xC8, 0x0002   },
    {1,  0xC6, 0x270B   },  // Mode config, disable JPEG bypass
    {1,  0xC8, 0x0000   },
    {1,  0xC6, 0x2702   },  // FIFO_config0b, no spoof, adaptive clock
    {1,  0xC8, 0x001E   },
    {1,  0xC6, 0xA907   },  // JPEG mode config, video
    {1,  0xC8, 0x0035   },
    {1,  0xC6, 0xA906   },  // Format YCbCr422
    {1,  0xC8, 0x0000   },
    {1,  0xC6, 0xA90A   },  // Set the qscale1
    {1,  0xC8, 0x0088   },
    {1,  0xC6, 0x2908   },  // Set the restartInt
    {1,  0xC8, 0x0020   },
    {100, 0x00, 0x00FA  },  // Delay =250ms
    {1, 0xC6, 0x2707    },  // MODE_OUTPUT_WIDTH_B
#ifdef XGA_FRAME
    {1, 0xC8, 1024      },
#endif    
#ifdef VGA_FRAME
    {1, 0xC8, 640       },
#endif    
#ifdef QVGA_FRAME
    {1, 0xC8, 320       },
#endif
    {1, 0xC6, 0x2709    },  // MODE_OUTPUT_HEIGHT_B
#ifdef XGA_FRAME
    {1, 0xC8, 768       },
#endif    
#ifdef VGA_FRAME
    {1, 0xC8, 480       },
#endif    
#ifdef QVGA_FRAME
    {1, 0xC8, 240       },
#endif
    {1, 0xC6, 0x2735    },  // MODE_CROP_X0_B
    {1, 0xC8, 640    },
    {1, 0xC6, 0x2737    },  // MODE_CROP_X1_B
    {1, 0xC8, 1600      },
    {1, 0xC6, 0x2739    },  // MODE_CROP_Y0_B
    {1, 0xC8, 480    },
    {1, 0xC6, 0x273B    },  // MODE_CROP_Y1_B
    {1, 0xC8, 1200      },
    {1, 0xC6, 0xA103    }, //SEQ_CMD
    {1, 0xC8, 0x0005    }, //SEQ_CMD, refresh
    {100, 0x00, 0x00FA  },  // Delay = 250ms
//    {111, 0xC8,0x0002   }, //Wait for sequencer change
};

static const s_RegList bypass_pll_list[]= {
    {0, 0x65, 0xA000   },  // Disable PLL
    {100, 0x00, 0x01F4 }, // Delay =500ms
};

static const s_RegList enable_pll_list[]= {
    {0, 0x65, 0x2000   },  // Enable PLL
    {100, 0x00, 0x01F4 }, // Delay =500ms
};

static const s_RegList context_a_list[]= {
    {1, 0xC6, 0xA103   }, //SEQ_CMD
    {1, 0xC8, 0x0001   }, //SEQ_CMD, Do Preview
};

static const s_RegList enter_standby_list[]= {
   {1, 0xC6, 0xA103    }, //SEQ_CMD
   {1, 0xC8, 0x0003    }, //SEQ_CMD, standby
};

static const s_RegList context_b_list[]= {
    {1, 0xC6, 0xA103    },  // SEQ_CMD, Do capture
    {1, 0xC8, 0x0002    },  // Start capture
};

static const s_RegList start_capture_cmd_list[]= {
    {1, 0xC6, 0xA103    },  // SEQ_CMD, Do capture
    {1, 0xC8, 0x0002    },  // Start capture
};

static const s_RegList stop_capture_cmd_list[]= {
    {1, 0xC6, 0xA103    },  // SEQ_CMD, Do capture
    {1, 0xC8, 0x0001    },  // Stop capture
};

#define INDEX_CROP_X0           1
#define INDEX_CROP_X1           3
#define INDEX_CROP_Y0           5
#define INDEX_CROP_Y1           7
#define INDEX_SIZE_WIDTH        12//9
#define INDEX_SIZE_HEIGHT       14//11
static s_RegList resolution_cmds_list[]= {
//    {100, 0x00, 0x01F4      },  // Delay =500ms
    {1, 0xC6, 0x2735        }, //MODE_CROP_X0_A
    {1, 0xC8, 0x0000        }, //MODE_CROP_X0_A
    {1, 0xC6, 0x2737        }, //MODE_CROP_X1_A
    {1, 0xC8, 1600          }, //MODE_CROP_X1_A
    {1, 0xC6, 0x2739        }, //MODE_CROP_Y0_A
    {1, 0xC8, 0x0000        }, //MODE_CROP_Y0_A
    {1, 0xC6, 0x273B        }, //MODE_CROP_Y1_A
    {1, 0xC8, 1200          }, //MODE_CROP_Y1_A
    {1, 0xC6, 0xA103        },  // SEQ_CMD, Do capture
    {1, 0xC8, 0x0005        },

    {1, 0xC6, 0x2707        }, //MODE_OUTPUT_WIDTH_B
    {1, 0xC8, 640           }, //MODE_OUTPUT_WIDTH_B
    {1, 0xC6, 0x2709        }, //MODE_OUTPUT_HEIGHT_B
    {1, 0xC8, 480           }, //MODE_OUTPUT_HEIGHT_B
    {100, 0x00, 0x01f4      },  // Delay = 500ms
};
#endif
static const s_RegList init_cmds_list[]= {
    {0, 0x33, 0x0343        }, // RESERVED_CORE_33
    {1, 0xC6, 0xA115        }, //SEQ_LLMODE
    {1, 0xC8, 0x0020        }, //SEQ_LLMODE
    {0, 0x38, 0x0866        }, // RESERVED_CORE_38
    {100, 0x00, 0x0064      }, // Delay =100ms
    {2, 0x80, 0x0168        }, // LENS_CORRECTION_CONTROL
    {2, 0x81, 0x6432        }, // ZONE_BOUNDS_X1_X2
    {2, 0x82, 0x3296        }, // ZONE_BOUNDS_X0_X3
    {2, 0x83, 0x9664        }, // ZONE_BOUNDS_X4_X5
    {2, 0x84, 0x5028        }, // ZONE_BOUNDS_Y1_Y2
    {2, 0x85, 0x2878        }, // ZONE_BOUNDS_Y0_Y3
    {2, 0x86, 0x7850        }, // ZONE_BOUNDS_Y4_Y5
    {2, 0x87, 0x0000        }, // CENTER_OFFSET
    {2, 0x88, 0x0152        }, // FX_RED
    {2, 0x89, 0x015C        }, // FX_GREEN
    {2, 0x8A, 0x00F4        }, // FX_BLUE
    {2, 0x8B, 0x0108        }, // FY_RED
    {2, 0x8C, 0x00FA        }, // FY_GREEN
    {2, 0x8D, 0x00CF        }, // FY_BLUE
    {2, 0x8E, 0x09AD        }, // DF_DX_RED
    {2, 0x8F, 0x091E        }, // DF_DX_GREEN
    {2, 0x90, 0x0B3F        }, // DF_DX_BLUE
    {2, 0x91, 0x0C85        }, // DF_DY_RED
    {2, 0x92, 0x0CFF        }, // DF_DY_GREEN
    {2, 0x93, 0x0D86        }, // DF_DY_BLUE
    {2, 0x94, 0x163A        }, // SECOND_DERIV_ZONE_0_RED
    {2, 0x95, 0x0E47        }, // SECOND_DERIV_ZONE_0_GREEN
    {2, 0x96, 0x103C        }, // SECOND_DERIV_ZONE_0_BLUE
    {2, 0x97, 0x1D35        }, // SECOND_DERIV_ZONE_1_RED
    {2, 0x98, 0x173E        }, // SECOND_DERIV_ZONE_1_GREEN
    {2, 0x99, 0x1119        }, // SECOND_DERIV_ZONE_1_BLUE
    {2, 0x9A, 0x1663        }, // SECOND_DERIV_ZONE_2_RED
    {2, 0x9B, 0x1569        }, // SECOND_DERIV_ZONE_2_GREEN
    {2, 0x9C, 0x104C        }, // SECOND_DERIV_ZONE_2_BLUE
    {2, 0x9D, 0x1015        }, // SECOND_DERIV_ZONE_3_RED
    {2, 0x9E, 0x1010        }, // SECOND_DERIV_ZONE_3_GREEN
    {2, 0x9F, 0x0B0A        }, // SECOND_DERIV_ZONE_3_BLUE
    {2, 0xA0, 0x0D53        }, // SECOND_DERIV_ZONE_4_RED
    {2, 0xA1, 0x0D51        }, // SECOND_DERIV_ZONE_4_GREEN
    {2, 0xA2, 0x0A44        }, // SECOND_DERIV_ZONE_4_BLUE
    {2, 0xA3, 0x1545        }, // SECOND_DERIV_ZONE_5_RED
    {2, 0xA4, 0x1643        }, // SECOND_DERIV_ZONE_5_GREEN
    {2, 0xA5, 0x1231        }, // SECOND_DERIV_ZONE_5_BLUE
    {2, 0xA6, 0x0047        }, // SECOND_DERIV_ZONE_6_RED
    {2, 0xA7, 0x035C        }, // SECOND_DERIV_ZONE_6_GREEN
    {2, 0xA8, 0xFE30        }, // SECOND_DERIV_ZONE_6_BLUE
    {2, 0xA9, 0x4625        }, // SECOND_DERIV_ZONE_7_RED
    {2, 0xAA, 0x47F3        }, // SECOND_DERIV_ZONE_7_GREEN
    {2, 0xAB, 0x5859        }, // SECOND_DERIV_ZONE_7_BLUE
    {2, 0xAC, 0x0000        }, // X2_FACTORS
    {2, 0xAD, 0x0000        }, // GLOBAL_OFFSET_FXY_FUNCTION
    {2, 0xAE, 0x0000        }, // K_FACTOR_IN_K_FX_FY
    {1, 0x08, 0x01FC        }, // COLOR_PIPELINE_CONTROL
    {100, 0x00, 0x00C8      }, // Delay =200ms
    {1, 0xBE, 0x0004        }, // YUV_YCBCR_CONTROL
    {0, 0x65, 0xA000        }, // PLL CLOCK_ENABLING
    {100, 0x00, 0x00C8      }, // Delay =200ms
    {1, 0xC6, 0x2003        }, //MON_ARG1
    {1, 0xC8, 0x0748        }, //MON_ARG1
    {1, 0xC6, 0xA002        }, //MON_CMD
    {1, 0xC8, 0x0001        }, //MON_CMD
    {100, 0x00, 0x01F4      }, //Delay = 500ms
    {1, 0xC6, 0xA361        }, //AWB_TG_MIN0
    {1, 0xC8, 0x00E2        }, //AWB_TG_MIN0
    {1, 0x1F, 0x0018        }, // RESERVED_SOC1_1F
    {1, 0x51, 0x7F40        }, // RESERVED_SOC1_51
    {100, 0x00, 0x01F4       }, //Delay = 500ms
    {0, 0x33, 0x0343        }, // RESERVED_CORE_33
    {0, 0x38, 0x0868        }, // RESERVED_CORE_38
    {1, 0xC6, 0xA10F        }, //SEQ_RESET_LEVEL_TH
    {1, 0xC8, 0x0042        }, //SEQ_RESET_LEVEL_TH
    {1, 0x1F, 0x0020        }, // RESERVED_SOC1_1F
    {1, 0xC6, 0xAB04        }, //HG_MAX_DLEVEL
    {1, 0xC8, 0x0008        }, //HG_MAX_DLEVEL
    {1, 0xC6, 0xA120        }, //SEQ_CAP_MODE
    {1, 0xC8, 0x0002        }, //SEQ_CAP_MODE
    {1, 0xC6, 0xA103        }, //SEQ_CMD
    {1, 0xC8, 0x0001        }, //SEQ_CMD
    {100, 0x00, 0x01F4      }, // Delay =1000ms
    {1, 0xC6, 0xA102        }, //SEQ_MODE
    {1, 0xC8, 0x001F        }, //SEQ_MODE
    {1, 0x08, 0x01FC        }, // COLOR_PIPELINE_CONTROL
    {1, 0x08, 0x01EC        }, // COLOR_PIPELINE_CONTROL
    {1, 0x08, 0x01FC        }, // COLOR_PIPELINE_CONTROL
    {1, 0x36, 0x0F08        }, // APERTURE_PARAMETERS
    {1, 0xC6, 0x270B        }, //MODE_CONFIG
    {1, 0xC8, 0x0030        }, //MODE_CONFIG, JPEG disabled for A and B
    {1, 0xC6, 0xA121        }, //SEQ_CAP_MODE
    {1, 0xC8, 0x007f        }, //SEQ_CAP_MODE (127 frames before switching to Preview)
    {0, 0x05, 0x011E        }, // HORZ_BLANK_B
    {0, 0x06, 0x006F        }, // VERT_BLANK_B
    {0, 0x07, 0xFE          }, // HORZ_BLANK_A
    {0, 0x08, 19            }, // VERT_BLANK_A
    {0, 0x20, 0x0303        }, // READ_MODE_B (Image flip settings)
    {0, 0x21, 0x8400        }, // READ_MODE_A (1ADC)
    {1, 0xC6, 0x2717        }, //MODE_SENSOR_X_DELAY_A
    {1, 0xC8, 792           }, //MODE_SENSOR_X_DELAY_A
    {1, 0xC6, 0x270F        }, //MODE_SENSOR_ROW_START_A
    {1, 0xC8, 0x001C        }, //MODE_SENSOR_ROW_START_A
    {1, 0xC6, 0x2711        }, //MODE_SENSOR_COL_START_A
    {1, 0xC8, 0x003C        }, //MODE_SENSOR_COL_START_A
    {1, 0xC6, 0x2713        }, //MODE_SENSOR_ROW_HEIGHT_A
    {1, 0xC8, 0x04B0        }, //MODE_SENSOR_ROW_HEIGHT_A
    {1, 0xC6, 0x2715        }, //MODE_SENSOR_COL_WIDTH_A
    {1, 0xC8, 0x0640        }, //MODE_SENSOR_COL_WIDTH_A
    {1, 0xC6, 0x2719        }, //MODE_SENSOR_ROW_SPEED_A
    {1, 0xC8, 0x0011        }, //MODE_SENSOR_ROW_SPEED_A
    {1, 0xC6, 0x2707        }, //MODE_OUTPUT_WIDTH_B
    {1, 0xC8, 0x0640        }, //MODE_OUTPUT_WIDTH_B
    {1, 0xC6, 0x2709        }, //MODE_OUTPUT_HEIGHT_B
    {1, 0xC8, 0x04B0        }, //MODE_OUTPUT_HEIGHT_B
    {1, 0xC6, 0x271B        }, //MODE_SENSOR_ROW_START_B
    {1, 0xC8, 0x001C        }, //MODE_SENSOR_ROW_START_B
    {1, 0xC6, 0x271D        }, //MODE_SENSOR_COL_START_B
    {1, 0xC8, 0x003C        }, //MODE_SENSOR_COL_START_B
    {1, 0xC6, 0x271F        }, //MODE_SENSOR_ROW_HEIGHT_B
    {1, 0xC8, 0x04B0        }, //MODE_SENSOR_ROW_HEIGHT_B
    {1, 0xC6, 0x2721        }, //MODE_SENSOR_COL_WIDTH_B
    {1, 0xC8, 0x0640        }, //MODE_SENSOR_COL_WIDTH_B
    {1, 0xC6, 0x2723        }, //MODE_SENSOR_X_DELAY_B
    {1, 0xC8, 0x0716        }, //MODE_SENSOR_X_DELAY_B
    {1, 0xC6, 0x2725        }, //MODE_SENSOR_ROW_SPEED_B
    {1, 0xC8, 0x0011        }, //MODE_SENSOR_ROW_SPEED_B
    //Maximum Slew-Rate on IO-Pads (for Mode A)
    {1, 0xC6, 0x276B        }, //MODE_FIFO_CONF0_A
    {1, 0xC8, 0x0027        }, //MODE_FIFO_CONF0_A
    {1, 0xC6, 0x276D        }, //MODE_FIFO_CONF1_A
    {1, 0xC8, 0xE1E1        }, //MODE_FIFO_CONF1_A
    {1, 0xC6, 0xA76F        }, //MODE_FIFO_CONF2_A
    {1, 0xC8, 0x00E1        }, //MODE_FIFO_CONF2_A
    //Maximum Slew-Rate on IO-Pads (for Mode B)
    {1, 0xC6, 0x2772        }, //MODE_FIFO_CONF0_B
    {1, 0xC8, 0x0027        }, //MODE_FIFO_CONF0_B
    {1, 0xC6, 0x2774        }, //MODE_FIFO_CONF1_B
    {1, 0xC8, 0xE1E1        }, //MODE_FIFO_CONF1_B
    {1, 0xC6, 0xA776        }, //MODE_FIFO_CONF2_B
    {1, 0xC8, 0x00E1        }, //MODE_FIFO_CONF2_B
    //Set maximum integration time to get a minimum of 15 fps at 45MHz
    {1, 0xC6, 0xA20E        }, //AE_MAX_INDEX
    {1, 0xC8, 0x0004        }, //AE_MAX_INDEX
    //Set minimum integration time to get a maximum of 15 fps at 45MHz
    {1, 0xC6, 0xA20D        }, //AE_MAX_INDEX
    {1, 0xC8, 0x0004        }, //AE_MAX_INDEX
    // Configue all GPIO for output and set low to save power
    {1, 0xC6, 0x9078        },
    {1, 0xC8, 0x0000        },
    {1, 0xC6, 0x9079        },
    {1, 0xC8, 0x0000        },
    {1, 0xC6, 0x9070        },
    {1, 0xC8, 0x0000        },
    {1, 0xC6, 0x9071        },
    {1, 0xC8, 0x0000        },
    // gamma and contrast
    {1, 0xC6, 0xA743        }, // MODE_GAM_CONT_A
    {1, 0xC8, 0x0003        }, // MODE_GAM_CONT_A
    {1, 0xC6, 0xA744        }, // MODE_GAM_CONT_B
    {1, 0xC8, 0x0003        }, // MODE_GAM_CONT_B
    {100, 0x00, 0x01f4      }, // Delay =500ms

};

void getCamId()
{

    uint16_t Id = 0;
    uint8_t ucBuffer[20];

    ucBuffer[0] = 0x00;
    ucBuffer[1] = 0x00;

    int lRetVal = -1;

    lRetVal = RegLstWrite((s_RegList *)soft_reset_cmd_list, sizeof(soft_reset_cmd_list)/sizeof(s_RegList));
    wait_ms(1);
    I2CBufferWrite(CAM_I2C_SLAVE_WRITE,ucBuffer,1,I2C_SEND_STOP);
    I2CBufferRead(CAM_I2C_SLAVE_READ,ucBuffer,2,I2C_SEND_STOP);

    Id = (uint16_t)ucBuffer[0] << 8 | (uint16_t)ucBuffer[1];

    HttpDebug("\r\nCamera ID = 0x%x\r\n",Id);

    if(Id != 0x1519) {
        HttpDebug("MT9D111 Camera not found! I2C read/write failed. \n\r");
        HAL_DCMI_MspDeInit(&phdcmi);
        while(1);
    }


}

//*****************************************************************************
//
//! This function initilizes the camera sensor
//!
//! \param                      None
//!
//! \return                     0 - Success
//!                             -1 - Error
//
//*****************************************************************************

int CameraSensorInit()
{
    HttpDebug("CameraSensorInit \n\r");
    int lRetVal = -1;

    lRetVal = RegLstWrite((s_RegList *)init_cmds_list, \
                          sizeof(init_cmds_list)/sizeof(s_RegList));
    ASSERT_ON_ERROR(lRetVal);

    lRetVal = RegLstWrite((s_RegList *)pll_cmds_list, \
                          sizeof(pll_cmds_list)/sizeof(s_RegList));
    ASSERT_ON_ERROR(lRetVal);                          

#ifndef ENABLE_JPEG

    lRetVal = RegLstWrite((s_RegList *)preview_cmds_list,
                          sizeof(preview_cmds_list)/sizeof(s_RegList));
    ASSERT_ON_ERROR(lRetVal);
    lRetVal = RegLstWrite((s_RegList *)image_size_240_320_preview_cmds_list, \
                          sizeof(image_size_240_320_preview_cmds_list)/ \
                          sizeof(s_RegList));
    ASSERT_ON_ERROR(lRetVal);
    lRetVal = RegLstWrite((s_RegList *)freq_setup_cmd_List,
                          sizeof(freq_setup_cmd_List)/sizeof(s_RegList));
    ASSERT_ON_ERROR(lRetVal);
    lRetVal = RegLstWrite((s_RegList *)preview_on_cmd_list,
                          sizeof(preview_on_cmd_list)/sizeof(s_RegList));
    ASSERT_ON_ERROR(lRetVal);
#endif
    return 0;
}

//*****************************************************************************
//
//! This function configures the sensor in JPEG mode
//!
//! \param[in] width - X-Axis
//! \param[in] height - Y-Axis
//!
//! \return                     0 - Success
//!                             -1 - Error
//
//*****************************************************************************
int StartSensorInJpegMode(int width, int height)
{

#ifdef ENABLE_JPEG
    int lRetVal = -1;
    HttpDebug("\n\rStartSensorInJpegMode \n\r");
    lRetVal = RegLstWrite((s_RegList *)capture_cmds_list,
                          sizeof(capture_cmds_list)/sizeof(s_RegList));
    ASSERT_ON_ERROR(lRetVal);
#endif
    return 0;
}

int StartCaptureCmd()
{

    int32_t lRetVal= -1;

#ifdef ENABLE_JPEG
    lRetVal = RegLstWrite((s_RegList *)start_capture_cmd_list,
                          sizeof(start_capture_cmd_list)/sizeof(s_RegList));
#endif
    return 0;
}

int StopCaptureCmd()
{

    int32_t lRetVal= -1;

#ifdef ENABLE_JPEG
    lRetVal = RegLstWrite((s_RegList *)stop_capture_cmd_list,
                          sizeof(stop_capture_cmd_list)/sizeof(s_RegList));
#endif
    return 0;
}

//*****************************************************************************
//
//! This function configures the sensor ouput resolution
//!
//! \param[in] width - X-Axis
//! \param[in] height - Y-Axis
//!
//! \return                     0 - Success
//!                             -1 - Error
//
//*****************************************************************************
int CameraSensorResolution(int width, int height)
{
    HttpDebug("CameraSensorResolution \n\r");
#ifdef ENABLE_JPEG
    int lRetVal = -1;

    lRetVal = RegLstWrite((s_RegList *)stop_capture_cmd_list,
                          sizeof(stop_capture_cmd_list)/sizeof(s_RegList));
    ASSERT_ON_ERROR(lRetVal);

    resolution_cmds_list[INDEX_SIZE_WIDTH].usValue = width;
    resolution_cmds_list[INDEX_SIZE_HEIGHT].usValue = height;
    lRetVal = RegLstWrite((s_RegList *)resolution_cmds_list,
                          sizeof(resolution_cmds_list)/sizeof(s_RegList));
    ASSERT_ON_ERROR(lRetVal);

    lRetVal = RegLstWrite((s_RegList *)start_capture_cmd_list,
                          sizeof(start_capture_cmd_list)/sizeof(s_RegList));
    ASSERT_ON_ERROR(lRetVal);


#else
    if(width != 240 || height != 256)
        return -1;
#endif
    return 0;
}

//*****************************************************************************
//
//! This function implements the Register Write in MT9D111 sensor
//!
//! \param1                     Register List
//! \param2                     No. Of Items
//!
//! \return                     0 - Success
//!                             -1 - Error
//
//*****************************************************************************
static int RegLstWrite(s_RegList *pRegLst, unsigned int ulNofItems)
{

    unsigned int       ulNdx;
    unsigned short      usTemp;
    unsigned char       i;
    uint8_t       ucBuffer[20];
    unsigned int       ulSize;
    int lRetVal = -1;
    int l = 0;

    if(pRegLst == NULL) {
        return RET_ERROR;
    }

    for(ulNdx = 0; ulNdx < ulNofItems; ulNdx++) {
        if(pRegLst->ucPageAddr == 100) {
            // PageAddr == 100, insret a delay equal to reg value
            wait_ms(pRegLst->usValue);
        } else {
            // Set the page
            ucBuffer[0] = SENSOR_PAGE_REG;//0xF0
            ucBuffer[1] = 0x00;
            ucBuffer[2] = pRegLst->ucPageAddr;

            if(0 != I2CBufferWrite(CAM_I2C_SLAVE_WRITE, ucBuffer, 3, I2C_SEND_STOP)) {
                HttpDebug("\n\rError writing SENSOR_PAGE_REG \n\r");
                return RET_ERROR;
            }

            ucBuffer[0] = SENSOR_PAGE_REG;
            lRetVal = I2CBufferWrite(CAM_I2C_SLAVE_WRITE, ucBuffer, 1, 0);
            ASSERT_ON_ERROR(lRetVal);
            lRetVal = I2CBufferRead(CAM_I2C_SLAVE_READ, ucBuffer, 2, I2C_SEND_STOP);
            ASSERT_ON_ERROR(lRetVal);

            ucBuffer[0] = pRegLst->ucRegAddr;

            if(pRegLst->ucPageAddr  == 0x1 && pRegLst->ucRegAddr == 0xC8) {
                usTemp = 0xC8;
                i=1;
                while(pRegLst->ucRegAddr == usTemp) {
                    ucBuffer[i] = (unsigned char)(pRegLst->usValue >> 8);
                    ucBuffer[i+1] = (unsigned char)(pRegLst->usValue & 0xFF);
                    i += 2;
                    usTemp++;
                    pRegLst++;
                    ulNdx++;
                }

                ulSize = (i-2)*2 + 1;
                ulNdx--;
                pRegLst--;
            } else {
                ulSize = 3;
                ucBuffer[1] = (unsigned char)(pRegLst->usValue >> 8);
                ucBuffer[2] = (unsigned char)(pRegLst->usValue & 0xFF);
            }

            if(0 != I2CBufferWrite(CAM_I2C_SLAVE_WRITE,ucBuffer, ulSize,I2C_SEND_STOP)) {
                HttpDebug("\n\rError i2c write \n\r");
                return RET_ERROR;
            }
        }

        pRegLst++;
        wait_ms(10);
    }

    return RET_OK;
}

static int wait_for_seq_state(int state)
{
    int i, new_state;
           
    for (i = 0; i < 1000; i++) {
        new_state = read_firmware_var(SEQ_DRV_ID, SEQ_STATE_OFFSET, 1);
 //     HttpDebug("seq state %d\r\n", new_state);
        if (new_state == state){
            return 0;
        }    
        wait_ms(2);
    }
    HttpDebug("Timeout waiting for seq_state %d\r\n", state);
     return 1;
}

/*
 * Read a 8/16-bit value from a firmware driver given the driver ID and the
 * var offset. It assumes logic address.
 * The value is returned if successful, or 1 otherwise.
 */
static uint16_t read_firmware_var(int id, int offset, int byte)
{
    uint16_t val;
    uint8_t       ucBuffer[20];       
    /* always use logical address */
    val = VAR_ADDRESS_TYPE_LOGIC << VAR_ADDRESS_TYPE_SHIFT;
    val |= (byte << VAR_LENGTH_SHIFT);
    val |= (id << VAR_DRV_ID_SHIFT);
    val |= (offset << VAR_ADDRESS_SHIFT);
    
    ucBuffer[0] = REG_PAGE;//0xF0
    ucBuffer[1] = 0x00;
    ucBuffer[2] = PAGE_IFP1;//1
    
    /* setup page pointer */
    if (I2CBufferWrite(CAM_I2C_SLAVE_WRITE, (uint8_t*)ucBuffer, 3, I2C_SEND_STOP)){
            return 1;
    }
    ucBuffer[0] = REG_VAR_ADDR;//0xC6
    ucBuffer[1] = val >> 8;
    ucBuffer[2] = val & 0x00FF;
       
    /* setup var pointer */
    if (I2CBufferWrite(CAM_I2C_SLAVE_WRITE, (uint8_t*)ucBuffer, 3, I2C_SEND_STOP)){
            return 1;
    }
    ucBuffer[0] = REG_VAR_DATA;//0xC8 
    if (I2CBufferWrite(CAM_I2C_SLAVE_WRITE, (uint8_t*)ucBuffer, 1, I2C_SEND_STOP)){
            return 1;
    }            

    /* read the var */
    if (I2CBufferRead(CAM_I2C_SLAVE_READ, ucBuffer, 2, I2C_SEND_STOP)){
            return 1;
    }
    val = ucBuffer[0] << 8;
    val |= ucBuffer[1];
            
    return val;
}

int Start_still_capture(int frames)
{
    int err = 1;
    
//    HttpDebug("Context B comamnd sequence ...");
    err = RegLstWrite((s_RegList *)context_b_list, sizeof(context_b_list)/sizeof(s_RegList));
    if (err){
        return err;
    }
    /* wait until the seq driver state change */
    err = wait_for_seq_state(SEQ_STATE_CAPTURE);
    if (err == 1){
        return err;
    }
    /* need a few frames delay to stablize the output */
//    wait_ms(500);

    return 0;
}

int Stop_still_capture(){
    int err = 1;
    
//    HttpDebug("Context A comamnd sequence ...");
    
    err = RegLstWrite((s_RegList *)context_a_list, sizeof(context_a_list)/sizeof(s_RegList));
    if (err){
        return err;
    }    
    /* wait until the seq driver state change */
    err = wait_for_seq_state(SEQ_STATE_PREVIEW);
    if (err == 1){
        return err;
    }
    return 0;
}

int cam_power_on(void)
{

    int err;
    HttpDebug("cam_power_on \r\n");
    /* the caller already enabled our XCLK, wait to make sure it is stable */
    wait_us(100);
    /* release STANDBY line */
    cam_exit_standby();
    /* wait 1ms before enable PLL per Micron Tech. Note */
    wait_ms(1);
    
    err = RegLstWrite((s_RegList *)pll_cmds_list, sizeof(pll_cmds_list)/sizeof(s_RegList));
    if (err){
        return err;
    }
    err = RegLstWrite((s_RegList *)context_a_list, sizeof(context_a_list)/sizeof(s_RegList));    
    if (err){
        return err;
    }    
    err = wait_for_seq_state(SEQ_STATE_PREVIEW);
    return err;
}

int cam_power_off(void)
{
            
    int err;
    
    /* have to check sequencer is in preview mode */
    if (read_firmware_var(SEQ_DRV_ID, SEQ_STATE_OFFSET, 1) != SEQ_STATE_PREVIEW) {
//        printf("Calling power_off while not in preview state!\r\n");
        /* Put sequencer in preview mode */
        err = RegLstWrite((s_RegList *)context_a_list, sizeof(context_a_list)/sizeof(s_RegList));    
        if (err){
            HttpDebug("Error writing context_a_list!\r\n");
            return err;
        }    
        err = wait_for_seq_state(SEQ_STATE_PREVIEW);
        if (err){
            HttpDebug("Cannot place cam in preview state!\r\n");    
            return err;
        }
    }
                   
    /* Issue standby command to sequencer */
    err = RegLstWrite((s_RegList *)enter_standby_list, sizeof(enter_standby_list)/sizeof(s_RegList));    
    if (err){
        return err;
    }         
    /* Poll the sequencer until it enters standby state */
     err = wait_for_seq_state(SEQ_STATE_STANDBY);
    if (err){
        return err;
    }    
    /* bypass PLL */
    err = RegLstWrite((s_RegList *)bypass_pll_list, sizeof(bypass_pll_list)/sizeof(s_RegList));
    if (err){
        return err;     
    }       
    /* assert STANDBY line */
    cam_enter_standby();
    /* the caller can cut off XCLK now */
    return 0;
}

void cam_exit_standby(void)
{
#ifdef MT9D111_CAM    
    HttpDebug("cam_exit_standby \r\n");
    standby = 0;
#endif    
}

void cam_enter_standby(void)
{
#ifdef MT9D111_CAM    
    HttpDebug("cam_enter_standby \r\n");       
    standby = 1;
    wait(1);
#endif    
}

//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************