Pi Firmware: use configurable half-pixel delay where appropriate in calibration, also introduce config struct

Change-Id: I2fd47a8baff531b3a2743079950811afbef10bcb
issue_1022
David Banks 2018-06-09 20:44:34 +01:00
rodzic 18ab9c084e
commit b74f86964c
2 zmienionych plików z 138 dodań i 91 usunięć

Wyświetl plik

@ -10,25 +10,32 @@
// The number of frames to compute differences over
#define NUM_CAL_FRAMES 10
typedef struct {
int sp_base[NUM_CHANNELS];
int sp_offset[NUM_OFFSETS];
int half_px_delay;
} config_t;
// Current calibration state for mode 0..6
static int default_sp_base[NUM_CHANNELS];
static int default_sp_offset[NUM_OFFSETS];
static config_t default_config;
// Current calibration state for mode 7
static int mode7_sp_base[NUM_CHANNELS];
static int mode7_sp_offset[NUM_OFFSETS];
static config_t mode7_config;
// =============================================================
// Private methods
// =============================================================
static void write_config(int *sp_base, int *sp_offset) {
static void write_config(config_t *config) {
int sp = 0;
for (int i = 0; i < NUM_CHANNELS; i++) {
sp |= (sp_base[i] & 7) << (i * 3);
sp |= (config->sp_base[i] & 7) << (i * 3);
}
if (config->half_px_delay) {
sp |= (1 << 21);
}
for (int i = 0; i < NUM_OFFSETS; i++) {
switch (sp_offset[i]) {
switch (config->sp_offset[i]) {
case -1:
sp |= 3 << (i * 2 + 9);
break;
@ -37,7 +44,7 @@ static void write_config(int *sp_base, int *sp_offset) {
break;
}
}
for (int i = 0; i < 21; i++) {
for (int i = 0; i < 22; i++) {
RPI_SetGpioValue(SP_DATA_PIN, sp & 1);
for (int j = 0; j < 1000; j++);
RPI_SetGpioValue(SP_CLKEN_PIN, 1);
@ -52,10 +59,12 @@ static void write_config(int *sp_base, int *sp_offset) {
RPI_SetGpioValue(SP_DATA_PIN, 0);
}
static void log_sp(int *sp_base, int *sp_offset) {
log_info("sp_base = %d %d %d, sp_offset = %d %d %d %d %d %d",
sp_base[CHAN_RED], sp_base[CHAN_GREEN], sp_base[CHAN_BLUE],
sp_offset[0], sp_offset[1], sp_offset[2], sp_offset[3], sp_offset[4], sp_offset[5]);
static void log_sp(config_t *config) {
log_info("sp_base = %d %d %d; sp_offset = %d %d %d %d %d %d; half = %d",
config->sp_base[CHAN_RED], config->sp_base[CHAN_GREEN], config->sp_base[CHAN_BLUE],
config->sp_offset[0], config->sp_offset[1], config->sp_offset[2],
config->sp_offset[3], config->sp_offset[4], config->sp_offset[5],
config->half_px_delay);
}
// =============================================================
@ -64,29 +73,29 @@ static void log_sp(int *sp_base, int *sp_offset) {
static void cpld_init() {
for (int i = 0; i < NUM_CHANNELS; i++) {
mode7_sp_base[i] = 0;
default_config.sp_base[i] = 0;
mode7_config.sp_base[i] = 0;
}
for (int i = 0; i < NUM_OFFSETS; i++) {
default_sp_offset[i] = 0;
mode7_sp_offset[i] = 0;
default_config.sp_offset[i] = 0;
mode7_config.sp_offset[i] = 0;
}
default_config.half_px_delay = 0;
mode7_config.half_px_delay = 0;
}
static void cpld_calibrate(int mode7, int elk, int chars_per_line) {
int min_i[NUM_CHANNELS];
int min_metric[NUM_CHANNELS];
int *metric;
int *sp_base;
int *sp_offset;
config_t *config;
if (mode7) {
log_info("Calibrating mode 7");
sp_base = mode7_sp_base;
sp_offset = mode7_sp_offset;
config = &mode7_config;
} else {
log_info("Calibrating modes 0..6");
sp_base = default_sp_base;
sp_offset = default_sp_offset;
config = &default_config;
}
for (int i = 0; i < NUM_CHANNELS; i++) {
@ -95,16 +104,17 @@ static void cpld_calibrate(int mode7, int elk, int chars_per_line) {
}
for (int i = 0; i < NUM_OFFSETS; i++) {
sp_offset[i] = 0;
config->sp_offset[i] = 0;
}
config->half_px_delay = 0;
for (int i = 0; i <= (mode7 ? 7 : 5); i++) {
for (int j = 0; j < NUM_CHANNELS; j++) {
sp_base[j] = i;
config->sp_base[j] = i;
}
write_config(sp_base, sp_offset);
write_config(config);
metric = diff_N_frames(i, NUM_CAL_FRAMES, mode7, elk, chars_per_line);
log_info("offset = %d: metric = %d %d %d\n", i, metric[CHAN_RED], metric[CHAN_GREEN], metric[CHAN_BLUE]);
log_info("offset = %d: metric = %d %d %d", i, metric[CHAN_RED], metric[CHAN_GREEN], metric[CHAN_BLUE]);
for (int j = 0; j < NUM_CHANNELS; j++) {
if (metric[j] < min_metric[j]) {
min_metric[j] = metric[j];
@ -112,77 +122,96 @@ static void cpld_calibrate(int mode7, int elk, int chars_per_line) {
}
}
}
if (mode7) {
// If the min metric is at the limit, make use of the half pixel delay
int toggle = 0;
if (min_i[CHAN_RED] <= 1 || min_i[CHAN_GREEN] <= 1 || min_i[CHAN_BLUE] <= 1) {
if (min_i[CHAN_RED] <= 2 && min_i[CHAN_GREEN] <= 2 && min_i[CHAN_BLUE] <= 2) {
toggle = 1;
}
}
if (min_i[CHAN_RED] >= 6 || min_i[CHAN_GREEN] >= 6 || min_i[CHAN_BLUE] >= 6) {
if (min_i[CHAN_RED] >= 5 && min_i[CHAN_GREEN] >= 5 && min_i[CHAN_BLUE] >= 5) {
toggle = 1;
}
}
if (toggle) {
log_info("Enabling half pixel delay");
config->half_px_delay = 1;
min_i[CHAN_RED] ^= 4;
min_i[CHAN_GREEN] ^= 4;
min_i[CHAN_BLUE] ^= 4;
}
}
for (int j = 0; j < NUM_CHANNELS; j++) {
sp_base[j] = min_i[j];
config->sp_base[j] = min_i[j];
}
// If the metric is non zero, there is scope for further optimiation in mode 7
int ref = min_metric[CHAN_RED] + min_metric[CHAN_GREEN] + min_metric[CHAN_BLUE];
if (mode7 && ref > 0) {
log_info("Optimizing calibration: sp_base = %d %d %d",
sp_base[CHAN_RED], sp_base[CHAN_GREEN], sp_base[CHAN_BLUE]);
log_info("Optimizing calibration");
log_sp(config);
log_debug("ref = %d", ref);
for (int i = 0; i < NUM_OFFSETS; i++) {
int left = INT_MAX;
int right = INT_MAX;
if (sp_base[CHAN_RED] > 0 && sp_base[CHAN_GREEN] > 0 && sp_base[CHAN_BLUE] > 0) {
sp_offset[i] = -1;
write_config(sp_base, sp_offset);
if (config->sp_base[CHAN_RED] > 0 && config->sp_base[CHAN_GREEN] > 0 && config->sp_base[CHAN_BLUE] > 0) {
config->sp_offset[i] = -1;
write_config(config);
metric = diff_N_frames(i, NUM_CAL_FRAMES, mode7, elk, chars_per_line);
left = metric[CHAN_RED] + metric[CHAN_GREEN] + metric[CHAN_BLUE];
}
if (sp_base[CHAN_RED] < 7 && sp_base[CHAN_GREEN] < 7 && sp_base[CHAN_BLUE] < 7) {
sp_offset[i] = 1;
write_config(sp_base, sp_offset);
if (config->sp_base[CHAN_RED] < 7 && config->sp_base[CHAN_GREEN] < 7 && config->sp_base[CHAN_BLUE] < 7) {
config->sp_offset[i] = 1;
write_config(config);
metric = diff_N_frames(i, NUM_CAL_FRAMES, mode7, elk, chars_per_line);
right = metric[CHAN_RED] + metric[CHAN_GREEN] + metric[CHAN_BLUE];
}
if (left < right && left < ref) {
sp_offset[i] = -1;
config->sp_offset[i] = -1;
ref = left;
log_info("nudged %d left, metric = %d", i, ref);
} else if (right < left && right < ref) {
sp_offset[i] = 1;
config->sp_offset[i] = 1;
ref = right;
log_info("nudged %d right, metric = %d", i, ref);
} else {
sp_offset[i] = 0;
config->sp_offset[i] = 0;
}
}
}
log_info("Calibration complete");
log_sp(sp_base, sp_offset);
write_config(sp_base, sp_offset);
log_sp(config);
write_config(config);
}
static void cpld_change_mode(int mode7) {
if (mode7) {
write_config(mode7_sp_base, mode7_sp_offset);
write_config(&mode7_config);
} else {
write_config(default_sp_base, default_sp_offset);
write_config(&default_config);
}
}
static void cpld_inc_sampling_base(int mode7) {
int *sp_base = mode7 ? mode7_sp_base : default_sp_base;
int *sp_offset = mode7 ? mode7_sp_offset : default_sp_offset;
config_t *config = mode7 ? &mode7_config : &default_config;
int limit = mode7 ? 8 : 6;
for (int i = 0; i < NUM_CHANNELS; i++) {
sp_base[i] = (sp_base[i] + 1) % limit;
config->sp_base[i] = (config->sp_base[i] + 1) % limit;
}
log_sp(sp_base, sp_offset);
write_config(sp_base, sp_offset);
log_sp(config);
write_config(config);
}
static void cpld_inc_sampling_offset(int mode7) {
int *sp_base = mode7 ? mode7_sp_base : default_sp_base;
int *sp_offset = mode7 ? mode7_sp_offset : default_sp_offset;
config_t *config = mode7 ? &mode7_config : &default_config;
for (int i = 0; i < NUM_OFFSETS; i++) {
sp_offset[i] = ((sp_offset[i] + 2) % 3) - 1;
config->sp_offset[i] = ((config->sp_offset[i] + 2) % 3) - 1;
}
log_sp(sp_base, sp_offset);
write_config(sp_base, sp_offset);
log_sp(config);
write_config(config);
}
cpld_t cpld_alternative = {

Wyświetl plik

@ -10,22 +10,30 @@
// The number of frames to compute differences over
#define NUM_CAL_FRAMES 10
typedef struct {
int sp_offset[NUM_OFFSETS];
int half_px_delay;
} config_t;
// Current calibration state for mode 0..6
static int default_sp_offset[NUM_OFFSETS];
static config_t default_config;
// Current calibration state for mode 7
static int mode7_sp_offset[NUM_OFFSETS];
static config_t mode7_config;
// =============================================================
// Private methods
// =============================================================
static void write_config(int *sp_offset) {
static void write_config(config_t *config) {
int sp = 0;
for (int i = 0; i < NUM_OFFSETS; i++) {
sp |= (sp_offset[i] & 7) << (i * 3);
sp |= (config->sp_offset[i] & 7) << (i * 3);
}
for (int i = 0; i < 18; i++) {
if (config->half_px_delay) {
sp |= (1 << 18);
}
for (int i = 0; i < 19; i++) {
RPI_SetGpioValue(SP_DATA_PIN, sp & 1);
for (int j = 0; j < 1000; j++);
RPI_SetGpioValue(SP_CLKEN_PIN, 1);
@ -40,9 +48,11 @@ static void write_config(int *sp_offset) {
RPI_SetGpioValue(SP_DATA_PIN, 0);
}
static void log_sp(int *sp_offset) {
log_info("sp_offset = %d %d %d %d %d %d",
sp_offset[0], sp_offset[1], sp_offset[2], sp_offset[3], sp_offset[4], sp_offset[5]);
static void log_sp(config_t *config) {
log_info("sp_offset = %d %d %d %d %d %d; half = %d",
config->sp_offset[0], config->sp_offset[1], config->sp_offset[2],
config->sp_offset[3], config->sp_offset[4], config->sp_offset[5],
config->half_px_delay);
}
// =============================================================
@ -51,9 +61,11 @@ static void log_sp(int *sp_offset) {
static void cpld_init() {
for (int i = 0; i < NUM_OFFSETS; i++) {
default_sp_offset[i] = 0;
mode7_sp_offset[i] = 0;
default_config.sp_offset[i] = 0;
mode7_config.sp_offset[i] = 0;
}
default_config.half_px_delay = 0;
mode7_config.half_px_delay = 0;
}
static void cpld_calibrate(int mode7, int elk, int chars_per_line) {
@ -61,80 +73,86 @@ static void cpld_calibrate(int mode7, int elk, int chars_per_line) {
int min_metric;
int *rgb_metric;
int metric;
int *sp_offset;
config_t *config;
if (mode7) {
log_info("Calibrating mode 7");
sp_offset = mode7_sp_offset;
config = &mode7_config;
} else {
log_info("Calibrating modes 0..6");
sp_offset = default_sp_offset;
config = &default_config;
}
min_metric = INT_MAX;
min_i = 0;
config->half_px_delay = 0;
for (int i = 0; i <= (mode7 ? 7 : 5); i++) {
for (int j = 0; j < NUM_OFFSETS; j++) {
sp_offset[j] = i;
config->sp_offset[j] = i;
}
write_config(sp_offset);
write_config(config);
rgb_metric = diff_N_frames(i, NUM_CAL_FRAMES, mode7, elk, chars_per_line);
metric = rgb_metric[CHAN_RED] + rgb_metric[CHAN_GREEN] + rgb_metric[CHAN_BLUE];
log_info("offset = %d: metric = %d\n", i, metric);
log_info("offset = %d: metric = %d", i, metric);
if (metric < min_metric) {
min_metric = metric;
min_i = i;
}
}
for (int i = 0; i < NUM_OFFSETS; i++) {
sp_offset[i] = min_i;
// If the min metric is at the limit, make use of the half pixel delay
if (mode7 && (min_i <= 1 || min_i >= 6)) {
log_info("Enabling half pixel delay");
config->half_px_delay = 1;
min_i ^= 4;
}
for (int i = 0; i < NUM_OFFSETS; i++) {
config->sp_offset[i] = min_i;
}
write_config(sp_offset);
// If the metric is non zero, there is scope for further optimiation in mode7
int ref = min_metric;
if (mode7 && ref > 0) {
log_info("Optimizing calibration");
log_sp(sp_offset);
log_sp(config);
log_debug("ref = %d", ref);
for (int i = 0; i < NUM_CHANNELS; i++) {
int left = INT_MAX;
int right = INT_MAX;
if (sp_offset[i] > 0) {
sp_offset[i]--;
write_config(sp_offset);
if (config->sp_offset[i] > 0) {
config->sp_offset[i]--;
write_config(config);
rgb_metric = diff_N_frames(i, NUM_CAL_FRAMES, mode7, elk, chars_per_line);
left = rgb_metric[CHAN_RED] + rgb_metric[CHAN_GREEN] + rgb_metric[CHAN_BLUE];
sp_offset[i]++;
config->sp_offset[i]++;
}
if (sp_offset[i] < 7) {
sp_offset[i]++;
write_config(sp_offset);
if (config->sp_offset[i] < 7) {
config->sp_offset[i]++;
write_config(config);
rgb_metric = diff_N_frames(i, NUM_CAL_FRAMES, mode7, elk, chars_per_line);
right = rgb_metric[CHAN_RED] + rgb_metric[CHAN_GREEN] + rgb_metric[CHAN_BLUE];
sp_offset[i]--;
config->sp_offset[i]--;
}
if (left < right && left < ref) {
sp_offset[i]--;
config->sp_offset[i]--;
ref = left;
log_info("nudged %d left, metric = %d", i, ref);
} else if (right < left && right < ref) {
sp_offset[i]++;
config->sp_offset[i]++;
ref = right;
log_info("nudged %d right, metric = %d", i, ref);
}
}
}
log_info("Calibration complete:");
log_sp(sp_offset);
write_config(sp_offset);
log_info("Calibration complete");
log_sp(config);
write_config(config);
}
static void cpld_change_mode(int mode7) {
if (mode7) {
write_config(mode7_sp_offset);
write_config(&mode7_config);
} else {
write_config(default_sp_offset);
write_config(&default_config);
}
}
@ -143,13 +161,13 @@ static void cpld_inc_sampling_base(int mode7) {
}
static void cpld_inc_sampling_offset(int mode7) {
int *sp_offset = mode7 ? mode7_sp_offset : default_sp_offset;
config_t *config = mode7 ? &mode7_config : &default_config;
int limit = mode7 ? 8 : 6;
for (int i = 0; i < NUM_OFFSETS; i++) {
sp_offset[i] = (sp_offset[i] + 1) % limit;
config->sp_offset[i] = (config->sp_offset[i] + 1) % limit;
}
log_sp(sp_offset);
write_config(sp_offset);
log_sp(config);
write_config(config);
}
cpld_t cpld_normal = {