mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
1021 lines
45 KiB
C
1021 lines
45 KiB
C
/*
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* Copyright (C) 2013-2024 OpenMV, LLC.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*
|
|
* MT9M114 driver.
|
|
*/
|
|
#include "omv_boardconfig.h"
|
|
#if (OMV_MT9M114_ENABLE == 1)
|
|
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "omv_i2c.h"
|
|
#include "omv_csi.h"
|
|
#include "py/mphal.h"
|
|
#include "mt9m114.h"
|
|
#include "sensor_config.h"
|
|
|
|
#define DUMMY_LINES 8
|
|
#define DUMMY_COLUMNS 8
|
|
|
|
#define SENSOR_WIDTH 1296
|
|
#define SENSOR_HEIGHT 976
|
|
|
|
#define ACTIVE_SENSOR_WIDTH (SENSOR_WIDTH - (2 * DUMMY_COLUMNS))
|
|
#define ACTIVE_SENSOR_HEIGHT (SENSOR_HEIGHT - (2 * DUMMY_LINES))
|
|
|
|
#define DUMMY_WIDTH_BUFFER 8
|
|
#define DUMMY_HEIGHT_BUFFER 8
|
|
|
|
static int16_t readout_x = 0;
|
|
static int16_t readout_y = 0;
|
|
|
|
static uint16_t readout_w = ACTIVE_SENSOR_WIDTH;
|
|
static uint16_t readout_h = ACTIVE_SENSOR_HEIGHT;
|
|
|
|
static const uint16_t default_regs[][2] = {
|
|
// Sensor Optimization
|
|
{0x316A, 0x8270},
|
|
{0x316C, 0x8270},
|
|
{0x3ED0, 0x2305},
|
|
{0x3ED2, 0x77CF},
|
|
{0x316E, 0x8202},
|
|
{0x3180, 0x87FF},
|
|
{0x30D4, 0x6080},
|
|
{0xA802, 0x0008},
|
|
|
|
// Errata 1 (Column Bands)
|
|
{0x3E14, 0xFF39}
|
|
};
|
|
|
|
static const uint8_t patch_0202[] = {
|
|
0xd0, 0x00, 0x70, 0xcf, 0xff, 0xff, 0xc5, 0xd4, 0x90, 0x3a, 0x21, 0x44, 0x0c, 0x00, 0x21, 0x86,
|
|
0x0f, 0xf3, 0xb8, 0x44, 0xb9, 0x48, 0xe0, 0x82, 0x20, 0xcc, 0x80, 0xe2, 0x21, 0xcc, 0x80, 0xa2,
|
|
0x21, 0xcc, 0x80, 0xe2, 0xf4, 0x04, 0xd8, 0x01, 0xf0, 0x03, 0xd8, 0x00, 0x7e, 0xe0, 0xc0, 0xf1,
|
|
0x08, 0xba, 0x06, 0x00, 0xc1, 0xa1, 0x76, 0xcf, 0xff, 0xff, 0xc1, 0x30, 0x6e, 0x04, 0xc0, 0x40,
|
|
0x71, 0xcf, 0xff, 0xff, 0xc7, 0x90, 0x81, 0x03, 0x77, 0xcf, 0xff, 0xff, 0xc7, 0xc0, 0xe0, 0x01,
|
|
0xa1, 0x03, 0xd8, 0x00, 0x0c, 0x6a, 0x04, 0xe0, 0xb8, 0x9e, 0x75, 0x08, 0x8e, 0x1c, 0x08, 0x09,
|
|
0x01, 0x91, 0xd8, 0x01, 0xae, 0x1d, 0xe5, 0x80, 0x20, 0xca, 0x00, 0x22, 0x20, 0xcf, 0x05, 0x22,
|
|
0x0c, 0x5c, 0x04, 0xe2, 0x21, 0xca, 0x00, 0x62, 0xe5, 0x80, 0xd9, 0x01, 0x79, 0xc0, 0xd8, 0x00,
|
|
0x0b, 0xe6, 0x04, 0xe0, 0xb8, 0x9e, 0x70, 0xcf, 0xff, 0xff, 0xc8, 0xd4, 0x90, 0x02, 0x08, 0x57,
|
|
0x02, 0x5e, 0xff, 0xdc, 0xe0, 0x80, 0x25, 0xcc, 0x90, 0x22, 0xf2, 0x25, 0x17, 0x00, 0x10, 0x8a,
|
|
0x73, 0xcf, 0xff, 0x00, 0x31, 0x74, 0x93, 0x07, 0x2a, 0x04, 0x10, 0x3e, 0x93, 0x28, 0x29, 0x42,
|
|
0x71, 0x40, 0x2a, 0x04, 0x10, 0x7e, 0x93, 0x49, 0x29, 0x42, 0x71, 0x41, 0x2a, 0x04, 0x10, 0xbe,
|
|
0x93, 0x4a, 0x29, 0x42, 0x71, 0x4b, 0x2a, 0x04, 0x10, 0xbe, 0x13, 0x0c, 0x01, 0x0a, 0x29, 0x42,
|
|
0x71, 0x42, 0x22, 0x50, 0x13, 0xca, 0x1b, 0x0c, 0x02, 0x84, 0xb3, 0x07, 0xb3, 0x28, 0x1b, 0x12,
|
|
0x02, 0xc4, 0xb3, 0x4a, 0xed, 0x88, 0x71, 0xcf, 0xff, 0x00, 0x31, 0x74, 0x91, 0x06, 0xb8, 0x8f,
|
|
0xb1, 0x06, 0x21, 0x0a, 0x83, 0x40, 0xc0, 0x00, 0x21, 0xca, 0x00, 0x62, 0x20, 0xf0, 0x00, 0x40,
|
|
0x0b, 0x02, 0x03, 0x20, 0xd9, 0x01, 0x07, 0xf1, 0x05, 0xe0, 0xc0, 0xa1, 0x78, 0xe0, 0xc0, 0xf1,
|
|
0x71, 0xcf, 0xff, 0xff, 0xc7, 0xc0, 0xd8, 0x40, 0xa9, 0x00, 0x71, 0xcf, 0xff, 0xff, 0xd0, 0x2c,
|
|
0xd8, 0x1e, 0x0a, 0x5a, 0x04, 0xe0, 0xda, 0x00, 0xd8, 0x00, 0xc0, 0xd1, 0x7e, 0xe0
|
|
};
|
|
static const uint8_t patch_0302[] = {
|
|
0xd1, 0x2c, 0x70, 0xcf, 0xff, 0xff, 0xc5, 0xd4, 0x90, 0x3a, 0x21, 0x44, 0x0c, 0x00, 0x21, 0x86,
|
|
0x0f, 0xf3, 0xb8, 0x44, 0x26, 0x2f, 0xf0, 0x08, 0xb9, 0x48, 0x21, 0xcc, 0x80, 0x21, 0xd8, 0x01,
|
|
0xf2, 0x03, 0xd8, 0x00, 0x7e, 0xe0, 0xc0, 0xf1, 0x71, 0xcf, 0xff, 0xff, 0xc6, 0x10, 0x91, 0x0e,
|
|
0x20, 0x8c, 0x80, 0x14, 0xf4, 0x18, 0x91, 0x0f, 0x20, 0x8c, 0x80, 0x0f, 0xf4, 0x14, 0x91, 0x16,
|
|
0x20, 0x8c, 0x80, 0x0a, 0xf4, 0x10, 0x91, 0x17, 0x20, 0x8c, 0x88, 0x07, 0xf4, 0x0c, 0x91, 0x18,
|
|
0x20, 0x86, 0x0f, 0xf3, 0xb8, 0x48, 0x08, 0x0d, 0x00, 0x90, 0xff, 0xea, 0xe0, 0x81, 0xd8, 0x01,
|
|
0xf2, 0x03, 0xd8, 0x00, 0xc0, 0xd1, 0x7e, 0xe0, 0x78, 0xe0, 0xc0, 0xf1, 0x71, 0xcf, 0xff, 0xff,
|
|
0xc6, 0x10, 0x91, 0x0e, 0x20, 0x8c, 0x80, 0x0a, 0xf4, 0x18, 0x91, 0x0f, 0x20, 0x8c, 0x88, 0x07,
|
|
0xf4, 0x14, 0x91, 0x16, 0x20, 0x8c, 0x80, 0x0a, 0xf4, 0x10, 0x91, 0x17, 0x20, 0x8c, 0x88, 0x07,
|
|
0xf4, 0x0c, 0x91, 0x18, 0x20, 0x86, 0x0f, 0xf3, 0xb8, 0x48, 0x08, 0x0d, 0x00, 0x90, 0xff, 0xd9,
|
|
0xe0, 0x80, 0xd8, 0x01, 0xf2, 0x03, 0xd8, 0x00, 0xf1, 0xdf, 0x90, 0x40, 0x71, 0xcf, 0xff, 0xff,
|
|
0xc5, 0xd4, 0xb1, 0x5a, 0x90, 0x41, 0x73, 0xcf, 0xff, 0xff, 0xc7, 0xd0, 0xb1, 0x40, 0x90, 0x42,
|
|
0xb1, 0x41, 0x90, 0x43, 0xb1, 0x42, 0x90, 0x44, 0xb1, 0x43, 0x90, 0x45, 0xb1, 0x47, 0x90, 0x46,
|
|
0xb1, 0x48, 0x90, 0x47, 0xb1, 0x4b, 0x90, 0x48, 0xb1, 0x4c, 0x90, 0x49, 0x19, 0x58, 0x00, 0x84,
|
|
0x90, 0x4a, 0x19, 0x5a, 0x00, 0x84, 0x88, 0x56, 0x1b, 0x36, 0x80, 0x82, 0x88, 0x57, 0x1b, 0x37,
|
|
0x80, 0x82, 0x90, 0x4c, 0x19, 0xa7, 0x00, 0x9c, 0x88, 0x1a, 0x7f, 0xe0, 0x1b, 0x54, 0x80, 0x02,
|
|
0x78, 0xe0, 0x71, 0xcf, 0xff, 0xff, 0xc3, 0x50, 0xd8, 0x28, 0xa9, 0x0b, 0x81, 0x00, 0x01, 0xc5,
|
|
0x03, 0x20, 0xd9, 0x00, 0x78, 0xe0, 0x22, 0x0a, 0x1f, 0x80, 0xff, 0xff, 0xd4, 0xe0, 0xc0, 0xf1,
|
|
0x08, 0x11, 0x00, 0x51, 0x22, 0x40, 0x12, 0x00, 0xff, 0xe1, 0xd8, 0x01, 0xf0, 0x06, 0x22, 0x40,
|
|
0x19, 0x00, 0xff, 0xde, 0xd8, 0x02, 0x1a, 0x05, 0x10, 0x02, 0xff, 0xf2, 0xf1, 0x95, 0xc0, 0xf1,
|
|
0x0e, 0x7e, 0x05, 0xc0, 0x75, 0xcf, 0xff, 0xff, 0xc8, 0x4c, 0x95, 0x02, 0x77, 0xcf, 0xff, 0xff,
|
|
0xc3, 0x44, 0x20, 0x44, 0x00, 0x8e, 0xb8, 0xa1, 0x09, 0x26, 0x03, 0xe0, 0xb5, 0x02, 0x95, 0x02,
|
|
0x95, 0x2e, 0x7e, 0x05, 0xb5, 0xc2, 0x70, 0xcf, 0xff, 0xff, 0xc6, 0x10, 0x09, 0x9a, 0x04, 0xa0,
|
|
0xb0, 0x26, 0x0e, 0x02, 0x05, 0x60, 0xde, 0x00, 0x0a, 0x12, 0x03, 0x20, 0xb7, 0xc4, 0x0b, 0x36,
|
|
0x03, 0xa0, 0x70, 0xc9, 0x95, 0x02, 0x76, 0x08, 0xb8, 0xa8, 0xb5, 0x02, 0x70, 0xcf, 0x00, 0x00,
|
|
0x55, 0x36, 0x78, 0x60, 0x26, 0x86, 0x1f, 0xfb, 0x95, 0x02, 0x78, 0xc5, 0x06, 0x31, 0x05, 0xe0,
|
|
0xb5, 0x02, 0x72, 0xcf, 0xff, 0xff, 0xc5, 0xd4, 0x92, 0x3a, 0x73, 0xcf, 0xff, 0xff, 0xc7, 0xd0,
|
|
0xb0, 0x20, 0x92, 0x20, 0xb0, 0x21, 0x92, 0x21, 0xb0, 0x22, 0x92, 0x22, 0xb0, 0x23, 0x92, 0x23,
|
|
0xb0, 0x24, 0x92, 0x27, 0xb0, 0x25, 0x92, 0x28, 0xb0, 0x26, 0x92, 0x2b, 0xb0, 0x27, 0x92, 0x2c,
|
|
0xb0, 0x28, 0x12, 0x58, 0x01, 0x01, 0xb0, 0x29, 0x12, 0x5a, 0x01, 0x01, 0xb0, 0x2a, 0x13, 0x36,
|
|
0x80, 0x81, 0xa8, 0x36, 0x13, 0x37, 0x80, 0x81, 0xa8, 0x37, 0x12, 0xa7, 0x07, 0x01, 0xb0, 0x2c,
|
|
0x13, 0x54, 0x80, 0x81, 0x7f, 0xe0, 0xa8, 0x3a, 0x78, 0xe0, 0xc0, 0xf1, 0x0d, 0xc2, 0x05, 0xc0,
|
|
0x76, 0x08, 0x09, 0xbb, 0x00, 0x10, 0x75, 0xcf, 0xff, 0xff, 0xd4, 0xe0, 0x8d, 0x21, 0x8d, 0x00,
|
|
0x21, 0x53, 0x00, 0x03, 0xb8, 0xc0, 0x8d, 0x45, 0x0b, 0x23, 0x00, 0x00, 0xea, 0x8f, 0x09, 0x15,
|
|
0x00, 0x1e, 0xff, 0x81, 0xe8, 0x08, 0x25, 0x40, 0x19, 0x00, 0xff, 0xde, 0x8d, 0x00, 0xb8, 0x80,
|
|
0xf0, 0x04, 0x8d, 0x00, 0xb8, 0xa0, 0xad, 0x00, 0x8d, 0x05, 0xe0, 0x81, 0x20, 0xcc, 0x80, 0xa2,
|
|
0xdf, 0x00, 0xf4, 0x0a, 0x71, 0xcf, 0xff, 0xff, 0xc8, 0x4c, 0x91, 0x02, 0x77, 0x08, 0xb8, 0xa6,
|
|
0x27, 0x86, 0x1f, 0xfe, 0xb1, 0x02, 0x0b, 0x42, 0x01, 0x80, 0x0e, 0x3e, 0x01, 0x80, 0x0f, 0x4a,
|
|
0x01, 0x60, 0x70, 0xc9, 0x8d, 0x05, 0xe0, 0x81, 0x20, 0xcc, 0x80, 0xa2, 0xf4, 0x29, 0x76, 0xcf,
|
|
0xff, 0xff, 0xc8, 0x4c, 0x08, 0x2d, 0x00, 0x51, 0x70, 0xcf, 0xff, 0xff, 0xc9, 0x0c, 0x88, 0x05,
|
|
0x09, 0xb6, 0x03, 0x60, 0xd9, 0x08, 0x20, 0x99, 0x08, 0x02, 0x96, 0x34, 0xb5, 0x03, 0x79, 0x02,
|
|
0x15, 0x23, 0x10, 0x80, 0xb6, 0x34, 0xe0, 0x01, 0x1d, 0x23, 0x10, 0x02, 0xf0, 0x0b, 0x96, 0x34,
|
|
0x95, 0x03, 0x60, 0x38, 0xb6, 0x14, 0x15, 0x3f, 0x10, 0x80, 0xe0, 0x01, 0x1d, 0x3f, 0x10, 0x02,
|
|
0xff, 0xa4, 0x96, 0x02, 0x7f, 0x05, 0xd8, 0x00, 0xb6, 0xe2, 0xad, 0x05, 0x05, 0x11, 0x05, 0xe0,
|
|
0xd8, 0x00, 0xc0, 0xf1, 0x0c, 0xfe, 0x05, 0xc0, 0x0a, 0x96, 0x05, 0xa0, 0x76, 0x08, 0x0c, 0x22,
|
|
0x02, 0x40, 0xe0, 0x80, 0x20, 0xca, 0x0f, 0x82, 0x00, 0x00, 0x19, 0x0b, 0x0c, 0x60, 0x05, 0xa2,
|
|
0x21, 0xca, 0x00, 0x22, 0x0c, 0x56, 0x02, 0x40, 0xe8, 0x06, 0x0e, 0x0e, 0x02, 0x20, 0x70, 0xc9,
|
|
0xf0, 0x48, 0x08, 0x96, 0x04, 0x40, 0x0e, 0x96, 0x04, 0x00, 0x09, 0x66, 0x03, 0x80, 0x75, 0xcf,
|
|
0xff, 0xff, 0xd4, 0xe0, 0x8d, 0x00, 0x08, 0x4d, 0x00, 0x1e, 0xff, 0x47, 0x08, 0x0d, 0x00, 0x50,
|
|
0xff, 0x57, 0x08, 0x41, 0x00, 0x51, 0x8d, 0x04, 0x95, 0x21, 0xe0, 0x64, 0x79, 0x0c, 0x70, 0x2f,
|
|
0x0c, 0xe2, 0x05, 0xe0, 0xd9, 0x64, 0x72, 0xcf, 0xff, 0xff, 0xc7, 0x00, 0x92, 0x35, 0x08, 0x11,
|
|
0x00, 0x43, 0xff, 0x3d, 0x08, 0x0d, 0x00, 0x51, 0xd8, 0x01, 0xff, 0x77, 0xf0, 0x25, 0x95, 0x01,
|
|
0x92, 0x35, 0x09, 0x11, 0x00, 0x03, 0xff, 0x49, 0x08, 0x0d, 0x00, 0x51, 0xd8, 0x00, 0xff, 0x72,
|
|
0xf0, 0x1b, 0x08, 0x86, 0x03, 0xe0, 0xd8, 0x01, 0x0e, 0xf6, 0x03, 0xc0, 0x0f, 0x52, 0x03, 0x40,
|
|
0x0d, 0xba, 0x02, 0x00, 0x0a, 0xf6, 0x04, 0x40, 0x0c, 0x22, 0x04, 0x00, 0x0d, 0x72, 0x04, 0x40,
|
|
0x0d, 0xc2, 0x02, 0x00, 0x09, 0x72, 0x04, 0x40, 0x0d, 0x3a, 0x02, 0x20, 0xd8, 0x20, 0x0b, 0xfa,
|
|
0x02, 0x60, 0x70, 0xc9, 0x04, 0x51, 0x05, 0xc0, 0x78, 0xe0, 0xd9, 0x00, 0xf0, 0x0a, 0x70, 0xcf,
|
|
0xff, 0xff, 0xd5, 0x20, 0x78, 0x35, 0x80, 0x41, 0x80, 0x00, 0xe1, 0x02, 0xa0, 0x40, 0x09, 0xf1,
|
|
0x81, 0x14, 0x71, 0xcf, 0xff, 0xff, 0xd4, 0xe0, 0x70, 0xcf, 0xff, 0xff, 0xc5, 0x94, 0xb0, 0x3a,
|
|
0x7f, 0xe0, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x02, 0x00, 0x03, 0x30,
|
|
0x00, 0x00, 0x00, 0x00, 0x03, 0xcd, 0x05, 0x0d, 0x01, 0xc5, 0x03, 0xb3, 0x00, 0xe0, 0x01, 0xe3,
|
|
0x02, 0x80, 0x01, 0xe0, 0x01, 0x09, 0x00, 0x80, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc9, 0xb4, 0xff, 0xff, 0xd3, 0x24, 0xff, 0xff,
|
|
0xca, 0x34, 0xff, 0xff, 0xd3, 0xec
|
|
};
|
|
static const uint8_t patch_0402[] = {
|
|
0xd5, 0x30, 0xc0, 0xf1, 0x0b, 0xba, 0x05, 0xc0, 0xc1, 0xa2, 0x75, 0xcf, 0xff, 0xff, 0xc7, 0xc0,
|
|
0xde, 0x00, 0x1c, 0x05, 0x33, 0x82, 0xc6, 0x61, 0x08, 0xc3, 0x00, 0x40, 0xe1, 0xd1, 0xf2, 0x17,
|
|
0xe1, 0xd4, 0xf4, 0x5b, 0x8d, 0x01, 0x08, 0xb3, 0x00, 0x1e, 0x1c, 0x00, 0x3f, 0x80, 0x00, 0x0c,
|
|
0x35, 0x00, 0x71, 0x8b, 0x0f, 0xbe, 0x04, 0xe0, 0x70, 0xc9, 0x08, 0x06, 0x05, 0x20, 0x70, 0xc9,
|
|
0x95, 0x25, 0x70, 0xcf, 0xff, 0x00, 0x00, 0x00, 0xb0, 0x39, 0xf0, 0x47, 0x8d, 0x01, 0x08, 0x27,
|
|
0x00, 0xdf, 0x8d, 0x02, 0x08, 0x1d, 0x00, 0x1e, 0x8d, 0x02, 0xad, 0x01, 0x8d, 0x01, 0xb8, 0xa3,
|
|
0xad, 0x01, 0x70, 0xcf, 0xff, 0x00, 0x00, 0x00, 0x90, 0x19, 0xb5, 0x05, 0xf0, 0x05, 0x8d, 0x01,
|
|
0xb8, 0xa0, 0xad, 0x01, 0x8d, 0x01, 0x08, 0x11, 0x00, 0xde, 0x8d, 0x01, 0xb8, 0xa3, 0xad, 0x01,
|
|
0x0d, 0x02, 0x04, 0xa0, 0xd8, 0x01, 0x8d, 0x01, 0x08, 0x53, 0x00, 0x1e, 0x85, 0x01, 0x0b, 0x5e,
|
|
0x05, 0xe0, 0x21, 0x8a, 0x04, 0x1f, 0x95, 0x24, 0x29, 0x05, 0x00, 0x3e, 0x1c, 0x00, 0x3e, 0x40,
|
|
0x71, 0x8b, 0x0f, 0x4e, 0x04, 0xe0, 0xd8, 0x00, 0x0f, 0x9a, 0x04, 0xe0, 0xd8, 0x00, 0xd8, 0x00,
|
|
0x0f, 0xb6, 0x04, 0xe0, 0xd9, 0x01, 0x8d, 0x01, 0x08, 0x23, 0x00, 0x5f, 0x20, 0x8a, 0x00, 0x1c,
|
|
0x0b, 0xe2, 0x04, 0xe0, 0xd9, 0x00, 0xd8, 0x0d, 0xb8, 0x0a, 0x0b, 0xd6, 0x04, 0xe0, 0xd9, 0x00,
|
|
0xd8, 0x90, 0x0b, 0xea, 0x04, 0xe0, 0xd9, 0x01, 0xd8, 0x00, 0x02, 0xf5, 0x05, 0xe0, 0xc0, 0xa2,
|
|
0x78, 0xe0, 0xc0, 0xf1, 0x73, 0xcf, 0xff, 0xff, 0xc7, 0xc0, 0x8b, 0x41, 0x0a, 0x0d, 0x00, 0xde,
|
|
0x8b, 0x41, 0x0a, 0x0f, 0x00, 0x5e, 0x72, 0xcf, 0x00, 0x00, 0x40, 0x3e, 0x7a, 0x40, 0xf0, 0x02,
|
|
0xd8, 0x00, 0xc0, 0xd1, 0x7e, 0xe0, 0xc0, 0xf1, 0xc5, 0xe1, 0x75, 0xcf, 0xff, 0xff, 0xc7, 0xc0,
|
|
0xd9, 0x00, 0xf0, 0x09, 0x70, 0xcf, 0xff, 0xff, 0xd7, 0x40, 0x78, 0x35, 0x80, 0x41, 0x80, 0x00,
|
|
0xe1, 0x02, 0xa0, 0x40, 0x09, 0xf3, 0x80, 0x94, 0x71, 0xcf, 0xff, 0xff, 0xd6, 0xd0, 0xd8, 0x03,
|
|
0x0d, 0x1e, 0x04, 0xa0, 0xda, 0x00, 0x70, 0xcf, 0xff, 0xff, 0xd5, 0x30, 0x0c, 0x22, 0x03, 0x00,
|
|
0xe8, 0x87, 0x70, 0xcf, 0xff, 0xff, 0xd6, 0xe8, 0x09, 0x4a, 0x02, 0x40, 0x21, 0x8a, 0x0a, 0x0f,
|
|
0xb5, 0x24, 0xd9, 0x04, 0xad, 0x23, 0x1d, 0x04, 0x1f, 0x80, 0x01, 0x6e, 0x36, 0x00, 0x02, 0x79,
|
|
0x05, 0xc0, 0xc0, 0xf1, 0x71, 0xcf, 0xff, 0xff, 0xc3, 0x50, 0x11, 0x09, 0x00, 0xc0, 0x73, 0xcf,
|
|
0xff, 0xff, 0xc1, 0x64, 0xe0, 0xd2, 0x72, 0xcf, 0xff, 0xff, 0xc7, 0xc0, 0xf4, 0x12, 0x8b, 0x08,
|
|
0x08, 0x21, 0x03, 0xd1, 0x8a, 0x01, 0x08, 0x19, 0x00, 0xdf, 0xd8, 0x54, 0xa9, 0x0b, 0xd8, 0x00,
|
|
0xa9, 0x08, 0x8a, 0x21, 0xb9, 0x83, 0xaa, 0x21, 0xaa, 0x0c, 0x0b, 0xe6, 0x04, 0x80, 0xf1, 0xb2,
|
|
0x78, 0xe0, 0xc0, 0xf1, 0x70, 0xcf, 0xff, 0xff, 0xc7, 0xc0, 0x88, 0x01, 0xb8, 0xe0, 0x0f, 0xb4,
|
|
0xff, 0xc2, 0x0e, 0x9a, 0x02, 0x40, 0xf1, 0xa6, 0x78, 0xe0, 0xc0, 0xf1, 0x71, 0xcf, 0xff, 0xff,
|
|
0xc7, 0xc0, 0x89, 0x61, 0x72, 0xcf, 0xff, 0xff, 0xc3, 0x50, 0x0b, 0x45, 0x00, 0xde, 0x08, 0x41,
|
|
0x08, 0x11, 0x89, 0x0c, 0xe0, 0x01, 0xa9, 0x0c, 0x89, 0x6c, 0x89, 0x03, 0x0b, 0x0d, 0x00, 0x03,
|
|
0x89, 0x02, 0x08, 0x2d, 0x00, 0x9e, 0x89, 0x02, 0x08, 0x13, 0x00, 0x9e, 0x89, 0x02, 0xb8, 0xa2,
|
|
0xa9, 0x02, 0x89, 0x01, 0xb8, 0x82, 0xf0, 0x03, 0x89, 0x01, 0xb8, 0xa2, 0xa9, 0x01, 0xd8, 0x50,
|
|
0xaa, 0x0b, 0xd9, 0x00, 0xaa, 0x2a, 0xaa, 0x28, 0x0c, 0xca, 0x02, 0xe0, 0x82, 0x00, 0xd8, 0x00,
|
|
0xf1, 0x7a, 0xff, 0xff, 0xca, 0xd0, 0xff, 0xff, 0xd6, 0x10
|
|
};
|
|
static const uint8_t patch_0502[] = {
|
|
0xd7, 0x48, 0x72, 0xcf, 0xff, 0xff, 0xc7, 0xc0, 0x08, 0x27, 0x00, 0x40, 0xe1, 0xd1, 0xf4, 0x0f,
|
|
0x8a, 0x01, 0x08, 0x1b, 0x00, 0xdf, 0x70, 0xcf, 0xff, 0xff, 0xc6, 0x44, 0x88, 0x08, 0xb8, 0xe4,
|
|
0x8a, 0x0e, 0x20, 0xcf, 0x00, 0x62, 0x20, 0xd0, 0x00, 0x61, 0xaa, 0x0e, 0x7f, 0xe0, 0xd8, 0x00,
|
|
0x78, 0xe0, 0xc0, 0xf1, 0x09, 0x6e, 0x05, 0xc0, 0x75, 0xcf, 0xff, 0xff, 0xc7, 0xc0, 0x70, 0xcf,
|
|
0x00, 0x00, 0x55, 0x36, 0x78, 0x60, 0xc1, 0xa1, 0x95, 0xca, 0x77, 0xcf, 0xff, 0xff, 0xc8, 0xd4,
|
|
0x9f, 0x1c, 0x08, 0x27, 0x00, 0x12, 0xd9, 0x08, 0x0d, 0x56, 0x03, 0x20, 0xda, 0x05, 0x9f, 0x3c,
|
|
0x09, 0x13, 0x0f, 0x82, 0x00, 0x00, 0x0b, 0x00, 0xb8, 0x2a, 0x7e, 0x0c, 0x76, 0x2f, 0xf0, 0x0f,
|
|
0x7e, 0x0c, 0x29, 0x41, 0x72, 0x8e, 0xf0, 0x0b, 0x78, 0x13, 0xd9, 0x08, 0x0d, 0x32, 0x03, 0x20,
|
|
0xda, 0x05, 0x71, 0x08, 0x09, 0x52, 0x05, 0xe0, 0x70, 0xc9, 0x76, 0x08, 0x8d, 0x0f, 0x08, 0x25,
|
|
0x00, 0x1e, 0x70, 0xcf, 0xff, 0xff, 0xc8, 0x2f, 0x0d, 0x1e, 0x04, 0x00, 0x28, 0x05, 0x03, 0xbe,
|
|
0x70, 0xcf, 0xff, 0xff, 0xc9, 0x14, 0x90, 0x33, 0xb9, 0x24, 0x09, 0x2a, 0x05, 0xe0, 0x70, 0x2f,
|
|
0x76, 0x08, 0x8d, 0x0e, 0x08, 0x83, 0x00, 0x5e, 0x8d, 0x01, 0x08, 0x7b, 0x00, 0xde, 0x8d, 0x0e,
|
|
0x77, 0xcf, 0xff, 0xff, 0xc8, 0x4c, 0xb8, 0xa0, 0xad, 0x0e, 0x8f, 0x27, 0x8f, 0x49, 0x22, 0x02,
|
|
0x80, 0x40, 0x00, 0x08, 0x00, 0x03, 0x21, 0x02, 0x00, 0x80, 0x78, 0x0e, 0xc0, 0x40, 0x8f, 0x08,
|
|
0x78, 0x2c, 0x70, 0x2f, 0xe0, 0x63, 0x08, 0xfe, 0x05, 0xe0, 0xd9, 0x64, 0x97, 0x20, 0x78, 0x0d,
|
|
0xb9, 0xc1, 0x21, 0x42, 0x80, 0x02, 0x22, 0xca, 0x00, 0x62, 0xc3, 0x00, 0x72, 0x59, 0x08, 0x17,
|
|
0x00, 0xe3, 0xd9, 0x00, 0x70, 0xcf, 0xff, 0xff, 0xd8, 0xba, 0x88, 0x00, 0xe0, 0x80, 0x22, 0xcc,
|
|
0x90, 0x22, 0xf2, 0x02, 0xd9, 0x01, 0x26, 0x2f, 0xf0, 0x47, 0xf2, 0x08, 0x8d, 0x0e, 0xb8, 0x80,
|
|
0xad, 0x0e, 0xa5, 0xc4, 0x8d, 0x02, 0xb8, 0x82, 0xad, 0x02, 0x70, 0xcf, 0xff, 0xff, 0xd8, 0xba,
|
|
0xa8, 0x40, 0xf0, 0x02, 0xa5, 0xc4, 0x00, 0x79, 0x05, 0xe0, 0xc0, 0xa1, 0x78, 0xe0, 0xc0, 0xf1,
|
|
0xc5, 0xe1, 0x75, 0xcf, 0xff, 0xff, 0xc7, 0xc0, 0xd9, 0x00, 0xf0, 0x09, 0x70, 0xcf, 0xff, 0xff,
|
|
0xd8, 0xbc, 0x78, 0x35, 0x80, 0x41, 0x80, 0x00, 0xe1, 0x02, 0xa0, 0x40, 0x09, 0xf3, 0x80, 0x94,
|
|
0x70, 0xcf, 0xff, 0xff, 0xd7, 0x48, 0x09, 0xde, 0x03, 0x00, 0x21, 0x8a, 0x00, 0x14, 0xb5, 0x2a,
|
|
0x00, 0x51, 0x05, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xcb, 0x54, 0xff, 0xff, 0xd7, 0x78
|
|
};
|
|
static const uint8_t awb_ccm[] = {
|
|
0xc8, 0x92, 0x02, 0x67, 0xff, 0x1a, 0xff, 0xb3, 0xff, 0x80, 0x01, 0x66, 0x00, 0x03, 0xff, 0x9a,
|
|
0xfe, 0xb4, 0x02, 0x4d, 0x01, 0xbf, 0xff, 0x01, 0xff, 0xf3, 0xff, 0x75, 0x01, 0x98, 0xff, 0xfd,
|
|
0xff, 0x9a, 0xfe, 0xe7, 0x02, 0xa8, 0x01, 0xd9, 0xff, 0x26, 0xff, 0xf3, 0xff, 0xb3, 0x01, 0x32,
|
|
0xff, 0xe8, 0xff, 0xda, 0xfe, 0xcd, 0x02, 0xc2
|
|
};
|
|
static const uint8_t awb_weights[] = {
|
|
0xc8, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x24, 0x15, 0x83, 0x20, 0x45, 0x03, 0xff,
|
|
0x00, 0x7c
|
|
};
|
|
static const uint16_t cpipe_regs_8_bit_a[] = {
|
|
0xC92A, // CAM_LL_START_SATURATION
|
|
0xC92B, // CAM_LL_END_SATURATION
|
|
0xC92C, // CAM_LL_START_DESATURATION
|
|
0xC92D, // CAM_LL_END_DESATURATION
|
|
0xC92E, // CAM_LL_START_DEMOSAIC
|
|
0xC92F, // CAM_LL_START_AP_GAIN
|
|
0xC930, // CAM_LL_START_AP_THRESH
|
|
0xC931, // CAM_LL_STOP_DEMOSAIC
|
|
0xC932, // CAM_LL_STOP_AP_GAIN
|
|
0xC933, // CAM_LL_STOP_AP_THRESH
|
|
0xC934, // CAM_LL_START_NR_RED
|
|
0xC935, // CAM_LL_START_NR_GREEN
|
|
0xC936, // CAM_LL_START_NR_BLUE
|
|
0xC937, // CAM_LL_START_NR_THRESH
|
|
0xC938, // CAM_LL_STOP_NR_RED
|
|
0xC939, // CAM_LL_STOP_NR_GREEN
|
|
0xC93A, // CAM_LL_STOP_NR_BLUE
|
|
0xC93B, // CAM_LL_STOP_NR_THRESH
|
|
0xC942, // CAM_LL_START_CONTRAST_GRADIENT
|
|
0xC943, // CAM_LL_STOP_CONTRAST_GRADIENT
|
|
0xC944, // CAM_LL_START_CONTRAST_LUMA_PERCENTAGE
|
|
0xC945, // CAM_LL_STOP_CONTRAST_LUMA_PERCENTAGE
|
|
0xC950, // CAM_LL_CLUSTER_DC_GATE_PERCENTAGE
|
|
0xC951, // CAM_LL_SUMMING_SENSITIVITY_FACTOR
|
|
0xC87B, // CAM_AET_TARGET_AVERAGE_LUMA_DARK
|
|
0xC878, // CAM_AET_AEMODE
|
|
0xB42A, // CCM_DELTA_GAIN
|
|
0xA80A, // AE_TRACK_AE_TRACKING_DAMPENING_SPEED
|
|
};
|
|
|
|
static const uint16_t cpipe_regs_8_bit_d[] = {
|
|
0x80, // CAM_LL_START_SATURATION
|
|
0x4B, // CAM_LL_END_SATURATION
|
|
0x00, // CAM_LL_START_DESATURATION
|
|
0xFF, // CAM_LL_END_DESATURATION
|
|
0x3C, // CAM_LL_START_DEMOSAIC
|
|
0x02, // CAM_LL_START_AP_GAIN
|
|
0x06, // CAM_LL_START_AP_THRESH
|
|
0x64, // CAM_LL_STOP_DEMOSAIC
|
|
0x01, // CAM_LL_STOP_AP_GAIN
|
|
0x0C, // CAM_LL_STOP_AP_THRESH
|
|
0x3C, // CAM_LL_START_NR_RED
|
|
0x3C, // CAM_LL_START_NR_GREEN
|
|
0x3C, // CAM_LL_START_NR_BLUE
|
|
0x0F, // CAM_LL_START_NR_THRESH
|
|
0x64, // CAM_LL_STOP_NR_RED
|
|
0x64, // CAM_LL_STOP_NR_GREEN
|
|
0x64, // CAM_LL_STOP_NR_BLUE
|
|
0x32, // CAM_LL_STOP_NR_THRESH
|
|
0x38, // CAM_LL_START_CONTRAST_GRADIENT
|
|
0x30, // CAM_LL_STOP_CONTRAST_GRADIENT
|
|
0x50, // CAM_LL_START_CONTRAST_LUMA_PERCENTAGE
|
|
0x19, // CAM_LL_STOP_CONTRAST_LUMA_PERCENTAGE
|
|
0x05, // CAM_LL_CLUSTER_DC_GATE_PERCENTAGE
|
|
0x40, // CAM_LL_SUMMING_SENSITIVITY_FACTOR
|
|
0x1B, // CAM_AET_TARGET_AVERAGE_LUMA_DARK
|
|
0x00, // CAM_AET_AEMODE (was 0x0E)
|
|
0x05, // CCM_DELTA_GAIN
|
|
0x20 // AE_TRACK_AE_TRACKING_DAMPENING_SPEED
|
|
};
|
|
|
|
static const uint16_t cpipe_regs_16_bit[][2] = {
|
|
{0xC926, 0x0020}, // CAM_LL_START_BRIGHTNESS
|
|
{0xC928, 0x009A}, // CAM_LL_STOP_BRIGHTNESS
|
|
{0xC946, 0x0070}, // CAM_LL_START_GAIN_METRIC
|
|
{0xC948, 0x00F3}, // CAM_LL_STOP_GAIN_METRIC
|
|
{0xC952, 0x0020}, // CAM_LL_START_TARGET_LUMA_BM
|
|
{0xC954, 0x009A}, // CAM_LL_STOP_TARGET_LUMA_BM
|
|
{0xC93C, 0x0020}, // CAM_LL_START_CONTRAST_BM
|
|
{0xC93E, 0x009A}, // CAM_LL_STOP_CONTRAST_BM
|
|
{0xC940, 0x00DC}, // CAM_LL_GAMMA
|
|
{0xC94A, 0x0230}, // CAM_LL_START_FADE_TO_BLACK_LUMA
|
|
{0xC94C, 0x0010}, // CAM_LL_STOP_FADE_TO_BLACK_LUMA
|
|
{0xC94E, 0x01CD}, // CAM_LL_CLUSTER_DC_TH_BM
|
|
{0xC890, 0x0080}, // CAM_AET_TARGET_GAIN
|
|
{0xC886, 0x0100}, // CAM_AET_AE_MAX_VIRT_AGAIN
|
|
{0xC87C, 0x005A} // CAM_AET_BLACK_CLIPPING_TARGET
|
|
};
|
|
|
|
static int host_command(omv_csi_t *csi, uint16_t command) {
|
|
if (omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_HOST_COMMAND, (command | MT9M114_HC_OK)) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
for (mp_uint_t start = mp_hal_ticks_ms();; mp_hal_delay_ms(MT9M114_HC_DELAY)) {
|
|
uint16_t reg_data;
|
|
|
|
if (omv_i2c_readw2(csi->i2c, csi->slv_addr, MT9M114_REG_HOST_COMMAND, ®_data) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if ((reg_data & command) == 0) {
|
|
return (reg_data & MT9M114_HC_OK) ? 0 : -1;
|
|
}
|
|
|
|
if ((mp_hal_ticks_ms() - start) >= MT9M114_HC_TIMEOUT) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int load_patch(omv_csi_t *csi, const uint8_t *patch, size_t patch_len,
|
|
uint16_t patch_loader_address, uint16_t patch_id, uint32_t patch_firmware_id) {
|
|
int ret = 0;
|
|
// Patch address is stashed in the first two bytes.
|
|
uint16_t patch_address = (((uint16_t) patch[0]) << 8) | patch[1];
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_XMDA_ACCESS_CTL_STAT, patch_address >> 15);
|
|
ret |=
|
|
omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_XMDA_PHYSICAL_ADDRESS_ACCESS, patch_address & 0x7FFF);
|
|
ret |= omv_i2c_write_bytes(csi->i2c, csi->slv_addr, (uint8_t *) patch, patch_len, OMV_I2C_XFER_NO_FLAGS);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_XMDA_LOGIC_ADDRESS_ACCESS, 0x0000);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_PATCHLDR_LOADER_ADDRESS, patch_loader_address);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_PATCHLDR_PATCH_ID, patch_id);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_PATCHLDR_FIRMWARE_ID_HI, patch_firmware_id >> 16);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_PATCHLDR_FIRMWARE_ID_LO, patch_firmware_id);
|
|
|
|
ret |= host_command(csi, MT9M114_HC_APPLY_PATCH);
|
|
|
|
uint8_t reg_data;
|
|
ret |= omv_i2c_readb2(csi->i2c, csi->slv_addr, MT9M114_REG_PATCHLDR_APPLY_STATUS, ®_data);
|
|
ret |= (reg_data == 0) ? 0: -1;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int load_awb_cmm(omv_csi_t *csi) {
|
|
return omv_i2c_write_bytes(csi->i2c, csi->slv_addr, (uint8_t *) awb_ccm, sizeof(awb_ccm), OMV_I2C_XFER_NO_FLAGS);
|
|
}
|
|
|
|
static int load_awb(omv_csi_t *csi) {
|
|
int ret = 0;
|
|
|
|
ret |= omv_i2c_writeb2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_AWB_XSCALE, 0x03);
|
|
ret |= omv_i2c_writeb2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_AWB_YSCALE, 0x02);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_AWB_Y_SHIFT_PRE_ADJ, 0x003C);
|
|
ret |= omv_i2c_write_bytes(csi->i2c, csi->slv_addr,
|
|
(uint8_t *) awb_weights, sizeof(awb_weights), OMV_I2C_XFER_NO_FLAGS);
|
|
|
|
for (int i = 0xC90C; i <= 0xC911; i++) {
|
|
ret |= omv_i2c_writeb2(csi->i2c, csi->slv_addr, i, 0x80);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int load_cpipe(omv_csi_t *csi) {
|
|
int ret = 0;
|
|
|
|
int a_size = sizeof(cpipe_regs_8_bit_a) / sizeof(cpipe_regs_8_bit_a[0]);
|
|
int d_size = sizeof(cpipe_regs_8_bit_d) / sizeof(cpipe_regs_8_bit_d[0]);
|
|
|
|
for (int i = 0, ii = IM_MIN(a_size, d_size); i < ii; i++) {
|
|
ret |= omv_i2c_writeb2(csi->i2c, csi->slv_addr, cpipe_regs_8_bit_a[i], cpipe_regs_8_bit_d[i]);
|
|
}
|
|
|
|
for (int i = 0; i < (sizeof(cpipe_regs_16_bit) / sizeof(cpipe_regs_16_bit[0])); i++) {
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, cpipe_regs_16_bit[i][0], cpipe_regs_16_bit[i][1]);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int set_system_state(omv_csi_t *csi, uint8_t state) {
|
|
if (omv_i2c_writeb2(csi->i2c, csi->slv_addr, MT9M114_REG_SYSMGR_NEXT_STATE, state) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return (host_command(csi, MT9M114_HC_SET_STATE) == 0) ? 0 : -1;
|
|
}
|
|
|
|
static int change_config(omv_csi_t *csi) {
|
|
return set_system_state(csi, MT9M114_SS_ENTER_CONFIG_CHANGE);
|
|
}
|
|
|
|
static int refresh(omv_csi_t *csi) {
|
|
int ret = host_command(csi, MT9M114_HC_REFRESH);
|
|
|
|
if (ret == 0) {
|
|
return ret;
|
|
}
|
|
|
|
uint8_t reg_data;
|
|
|
|
if (omv_i2c_readb2(csi->i2c, csi->slv_addr, MT9M114_REG_SEQ_ERROR_CODE, ®_data) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return -reg_data;
|
|
}
|
|
|
|
static int set_pixformat(omv_csi_t *csi, pixformat_t pixformat);
|
|
static int set_framesize(omv_csi_t *csi, omv_csi_framesize_t framesize);
|
|
static int reset(omv_csi_t *csi) {
|
|
int ret = 0;
|
|
readout_x = 0;
|
|
readout_y = 0;
|
|
|
|
readout_w = ACTIVE_SENSOR_WIDTH;
|
|
readout_h = ACTIVE_SENSOR_HEIGHT;
|
|
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SYSCTL, MT9M114_SYSCTL_SOFT_RESET);
|
|
mp_hal_delay_ms(1);
|
|
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SYSCTL, 0);
|
|
mp_hal_delay_ms(45);
|
|
|
|
for (mp_uint_t start = mp_hal_ticks_ms();; mp_hal_delay_ms(MT9M114_HC_DELAY)) {
|
|
uint16_t reg_data;
|
|
|
|
if (omv_i2c_readw2(csi->i2c, csi->slv_addr, MT9M114_REG_HOST_COMMAND, ®_data) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if ((reg_data & MT9M114_HC_SET_STATE) != 0) {
|
|
break;
|
|
}
|
|
|
|
if ((mp_hal_ticks_ms() - start) >= MT9M114_HC_TIMEOUT) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
for (mp_uint_t start = mp_hal_ticks_ms();; mp_hal_delay_ms(MT9M114_HC_DELAY)) {
|
|
uint8_t reg_data;
|
|
|
|
if (omv_i2c_readb2(csi->i2c, csi->slv_addr, MT9M114_REG_SYSMGR_CURRENT_STATE, ®_data) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (reg_data != MT9M114_SS_STANDBY) {
|
|
break;
|
|
}
|
|
|
|
if ((mp_hal_ticks_ms() - start) >= MT9M114_HC_TIMEOUT) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// Errata 2 (Black Frame Output)
|
|
uint16_t reg;
|
|
ret |= omv_i2c_readw2(csi->i2c, csi->slv_addr, 0x301A, ®);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, 0x301A, reg | (1 << 9));
|
|
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_SYSCTL_PLL_DIVIDER_M_N,
|
|
(omv_csi_get_clk_frequency(csi, true) == OMV_MT9M114_CLK_FREQ)
|
|
? 0x120 // xclk=24MHz, m=32, n=1, csi=48MHz, bus=76.8MHz
|
|
: 0x448); // xclk=25MHz, m=72, n=4, csi=45MHz, bus=72MHz
|
|
|
|
for (int i = 0; i < (sizeof(default_regs) / sizeof(default_regs[0])); i++) {
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, default_regs[i][0], default_regs[i][1]);
|
|
}
|
|
|
|
ret |= set_framesize(csi, OMV_CSI_FRAMESIZE_SXGAM);
|
|
|
|
// Black level correction fix
|
|
ret |= load_patch(csi, patch_0202, sizeof(patch_0202), 0x010c, 0x0202, 0x41030202);
|
|
// Adaptive Sensitivity
|
|
ret |= load_patch(csi, patch_0302, sizeof(patch_0302), 0x04b4, 0x0302, 0x41030202);
|
|
// System Idle Control (auto wakeup from standby)
|
|
ret |= load_patch(csi, patch_0402, sizeof(patch_0402), 0x0634, 0x0402, 0x41030202);
|
|
// Ambient light csi
|
|
ret |= load_patch(csi, patch_0502, sizeof(patch_0502), 0x0884, 0x0502, 0x41030202);
|
|
|
|
ret |= load_awb_cmm(csi);
|
|
ret |= load_awb(csi);
|
|
ret |= load_cpipe(csi);
|
|
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_PORT_OUTPUT_CONTROL, 0x8008);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_PAD_SLEW, 0x0777);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CONTROL_READ_MODE,
|
|
MT9M114_SENSOR_CONTROL_READ_MODE_HMIRROR | MT9M114_SENSOR_CONTROL_READ_MODE_VFLIP);
|
|
|
|
ret |= change_config(csi);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int sleep(omv_csi_t *csi, int enable) {
|
|
uint8_t state = MT9M114_SS_LEAVE_STANDBY;
|
|
uint8_t new_state = MT9M114_SS_STREAMING;
|
|
|
|
if (enable) {
|
|
state = MT9M114_SS_ENTER_STANDBY;
|
|
new_state = MT9M114_SS_STANDBY;
|
|
}
|
|
|
|
if (set_system_state(csi, state) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
for (mp_uint_t start = mp_hal_ticks_ms();; mp_hal_delay_ms(MT9M114_HC_DELAY)) {
|
|
uint8_t reg_data;
|
|
|
|
if (omv_i2c_readb2(csi->i2c, csi->slv_addr, MT9M114_REG_SYSMGR_CURRENT_STATE, ®_data) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (reg_data == new_state) {
|
|
return 0;
|
|
}
|
|
|
|
if ((mp_hal_ticks_ms() - start) >= MT9M114_HC_TIMEOUT) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static int read_reg(omv_csi_t *csi, uint16_t reg_addr) {
|
|
uint16_t reg_data;
|
|
|
|
if (omv_i2c_readw2(csi->i2c, csi->slv_addr, reg_addr, ®_data) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return reg_data;
|
|
}
|
|
|
|
static int write_reg(omv_csi_t *csi, uint16_t reg_addr, uint16_t reg_data) {
|
|
return omv_i2c_writew2(csi->i2c, csi->slv_addr, reg_addr, reg_data);
|
|
}
|
|
|
|
static int set_pixformat(omv_csi_t *csi, pixformat_t pixformat) {
|
|
uint16_t reg = 0;
|
|
|
|
switch (pixformat) {
|
|
case PIXFORMAT_GRAYSCALE:
|
|
case PIXFORMAT_YUV422:
|
|
reg = MT9M114_OUTPUT_FORMAT_YUV | MT9M114_OUTPUT_FORMAT_SWAP_BYTES;
|
|
break;
|
|
case PIXFORMAT_RGB565:
|
|
reg = MT9M114_OUTPUT_FORMAT_RGB | MT9M114_OUTPUT_FORMAT_RGB565 | MT9M114_OUTPUT_FORMAT_SWAP_BYTES;
|
|
break;
|
|
case PIXFORMAT_BAYER:
|
|
if ((csi->framesize != OMV_CSI_FRAMESIZE_INVALID)
|
|
&& (csi->framesize != OMV_CSI_FRAMESIZE_VGA)
|
|
&& (csi->framesize != OMV_CSI_FRAMESIZE_SXGAM)) {
|
|
return -1;
|
|
}
|
|
reg = MT9M114_OUTPUT_FORMAT_BAYER | MT9M114_OUTPUT_FORMAT_RAW_BAYER_10;
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
if (omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_OUTPUT_FORMAT, reg) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return change_config(csi);
|
|
}
|
|
|
|
static int set_framesize(omv_csi_t *csi, omv_csi_framesize_t framesize) {
|
|
int ret = 0;
|
|
uint16_t w = csi->resolution[framesize][0];
|
|
uint16_t h = csi->resolution[framesize][1];
|
|
|
|
if ((csi->pixformat == PIXFORMAT_BAYER) &&
|
|
((framesize != OMV_CSI_FRAMESIZE_VGA) && (framesize != OMV_CSI_FRAMESIZE_SXGAM))) {
|
|
return -1;
|
|
}
|
|
|
|
if ((w > ACTIVE_SENSOR_WIDTH) || (h > ACTIVE_SENSOR_HEIGHT)) {
|
|
return -1;
|
|
}
|
|
|
|
// Step 0: Clamp readout settings.
|
|
|
|
readout_w = IM_MAX(readout_w, w);
|
|
readout_h = IM_MAX(readout_h, h);
|
|
|
|
int readout_x_max = (ACTIVE_SENSOR_WIDTH - readout_w) / 2;
|
|
int readout_y_max = (ACTIVE_SENSOR_HEIGHT - readout_h) / 2;
|
|
readout_x = IM_CLAMP(readout_x, -readout_x_max, readout_x_max);
|
|
readout_y = IM_CLAMP(readout_y, -readout_y_max, readout_y_max);
|
|
|
|
// Step 1: Determine readout area and subsampling amount.
|
|
|
|
uint16_t read_mode;
|
|
|
|
if (omv_i2c_readw2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CONTROL_READ_MODE, &read_mode) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
int read_mode_div = 1;
|
|
read_mode &= ~(MT9M114_SENSOR_CONTROL_READ_MODE_HBIN_MASK | MT9M114_SENSOR_CONTROL_READ_MODE_VBIN_MASK);
|
|
|
|
if ((w <= (readout_w / 2)) && (h <= (readout_h / 2))) {
|
|
read_mode_div = 2;
|
|
read_mode |= MT9M114_SENSOR_CONTROL_READ_MODE_HBIN | MT9M114_SENSOR_CONTROL_READ_MODE_VBIN;
|
|
}
|
|
|
|
// Step 2: Determine horizontal and vertical start and end points.
|
|
|
|
uint16_t sensor_w = readout_w + DUMMY_WIDTH_BUFFER; // camera hardware needs dummy pixels to sync
|
|
uint16_t sensor_h = readout_h + DUMMY_HEIGHT_BUFFER; // camera hardware needs dummy lines to sync
|
|
|
|
uint16_t sensor_ws = IM_CLAMP((((ACTIVE_SENSOR_WIDTH - sensor_w) / 4) + (readout_x / 2)) * 2,
|
|
-(DUMMY_WIDTH_BUFFER / 2),
|
|
ACTIVE_SENSOR_WIDTH - sensor_w) + DUMMY_COLUMNS; // must be multiple of 2
|
|
uint16_t sensor_we = sensor_ws + sensor_w - 1;
|
|
|
|
int sensor_ws_mod = sensor_ws % (read_mode_div * 4); // multiple 4/8
|
|
if (sensor_ws_mod) {
|
|
sensor_ws -= sensor_ws_mod;
|
|
sensor_we += read_mode_div;
|
|
}
|
|
|
|
uint16_t sensor_hs = IM_CLAMP((((ACTIVE_SENSOR_HEIGHT - sensor_h) / 4) - (readout_y / 2)) * 2,
|
|
-(DUMMY_HEIGHT_BUFFER / 2),
|
|
ACTIVE_SENSOR_HEIGHT - sensor_h) + DUMMY_LINES; // must be multiple of 2
|
|
uint16_t sensor_he = sensor_hs + sensor_h - 1;
|
|
|
|
int sensor_hs_mod = sensor_hs % (read_mode_div * 4); // multiple 4/8
|
|
if (sensor_hs_mod) {
|
|
sensor_hs -= sensor_hs_mod;
|
|
sensor_he += read_mode_div;
|
|
}
|
|
|
|
// Step 3: Determine scaling window offset.
|
|
|
|
float ratio = IM_MIN((readout_w / read_mode_div) / ((float) w), (readout_h / read_mode_div) / ((float) h));
|
|
|
|
uint16_t w_mul = w * ratio;
|
|
uint16_t h_mul = h * ratio;
|
|
uint16_t x_off = ((readout_w / read_mode_div) - w_mul) / 2;
|
|
uint16_t y_off = ((readout_h / read_mode_div) - h_mul) / 2;
|
|
|
|
// Step 4: Write regs.
|
|
|
|
uint16_t frame_length_lines = (readout_h / read_mode_div) + ((read_mode_div == 2) ? 40 : 39) + DUMMY_HEIGHT_BUFFER;
|
|
uint16_t line_length_pck = (readout_w / read_mode_div) + ((read_mode_div == 2) ? 534 : 323) + DUMMY_WIDTH_BUFFER;
|
|
|
|
// Errata 4 (Cam_port_clock_slowdown issues/limitations)
|
|
if (!(line_length_pck % 5)) {
|
|
line_length_pck += 1;
|
|
}
|
|
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_Y_ADDR_START, sensor_hs);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_X_ADDR_START, sensor_ws);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_Y_ADDR_END, sensor_he);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_X_ADDR_END, sensor_we);
|
|
|
|
int pixclk = (omv_csi_get_clk_frequency(csi, true) == OMV_MT9M114_CLK_FREQ) ? 48000000 : 45000000;
|
|
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_PIXCLK, pixclk >> 16);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_PIXCLK + 2, pixclk);
|
|
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_FINE_INTEG_TIME_MIN,
|
|
(read_mode_div == 2) ? 451 : 219); // figured this out by checking register wizard against datasheet
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_FINE_INTEG_TIME_MAX,
|
|
(read_mode_div == 2) ? 947 : 1480); // figured this out by checking register wizard against datasheet
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_FRAME_LENGTH_LINES,
|
|
frame_length_lines); // figured this out by checking register wizard against datasheet
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_LINE_LENGTH_PCK,
|
|
line_length_pck); // figured this out by checking register wizard against datasheet
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_FINE_CORRECTION,
|
|
(read_mode_div == 2) ? 224 : 96); // figured this out by checking register wizard against datasheet
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_CPIPE_LAST_ROW,
|
|
(readout_h / read_mode_div) + 3); // figured this out by checking register wizard against datasheet
|
|
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CONTROL_READ_MODE, read_mode);
|
|
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_CROP_WINDOW_X_OFFSET, x_off);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_CROP_WINDOW_Y_OFFSET, y_off);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_CROP_WINDOW_WIDTH, w_mul);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_CROP_WINDOW_HEIGHT, h_mul);
|
|
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_OUTPUT_WIDTH, w);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_OUTPUT_HEIGHT, h);
|
|
|
|
float rate = (((float) pixclk) / (frame_length_lines * line_length_pck)) * 256;
|
|
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_AET_MAX_FRAME_RATE, fast_ceilf(rate));
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_AET_MIN_FRAME_RATE, fast_floorf(rate / 2.f));
|
|
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_AWB_CLIP_WINDOW_X_START, 0);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_AWB_CLIP_WINDOW_Y_START, 0);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_AWB_CLIP_WINDOW_X_END, w - 1);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_AWB_CLIP_WINDOW_Y_END, h - 1);
|
|
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_AE_INITIAL_WINDOW_X_START, 0);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_AE_INITIAL_WINDOW_Y_START, 0);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_AE_INITIAL_WINDOW_X_END, (w / 5) - 1);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_AE_INITIAL_WINDOW_Y_END, (h / 5) - 1);
|
|
|
|
ret |= omv_i2c_writeb2(csi->i2c, csi->slv_addr, MT9M114_REG_AUTO_BINNING_MODE, 0);
|
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_LL_ALGO, 0);
|
|
|
|
return change_config(csi);
|
|
}
|
|
|
|
static int set_framerate(omv_csi_t *csi, int framerate) {
|
|
if (omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_AET_MAX_FRAME_RATE, framerate * 256) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_AET_MIN_FRAME_RATE, framerate * 128) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return change_config(csi);
|
|
}
|
|
|
|
static int set_contrast(omv_csi_t *csi, int level) {
|
|
// -16 to +16
|
|
int new_level = (level > 0) ? (level * 2) : level;
|
|
|
|
if ((new_level < -16) || (32 < new_level)) {
|
|
return -1;
|
|
}
|
|
|
|
if (omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_UVC_CONTRAST_CONTROL, new_level + 32) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return refresh(csi);
|
|
}
|
|
|
|
static int set_brightness(omv_csi_t *csi, int level) {
|
|
// -16 to +16
|
|
int new_level = level * 2;
|
|
|
|
if ((new_level < -32) || (32 < new_level)) {
|
|
return -1;
|
|
}
|
|
|
|
if (omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_UVC_BRIGHTNESS_CONTROL, new_level + 55) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return refresh(csi);
|
|
}
|
|
|
|
static int set_saturation(omv_csi_t *csi, int level) {
|
|
// -16 to +16
|
|
int new_level = level * 8;
|
|
|
|
if ((new_level < -128) || (128 < new_level)) {
|
|
return -1;
|
|
}
|
|
|
|
new_level = IM_MIN(new_level, 127);
|
|
|
|
if (omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_UVC_SATURATION_CONTROL, new_level + 128) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return refresh(csi);
|
|
}
|
|
|
|
static int set_gainceiling(omv_csi_t *csi, omv_csi_gainceiling_t gainceiling) {
|
|
return 0;
|
|
}
|
|
|
|
static int set_colorbar(omv_csi_t *csi, int enable) {
|
|
if (omv_i2c_writeb2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_MODE_SELECT, enable ? 2 : 0) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return change_config(csi);
|
|
}
|
|
|
|
static int set_auto_gain(omv_csi_t *csi, int enable, float gain_db, float gain_db_ceiling) {
|
|
if (omv_i2c_writeb2(csi->i2c, csi->slv_addr, MT9M114_REG_UVC_AE_MODE_CONTROL, enable ? 0x2 : 0x1) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if ((enable == 0) && (!isnanf(gain_db)) && (!isinff(gain_db))) {
|
|
int gain = __USAT(expf((gain_db / 20.0f) * M_LN10) * 32.0f, 16);
|
|
|
|
if (omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_UVC_GAIN_CONTROL, gain) != 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return refresh(csi);
|
|
}
|
|
|
|
static int get_gain_db(omv_csi_t *csi, float *gain_db) {
|
|
uint16_t gain;
|
|
|
|
if (omv_i2c_readw2(csi->i2c, csi->slv_addr, MT9M114_REG_UVC_GAIN_CONTROL, &gain) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
*gain_db = 20.0f * log10f(gain / 32.0f);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int set_auto_exposure(omv_csi_t *csi, int enable, int exposure_us) {
|
|
if (omv_i2c_writeb2(csi->i2c, csi->slv_addr, MT9M114_REG_UVC_AE_MODE_CONTROL, enable ? 0x2 : 0x1) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if ((enable == 0) && (exposure_us >= 0)) {
|
|
if (omv_i2c_writeb2(csi->i2c, csi->slv_addr, MT9M114_REG_UVC_MANUAL_EXPOSURE_CONFIG, 0x1) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
int exposure_100_us = exposure_us / 100;
|
|
|
|
if (omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_UVC_EXPOSURE_TIME_ABSOLUTE_CTRL,
|
|
exposure_100_us >> 16) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_UVC_EXPOSURE_TIME_ABSOLUTE_CTRL + 2,
|
|
exposure_100_us) != 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return refresh(csi);
|
|
}
|
|
|
|
static int get_exposure_us(omv_csi_t *csi, int *exposure_us) {
|
|
uint16_t reg_h, reg_l;
|
|
|
|
if (omv_i2c_readw2(csi->i2c, csi->slv_addr, MT9M114_REG_UVC_EXPOSURE_TIME_ABSOLUTE_CTRL, ®_h) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (omv_i2c_readw2(csi->i2c, csi->slv_addr, MT9M114_REG_UVC_EXPOSURE_TIME_ABSOLUTE_CTRL + 2, ®_l) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
*exposure_us = ((reg_h << 16) | reg_l) * 100;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int set_auto_whitebal(omv_csi_t *csi, int enable, float r_gain_db, float g_gain_db, float b_gain_db) {
|
|
if (omv_i2c_writeb2(csi->i2c, csi->slv_addr, MT9M114_REG_UVC_WHITE_BALANCE_AUTO_CONTROL,
|
|
enable ? 0x1 : 0x0) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int get_rgb_gain_db(omv_csi_t *csi, float *r_gain_db, float *g_gain_db, float *b_gain_db) {
|
|
*r_gain_db = 0;
|
|
*g_gain_db = 0;
|
|
*b_gain_db = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int set_hmirror(omv_csi_t *csi, int enable) {
|
|
uint16_t reg_data;
|
|
|
|
if (omv_i2c_readw2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CONTROL_READ_MODE, ®_data) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
reg_data = (reg_data & (~MT9M114_SENSOR_CONTROL_READ_MODE_HMIRROR)) |
|
|
(enable ? 0x0 : MT9M114_SENSOR_CONTROL_READ_MODE_HMIRROR); // inverted
|
|
|
|
if (omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CONTROL_READ_MODE, reg_data) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return change_config(csi);
|
|
}
|
|
|
|
static int set_vflip(omv_csi_t *csi, int enable) {
|
|
uint16_t reg_data;
|
|
|
|
if (omv_i2c_readw2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CONTROL_READ_MODE, ®_data) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
reg_data = (reg_data & (~MT9M114_SENSOR_CONTROL_READ_MODE_VFLIP)) |
|
|
(enable ? 0x0 : MT9M114_SENSOR_CONTROL_READ_MODE_VFLIP); // inverted
|
|
|
|
if (omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CONTROL_READ_MODE, reg_data) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return change_config(csi);
|
|
}
|
|
|
|
static int set_special_effect(omv_csi_t *csi, omv_csi_sde_t sde) {
|
|
switch (sde) {
|
|
case OMV_CSI_SDE_NEGATIVE:
|
|
if (omv_i2c_writeb2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_SFX_CONTROL, 0x3) != 0) {
|
|
return -1;
|
|
}
|
|
break;
|
|
case OMV_CSI_SDE_NORMAL:
|
|
if (omv_i2c_writeb2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_SFX_CONTROL, 0x0) != 0) {
|
|
return -1;
|
|
}
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return refresh(csi);
|
|
}
|
|
|
|
static int ioctl(omv_csi_t *csi, int request, va_list ap) {
|
|
int ret = 0;
|
|
|
|
switch (request) {
|
|
case OMV_CSI_IOCTL_SET_READOUT_WINDOW: {
|
|
int tmp_readout_x = va_arg(ap, int);
|
|
int tmp_readout_y = va_arg(ap, int);
|
|
int tmp_readout_w = IM_CLAMP(va_arg(ap, int),
|
|
csi->resolution[csi->framesize][0],
|
|
ACTIVE_SENSOR_WIDTH);
|
|
int tmp_readout_h = IM_CLAMP(va_arg(ap, int),
|
|
csi->resolution[csi->framesize][1],
|
|
ACTIVE_SENSOR_HEIGHT);
|
|
int readout_x_max = (ACTIVE_SENSOR_WIDTH - tmp_readout_w) / 2;
|
|
int readout_y_max = (ACTIVE_SENSOR_HEIGHT - tmp_readout_h) / 2;
|
|
tmp_readout_x = IM_CLAMP(tmp_readout_x, -readout_x_max, readout_x_max);
|
|
tmp_readout_y = IM_CLAMP(tmp_readout_y, -readout_y_max, readout_y_max);
|
|
bool changed = (tmp_readout_x != readout_x) || (tmp_readout_y != readout_y) ||
|
|
(tmp_readout_w != readout_w) || (tmp_readout_h != readout_h);
|
|
readout_x = tmp_readout_x;
|
|
readout_y = tmp_readout_y;
|
|
readout_w = tmp_readout_w;
|
|
readout_h = tmp_readout_h;
|
|
if (changed && (csi->framesize != OMV_CSI_FRAMESIZE_INVALID)) {
|
|
ret |= set_framesize(csi, csi->framesize);
|
|
}
|
|
break;
|
|
}
|
|
case OMV_CSI_IOCTL_GET_READOUT_WINDOW: {
|
|
*va_arg(ap, int *) = readout_x;
|
|
*va_arg(ap, int *) = readout_y;
|
|
*va_arg(ap, int *) = readout_w;
|
|
*va_arg(ap, int *) = readout_h;
|
|
break;
|
|
}
|
|
default: {
|
|
ret = -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int mt9m114_init(omv_csi_t *csi) {
|
|
// Initialize csi structure.
|
|
csi->reset = reset;
|
|
csi->sleep = sleep;
|
|
csi->read_reg = read_reg;
|
|
csi->write_reg = write_reg;
|
|
csi->set_pixformat = set_pixformat;
|
|
csi->set_framesize = set_framesize;
|
|
csi->set_framerate = set_framerate;
|
|
csi->set_contrast = set_contrast;
|
|
csi->set_brightness = set_brightness;
|
|
csi->set_saturation = set_saturation;
|
|
csi->set_gainceiling = set_gainceiling;
|
|
csi->set_colorbar = set_colorbar;
|
|
csi->set_auto_gain = set_auto_gain;
|
|
csi->get_gain_db = get_gain_db;
|
|
csi->set_auto_exposure = set_auto_exposure;
|
|
csi->get_exposure_us = get_exposure_us;
|
|
csi->set_auto_whitebal = set_auto_whitebal;
|
|
csi->get_rgb_gain_db = get_rgb_gain_db;
|
|
csi->set_hmirror = set_hmirror;
|
|
csi->set_vflip = set_vflip;
|
|
csi->set_special_effect = set_special_effect;
|
|
csi->ioctl = ioctl;
|
|
|
|
// Set csi flags
|
|
csi->vsync_pol = 0;
|
|
csi->hsync_pol = 0;
|
|
csi->pixck_pol = 0;
|
|
csi->frame_sync = 0;
|
|
csi->mono_bpp = 2;
|
|
csi->rgb_swap = 0;
|
|
csi->yuv_format = SUBFORMAT_ID_YVU422;
|
|
csi->cfa_format = SUBFORMAT_ID_GBRG;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif // (OMV_MT9M114_ENABLE == 1)
|