Extended calibration to detect Electron

Change-Id: I8893c014b18ac199ecc76d3cec4d89d23e13f76c
issue_1022
David Banks 2017-06-28 14:44:34 +01:00
rodzic c9c7e5957e
commit 0db1745459
3 zmienionych plików z 77 dodań i 21 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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);
}
}