kopia lustrzana https://github.com/hoglet67/RGBtoHDMI
Pi Firmware: use configurable half-pixel delay where appropriate in calibration, also introduce config struct
Change-Id: I2fd47a8baff531b3a2743079950811afbef10bcbissue_1022
rodzic
18ab9c084e
commit
b74f86964c
|
@ -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 = {
|
||||
|
|
|
@ -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 = {
|
||||
|
|
Ładowanie…
Reference in New Issue