From 0db17454599bea046c7e65bc1d6ad7a449088b1a Mon Sep 17 00:00:00 2001 From: David Banks Date: Wed, 28 Jun 2017 14:44:34 +0100 Subject: [PATCH] Extended calibration to detect Electron Change-Id: I8893c014b18ac199ecc76d3cec4d89d23e13f76c --- src/defs.h | 3 +- src/rgb_to_fb.S | 4 ++- src/rgb_to_hdmi.c | 91 +++++++++++++++++++++++++++++++++++++---------- 3 files changed, 77 insertions(+), 21 deletions(-) diff --git a/src/defs.h b/src/defs.h index 90539888..80468a5b 100644 --- a/src/defs.h +++ b/src/defs.h @@ -27,11 +27,12 @@ #define BIT_MODE7 0x01 #define BIT_DRAW_BUFFER 0x02 #define BIT_DISP_BUFFER 0x04 -#define BIT_FIELD_TYPE 0x08 +#define BIT_ELK 0x08 #define BIT_PROBE 0x10 #define BIT_CALIBRATE 0x20 #define BIT_CAL_COUNT 0x40 #define BIT_INITIALIZE 0x80 +#define BIT_FIELD_TYPE 0x100 // R0 return value bits #define BIT_CAL 0x02 diff --git a/src/rgb_to_fb.S b/src/rgb_to_fb.S index 83c3b6c8..9b2e758f 100644 --- a/src/rgb_to_fb.S +++ b/src/rgb_to_fb.S @@ -113,7 +113,7 @@ rgb_to_fb: bleq clear_screen // clear all the state bits apart from the following: - bic r3, r3, #~(BIT_MODE7 | BIT_PROBE | BIT_CALIBRATE | BIT_CAL_COUNT | BIT_INITIALIZE) + bic r3, r3, #~(BIT_MODE7 | BIT_PROBE | BIT_CALIBRATE | BIT_CAL_COUNT | BIT_INITIALIZE | BIT_ELK) // write to buffer 0, display buffer 1 orr r3, r3, #BIT_DISP_BUFFER @@ -190,6 +190,8 @@ frame: // Correct the relative positions of the odd and even frames // In Mode 0..6, reduce the number of active lines by one for the even frame // In Mode 7, increment the frame buffer pointer by one line for the even field + tst r3, #BIT_ELK + bne skip_line_loop tst r3, #BIT_FIELD_TYPE beq skip_line_loop tst r3, #BIT_MODE7 diff --git a/src/rgb_to_hdmi.c b/src/rgb_to_hdmi.c index 7c4a8dfe..122937bd 100644 --- a/src/rgb_to_hdmi.c +++ b/src/rgb_to_hdmi.c @@ -346,7 +346,7 @@ void init_hardware() { static char last[SCREEN_HEIGHT * 336] __attribute__((aligned(32))); -int diff_N_frames(int sp, int n, int mode7, int chars_per_line) { +int diff_N_frames(int sp, int n, int mode7, int elk, int chars_per_line) { int sum = 0; int min = INT_MAX; @@ -361,11 +361,11 @@ int diff_N_frames(int sp, int n, int mode7, int chars_per_line) { // In mode 0..6, set BIT_CAL_COUNT to 1 (capture 1 field) // In mode 7, set BIT_CAL_COUNT to 0 (capture two fields, doesn't matter whether odd-even or even-odd) - unsigned int flags = mode7 | BIT_CALIBRATE | (mode7 ? 0 : BIT_CAL_COUNT); + unsigned int flags = mode7 | BIT_CALIBRATE | (mode7 ? 0 : BIT_CAL_COUNT) | (elk ? BIT_ELK : 0); #ifdef INSTRUMENT_CAL t = _get_cycle_counter(); -#endif +#endif // Grab an initial frame rgb_to_fb(fb, chars_per_line, pitch, flags); #ifdef INSTRUMENT_CAL @@ -428,7 +428,7 @@ int diff_N_frames(int sp, int n, int mode7, int chars_per_line) { return sum; } -int total_N_frames(int sp, int n, int mode7, int chars_per_line) { +int total_N_frames(int sp, int n, int mode7, int elk, int chars_per_line) { int sum = 0; int min = INT_MAX; @@ -442,7 +442,7 @@ int total_N_frames(int sp, int n, int mode7, int chars_per_line) { // In mode 0..6, set BIT_CAL_COUNT to 1 (capture 1 field) // In mode 7, set BIT_CAL_COUNT to 0 (capture two fields, doesn't matter whether odd-even or even-odd) - unsigned int flags = mode7 | BIT_CALIBRATE | (mode7 ? 0 : BIT_CAL_COUNT); + unsigned int flags = mode7 | BIT_CALIBRATE | (mode7 ? 0 : BIT_CAL_COUNT) | (elk ? BIT_ELK : 0); for (int i = 0; i < n; i++) { int total = 0; @@ -488,19 +488,21 @@ int total_N_frames(int sp, int n, int mode7, int chars_per_line) { return sum; } -void calibrate_sampling(int mode7, int chars_per_line) { - int i; - int j; - int min_i; - int min_metric; - int metric; - - // Wait for the cal button to be released +// Wait for the cal button to be released +void wait_for_cal_release() { int cal_bit = 0; do { cal_bit = ((*(volatile uint32_t *)(PERIPHERAL_BASE + 0x200034)) >> CAL_PIN) & 1; log_debug("cal_bit = %d", cal_bit); } while (cal_bit == 0); +} + +void calibrate_sampling(int mode7, int elk, int chars_per_line) { + int i; + int j; + int min_i; + int min_metric; + int metric; if (mode7) { log_info("Calibrating mode 7"); @@ -512,7 +514,7 @@ void calibrate_sampling(int mode7, int chars_per_line) { sp_mode7[j] = i; } init_sampling_point_register(sp_mode7, sp_default); - metric = diff_N_frames(i, NUM_CAL_FRAMES, mode7, chars_per_line); + metric = diff_N_frames(i, NUM_CAL_FRAMES, mode7, elk, chars_per_line); if (metric < min_metric) { min_metric = metric; min_i = i; @@ -534,13 +536,13 @@ void calibrate_sampling(int mode7, int chars_per_line) { if (sp_mode7[i] > 0) { sp_mode7[i]--; init_sampling_point_register(sp_mode7, sp_default); - left = diff_N_frames(i, NUM_CAL_FRAMES, mode7, chars_per_line); + left = diff_N_frames(i, NUM_CAL_FRAMES, mode7, elk, chars_per_line); sp_mode7[i]++; } if (sp_mode7[i] < 7) { sp_mode7[i]++; init_sampling_point_register(sp_mode7, sp_default); - right = diff_N_frames(i, NUM_CAL_FRAMES, mode7, chars_per_line); + right = diff_N_frames(i, NUM_CAL_FRAMES, mode7, elk, chars_per_line); sp_mode7[i]--; } if (left < right && left < ref) { @@ -562,7 +564,7 @@ void calibrate_sampling(int mode7, int chars_per_line) { min_i = 0; for (i = 0; i <= 5; i++) { init_sampling_point_register(sp_mode7, i); - metric = diff_N_frames(i, NUM_CAL_FRAMES, mode7, chars_per_line); + metric = diff_N_frames(i, NUM_CAL_FRAMES, mode7, elk, chars_per_line); if (metric < min_metric) { min_metric = metric; min_i = i; @@ -574,7 +576,54 @@ void calibrate_sampling(int mode7, int chars_per_line) { } } +int test_for_elk(int mode7, int chars_per_line) { + + // If mode 7, then assume the Beeb + if (mode7) { + return 0; + } + + unsigned int flags = BIT_CALIBRATE | BIT_CAL_COUNT; + unsigned char *fb1 = fb; + unsigned char *fb2 = fb + SCREEN_HEIGHT * pitch; + + // Grab one field + rgb_to_fb(fb1, chars_per_line, pitch, flags); + + // Grab second field + rgb_to_fb(fb2, chars_per_line, pitch, flags); + + unsigned int min_diff = INT_MAX; + unsigned int min_offset = 0; + + for (int offset = -2; offset <= 2; offset += 2) { + + uint32_t *p1 = (uint32_t *)(fb1 + 2 * pitch); + uint32_t *p2 = (uint32_t *)(fb2 + 2 * pitch + offset * pitch); + unsigned int diff = 0; + for (int i = 0; i < (SCREEN_HEIGHT - 4) * pitch; i += 4) { + uint32_t d = (*p1++) ^ (*p2++); + while (d) { + if (d & 0x0F) { + diff++; + } + d >>= 4; + } + } + if (diff < min_diff) { + min_diff = diff; + min_offset = offset; + } + log_debug("offset = %d, diff = %u", offset, diff); + + } + log_debug("min offset = %d", min_offset); + return min_offset != 0; +} + + void rgb_to_hdmi_main() { + int elk; int mode7; int last_mode7; int result; @@ -586,6 +635,7 @@ void rgb_to_hdmi_main() { // Determine initial mode mode7 = rgb_to_fb(fb, 0, 0, BIT_PROBE); + elk = 0; while (1) { log_debug("Setting mode7 = %d", mode7); @@ -600,12 +650,15 @@ void rgb_to_hdmi_main() { do { log_debug("Entering rgb_to_fb"); - result = rgb_to_fb(fb, chars_per_line, pitch, mode7 | BIT_INITIALIZE); + result = rgb_to_fb(fb, chars_per_line, pitch, mode7 | BIT_INITIALIZE | (elk ? BIT_ELK : 0)); log_debug("Leaving rgb_to_fb, result= %d", result); if (result & BIT_CAL) { + wait_for_cal_release(); + elk = test_for_elk(mode7, chars_per_line); + log_debug("Elk mode = %d", elk); for (int c = 0; c < NUM_CAL_PASSES; c++) { - calibrate_sampling(mode7, chars_per_line); + calibrate_sampling(mode7, elk, chars_per_line); } }