mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
boards/NICLAV: Add readout control to driver and fix image orientation.
This commit is contained in:
parent
1a264aca54
commit
c64e564943
@ -27,6 +27,9 @@
|
||||
// Sensor external clock timer frequency.
|
||||
#define OMV_XCLK_FREQUENCY (12000000)
|
||||
|
||||
// GC4145 Sensor Settings
|
||||
#define OMV_GC2145_ROTATE (1)
|
||||
|
||||
// Enable hardware JPEG
|
||||
#define OMV_HARDWARE_JPEG (1)
|
||||
|
||||
|
||||
@ -14,7 +14,6 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "cambus.h"
|
||||
#include "sensor.h"
|
||||
@ -22,8 +21,26 @@
|
||||
#include "gc2145_regs.h"
|
||||
#include "py/mphal.h"
|
||||
|
||||
#define GC_MAX_WIN_W (1600)
|
||||
#define GC_MAX_WIN_H (1200)
|
||||
#define BLANK_LINES 16
|
||||
#define DUMMY_LINES 16
|
||||
|
||||
#define BLANK_COLUMNS 0
|
||||
#define DUMMY_COLUMNS 8
|
||||
|
||||
#define SENSOR_WIDTH 1616
|
||||
#define SENSOR_HEIGHT 1248
|
||||
|
||||
#define ACTIVE_SENSOR_WIDTH (SENSOR_WIDTH - BLANK_COLUMNS - (2 * DUMMY_COLUMNS))
|
||||
#define ACTIVE_SENSOR_HEIGHT (SENSOR_HEIGHT - BLANK_LINES - (2 * DUMMY_LINES))
|
||||
|
||||
#define DUMMY_WIDTH_BUFFER 16
|
||||
#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;
|
||||
|
||||
// SLAVE ADDR 0x78
|
||||
static const uint8_t default_regs[][2] = {
|
||||
@ -60,7 +77,11 @@ static const uint8_t default_regs[][2] = {
|
||||
{0x9a, 0x0E}, // Subsample mode
|
||||
|
||||
{0x12, 0x2e}, //
|
||||
#if (OMV_GC2145_ROTATE == 1)
|
||||
{0x17, 0x17}, // Analog Mode 1 (vflip/mirror[1:0])
|
||||
#else
|
||||
{0x17, 0x14}, // Analog Mode 1 (vflip/mirror[1:0])
|
||||
#endif
|
||||
{0x18, 0x22}, // Analog Mode 2
|
||||
{0x19, 0x0e},
|
||||
{0x1a, 0x01},
|
||||
@ -700,6 +721,12 @@ static int reset(sensor_t *sensor)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
readout_x = 0;
|
||||
readout_y = 0;
|
||||
|
||||
readout_w = ACTIVE_SENSOR_WIDTH;
|
||||
readout_h = ACTIVE_SENSOR_HEIGHT;
|
||||
|
||||
// Write default regsiters
|
||||
for (int i = 0; default_regs[i][0]; i++) {
|
||||
ret |= cambus_writeb(&sensor->bus, sensor->slv_addr, default_regs[i][0], default_regs[i][1]);
|
||||
@ -804,56 +831,62 @@ static int set_framesize(sensor_t *sensor, framesize_t framesize)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
uint16_t win_w;
|
||||
uint16_t win_h;
|
||||
|
||||
uint16_t w = resolution[framesize][0];
|
||||
uint16_t h = resolution[framesize][1];
|
||||
|
||||
if (w < resolution[FRAMESIZE_QVGA][0] && h < resolution[FRAMESIZE_QVGA][1]) {
|
||||
win_w = w * 5;
|
||||
win_h = h * 5;
|
||||
} else if (w < resolution[FRAMESIZE_VGA][0] && h < resolution[FRAMESIZE_VGA][1]) {
|
||||
win_w = w * 3;
|
||||
win_h = h * 3;
|
||||
} else if (w < resolution[FRAMESIZE_SVGA][0] && h < resolution[FRAMESIZE_SVGA][1]) {
|
||||
win_w = w * 2;
|
||||
win_h = h * 2;
|
||||
} else if (w <= resolution[FRAMESIZE_UXGA][0] && h <= resolution[FRAMESIZE_UXGA][1]) {
|
||||
// For bigger frames use full UXGA window.
|
||||
win_w = resolution[FRAMESIZE_UXGA][0];
|
||||
win_h = resolution[FRAMESIZE_UXGA][1];
|
||||
} else {
|
||||
// Invalid resolution.
|
||||
if ((w > ACTIVE_SENSOR_WIDTH) || (h > ACTIVE_SENSOR_HEIGHT)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t c_ratio = win_w / w;
|
||||
uint16_t r_ratio = win_h / h;
|
||||
// Step 0: Clamp readout settings.
|
||||
|
||||
if (c_ratio % 2 == 0) {
|
||||
c_ratio --;
|
||||
}
|
||||
if (r_ratio % 2 == 0) {
|
||||
r_ratio --;
|
||||
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_MAX(IM_MIN(readout_x, readout_x_max), -readout_x_max);
|
||||
readout_y = IM_MAX(IM_MIN(readout_y, readout_y_max), -readout_y_max);
|
||||
|
||||
// Step 1: Determine sub-readout window.
|
||||
|
||||
uint16_t ratio = fast_floorf(IM_MIN(readout_w / ((float) w), readout_h / ((float) h)));
|
||||
|
||||
// Limit the maximum amount of scaling allowed to keep the frame rate up.
|
||||
ratio = IM_MIN(ratio, 3);
|
||||
|
||||
if (!(ratio % 2)) { // camera outputs messed up bayer images at even ratios for some reason...
|
||||
ratio -= 1;
|
||||
}
|
||||
|
||||
uint16_t x = (((win_w / c_ratio) - w) / 2);
|
||||
uint16_t y = (((win_h / r_ratio) - h) / 2);
|
||||
uint16_t sub_readout_w = w * ratio;
|
||||
uint16_t sub_readout_h = h * ratio;
|
||||
|
||||
uint16_t win_x = ((GC_MAX_WIN_W - win_w) / 2);
|
||||
uint16_t win_y = ((GC_MAX_WIN_H - win_h) / 2);
|
||||
// Step 2: Determine horizontal and vertical start and end points.
|
||||
|
||||
// Set readout window first.
|
||||
ret |= set_window(sensor, 0x09, win_x, win_y, win_w + 16, win_h + 8);
|
||||
uint16_t sensor_w = sub_readout_w + DUMMY_WIDTH_BUFFER; // camera hardware needs dummy pixels to sync
|
||||
uint16_t sensor_h = sub_readout_h + DUMMY_HEIGHT_BUFFER; // camera hardware needs dummy lines to sync
|
||||
|
||||
uint16_t sensor_x = IM_MAX(IM_MIN((((ACTIVE_SENSOR_WIDTH - sensor_w) / 4) - (readout_x / 2)) * 2,
|
||||
ACTIVE_SENSOR_WIDTH - sensor_w), -(DUMMY_WIDTH_BUFFER / 2)) + DUMMY_COLUMNS; // must be multiple of 2
|
||||
|
||||
uint16_t sensor_y = IM_MAX(IM_MIN((((ACTIVE_SENSOR_HEIGHT - sensor_h) / 4) - (readout_y / 2)) * 2,
|
||||
ACTIVE_SENSOR_HEIGHT - sensor_h), -(DUMMY_HEIGHT_BUFFER / 2)) + DUMMY_LINES; // must be multiple of 2
|
||||
|
||||
// Step 3: Write regs.
|
||||
|
||||
// Set Readout window first.
|
||||
ret |= set_window(sensor, 0x09, sensor_x, sensor_y, sensor_w, sensor_h);
|
||||
|
||||
// Set cropping window next.
|
||||
ret |= set_window(sensor, 0x91, x, y, w, h);
|
||||
ret |= set_window(sensor, 0x91, 0, 0, w, h);
|
||||
|
||||
// Enable crop
|
||||
ret |= cambus_writeb(&sensor->bus, sensor->slv_addr, 0x90, 0x01);
|
||||
|
||||
// Set Sub-sampling ratio and mode
|
||||
ret |= cambus_writeb(&sensor->bus, sensor->slv_addr, 0x99, ((r_ratio << 4) | c_ratio));
|
||||
ret |= cambus_writeb(&sensor->bus, sensor->slv_addr, 0x99, ((ratio << 4) | (ratio)));
|
||||
ret |= cambus_writeb(&sensor->bus, sensor->slv_addr, 0x9A, 0x0E);
|
||||
|
||||
return ret;
|
||||
@ -867,7 +900,7 @@ static int set_hmirror(sensor_t *sensor, int enable)
|
||||
// P0 regs
|
||||
ret |= cambus_writeb(&sensor->bus, sensor->slv_addr, 0xFE, 0x00);
|
||||
ret |= cambus_readb(&sensor->bus, sensor->slv_addr, REG_AMODE1, ®);
|
||||
ret |= cambus_writeb(&sensor->bus, sensor->slv_addr, REG_AMODE1, REG_AMODE1_SET_HMIRROR(reg, enable)) ;
|
||||
ret |= cambus_writeb(&sensor->bus, sensor->slv_addr, REG_AMODE1, REG_AMODE1_SET_HMIRROR(reg, enable));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -879,7 +912,7 @@ static int set_vflip(sensor_t *sensor, int enable)
|
||||
// P0 regs
|
||||
ret |= cambus_writeb(&sensor->bus, sensor->slv_addr, 0xFE, 0x00);
|
||||
ret |= cambus_readb(&sensor->bus, sensor->slv_addr, REG_AMODE1, ®);
|
||||
ret |= cambus_writeb(&sensor->bus, sensor->slv_addr, REG_AMODE1, REG_AMODE1_SET_VMIRROR(reg, enable)) ;
|
||||
ret |= cambus_writeb(&sensor->bus, sensor->slv_addr, REG_AMODE1, REG_AMODE1_SET_VMIRROR(reg, enable));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -903,6 +936,49 @@ static int set_auto_whitebal(sensor_t *sensor, int enable, float r_gain_db, floa
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ioctl(sensor_t *sensor, int request, va_list ap)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (request) {
|
||||
case 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_MAX(IM_MIN(va_arg(ap, int), ACTIVE_SENSOR_WIDTH),
|
||||
resolution[sensor->framesize][0]);
|
||||
int tmp_readout_h = IM_MAX(IM_MIN(va_arg(ap, int), ACTIVE_SENSOR_HEIGHT),
|
||||
resolution[sensor->framesize][1]);
|
||||
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_MAX(IM_MIN(tmp_readout_x, readout_x_max), -readout_x_max);
|
||||
tmp_readout_y = IM_MAX(IM_MIN(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 && (sensor->framesize != FRAMESIZE_INVALID)) {
|
||||
set_framesize(sensor, sensor->framesize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 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 gc2145_init(sensor_t *sensor)
|
||||
{
|
||||
// Initialize sensor structure.
|
||||
@ -916,6 +992,7 @@ int gc2145_init(sensor_t *sensor)
|
||||
sensor->set_vflip = set_vflip;
|
||||
sensor->set_auto_exposure = set_auto_exposure;
|
||||
sensor->set_auto_whitebal = set_auto_whitebal;
|
||||
sensor->ioctl = ioctl;
|
||||
|
||||
// Set sensor flags
|
||||
sensor->hw_flags.vsync = 0;
|
||||
@ -925,7 +1002,6 @@ int gc2145_init(sensor_t *sensor)
|
||||
sensor->hw_flags.jpege = 0;
|
||||
sensor->hw_flags.gs_bpp = 2;
|
||||
sensor->hw_flags.rgb_swap = 1;
|
||||
sensor->hw_flags.yuv_order = SENSOR_HW_FLAGS_YVU422;
|
||||
sensor->hw_flags.bayer = SENSOR_HW_FLAGS_BAYER_GBRG;
|
||||
|
||||
return 0;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user