kopia lustrzana https://github.com/hoglet67/RGBtoHDMI
Pi Firmware: Added alternative pixel sampling modes (subsample, pixel double)
Change-Id: If6a1bd8219cc5a4d650a63692f07f922e40e3d7epull/29/head
rodzic
75e7d7cf59
commit
522138da0d
|
@ -63,6 +63,8 @@ file( GLOB core_files
|
|||
rgb_to_hdmi.c
|
||||
rgb_to_fb.S
|
||||
capture_line_default_4bpp.S
|
||||
capture_line_default_4bpp_double.S
|
||||
capture_line_default_4bpp_subsample.S
|
||||
capture_line_default_8bpp.S
|
||||
capture_line_atom_4bpp.S
|
||||
capture_line_atom_8bpp.S
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
#include "rpi-base.h"
|
||||
#include "defs.h"
|
||||
|
||||
#include "macros.S"
|
||||
|
||||
.text
|
||||
|
||||
.global capture_line_default_4bpp_double
|
||||
|
||||
.macro CAPTURE_BITS_DOUBLE
|
||||
// Pixel 0 in GPIO 4.. 2 -> 7.. 4 and 3.. 0
|
||||
// Pixel 1 in GPIO 7.. 5 -> 15..12 and 11.. 8
|
||||
// Pixel 2 in GPIO 10.. 8 -> 23..20 and 19..16
|
||||
// Pixel 3 in GPIO 13..11 -> 31..28 and 27..24
|
||||
|
||||
and r10, r8, #(7 << PIXEL_BASE)
|
||||
and r9, r8, #(7 << (PIXEL_BASE + 3))
|
||||
mov r10, r10, lsl #(4 - PIXEL_BASE)
|
||||
orr r10, r10, r9, lsl #(12 - (PIXEL_BASE + 3))
|
||||
|
||||
and r9, r8, #(7 << (PIXEL_BASE + 6))
|
||||
and r8, r8, #(7 << (PIXEL_BASE + 9))
|
||||
orr r10, r10, r9, lsl #(20 - (PIXEL_BASE + 6))
|
||||
orr r10, r10, r8, lsl #(28 - (PIXEL_BASE + 9))
|
||||
|
||||
// Pixel double
|
||||
orr r10, r10, lsr #4
|
||||
.endm
|
||||
|
||||
// The capture line function is provided the following:
|
||||
// r0 = pointer to current line in frame buffer
|
||||
// r1 = number of 8-pixel blocks to capture (=param_chars_per_line)
|
||||
// r2 = frame buffer line pitch in bytes (=param_fb_pitch)
|
||||
// r3 = flags register
|
||||
// r4 = GPLEV0 constant
|
||||
// r5 = frame buffer height (=param_fb_height)
|
||||
// r6 = scan line count modulo 10
|
||||
//
|
||||
// All registers are available as scratch registers (i.e. nothing needs to be preserved)
|
||||
|
||||
capture_line_default_4bpp_double:
|
||||
|
||||
push {lr}
|
||||
mov r6, #0
|
||||
mov r7, #0
|
||||
tst r3, #BIT_VSYNC_MARKER
|
||||
ldrne r7, =0x11111111
|
||||
loop:
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
|
||||
CAPTURE_BITS_DOUBLE // input in r8, result in r10, corrupts r9/r14
|
||||
|
||||
// Orr in the VSync indicator
|
||||
|
||||
orr r10, r10, r7
|
||||
|
||||
// Line double always in Modes 0-6 regardless of interlace
|
||||
// On the multi core Pi this introduces stalling artefacts
|
||||
#ifndef HAS_MULTICORE
|
||||
tst r3, #BIT_SCANLINES
|
||||
streq r10, [r0, r2]
|
||||
strne r6, [r0, r2]
|
||||
#endif
|
||||
str r10, [r0], #4
|
||||
subs r1, r1, #1
|
||||
bne loop
|
||||
|
||||
pop {pc}
|
|
@ -0,0 +1,83 @@
|
|||
#include "rpi-base.h"
|
||||
#include "defs.h"
|
||||
|
||||
#include "macros.S"
|
||||
|
||||
.text
|
||||
|
||||
.global capture_line_default_4bpp_subsample
|
||||
|
||||
.macro CAPTURE_LOW_BITS_SUBSAMPLE
|
||||
// Pixel 0 in GPIO 4.. 2 -> 7.. 4
|
||||
// Pixel 1 ignored
|
||||
// Pixel 2 in GPIO 10.. 8 -> 15..12
|
||||
// Pixel 3 ignored
|
||||
|
||||
and r10, r8, #(7 << PIXEL_BASE)
|
||||
mov r10, r10, lsl #(4 - PIXEL_BASE)
|
||||
|
||||
and r9, r8, #(7 << (PIXEL_BASE + 6))
|
||||
orr r10, r10, r9, lsl #(6 - PIXEL_BASE)
|
||||
|
||||
.endm
|
||||
|
||||
.macro CAPTURE_HIGH_BITS_SUBSAMPLE
|
||||
// Pixel 4 in GPIO 4.. 2 -> 23..20
|
||||
// Pixel 5 ignored
|
||||
// Pixel 6 in GPIO 10.. 8 -> 31..28
|
||||
// Pixel 7 ignored
|
||||
|
||||
and r9, r8, #(7 << PIXEL_BASE)
|
||||
orr r10, r10, r9, lsl #(20 - PIXEL_BASE)
|
||||
|
||||
and r9, r8, #(7 << (PIXEL_BASE + 6))
|
||||
orr r10, r10, r9, lsl #(22 - PIXEL_BASE)
|
||||
|
||||
.endm
|
||||
|
||||
// The capture line function is provided the following:
|
||||
// r0 = pointer to current line in frame buffer
|
||||
// r1 = number of 8-pixel blocks to capture (=param_chars_per_line)
|
||||
// r2 = frame buffer line pitch in bytes (=param_fb_pitch)
|
||||
// r3 = flags register
|
||||
// r4 = GPLEV0 constant
|
||||
// r5 = frame buffer height (=param_fb_height)
|
||||
// r6 = scan line count modulo 10
|
||||
//
|
||||
// All registers are available as scratch registers (i.e. nothing needs to be preserved)
|
||||
|
||||
capture_line_default_4bpp_subsample:
|
||||
|
||||
push {lr}
|
||||
mov r6, #0
|
||||
mov r7, #0
|
||||
tst r3, #BIT_VSYNC_MARKER
|
||||
ldrne r7, =0x11111111
|
||||
loop:
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
|
||||
CAPTURE_LOW_BITS_SUBSAMPLE // input in r8, result in r10, corrupts r9/r14
|
||||
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
|
||||
CAPTURE_HIGH_BITS_SUBSAMPLE // input in r8, result in r10, corrupts r9/r14
|
||||
|
||||
// Pixel double
|
||||
orr r10, r10, lsr #4
|
||||
|
||||
// Orr in the VSync indicator
|
||||
|
||||
orr r10, r10, r7
|
||||
|
||||
// Line double always in Modes 0-6 regardless of interlace
|
||||
// On the multi core Pi this introduces stalling artefacts
|
||||
#ifndef HAS_MULTICORE
|
||||
tst r3, #BIT_SCANLINES
|
||||
streq r10, [r0, r2]
|
||||
strne r6, [r0, r2]
|
||||
#endif
|
||||
str r10, [r0], #4
|
||||
subs r1, r1, #1
|
||||
bne loop
|
||||
|
||||
pop {pc}
|
|
@ -5,6 +5,7 @@
|
|||
#include <string.h>
|
||||
#include "defs.h"
|
||||
#include "cpld.h"
|
||||
#include "geometry.h"
|
||||
#include "osd.h"
|
||||
#include "logging.h"
|
||||
#include "rgb_to_fb.h"
|
||||
|
@ -392,7 +393,13 @@ static void cpld_set_mode(capture_info_t *capinfo, int mode) {
|
|||
if (capinfo->bpp == 8) {
|
||||
capinfo->capture_line = capture_line_default_8bpp;
|
||||
} else {
|
||||
capinfo->capture_line = capture_line_default_4bpp;
|
||||
if (capinfo->px_sampling == PS_DOUBLE) {
|
||||
capinfo->capture_line = capture_line_default_4bpp_double;
|
||||
} else if (capinfo->px_sampling == PS_SUBSAMPLE) {
|
||||
capinfo->capture_line = capture_line_default_4bpp_subsample;
|
||||
} else {
|
||||
capinfo->capture_line = capture_line_default_4bpp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,6 +127,7 @@ typedef struct {
|
|||
int v_offset; // vertical offset (in lines)
|
||||
int ncapture; // number of fields to capture, or -1 to capture forever
|
||||
int (*capture_line)(); // the capture line function to use
|
||||
int px_sampling; // whether to sample normally, sub-sample or pixel double
|
||||
} capture_info_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -11,21 +11,29 @@ enum {
|
|||
FB_BPP,
|
||||
CLOCK,
|
||||
LINE_LEN,
|
||||
CLOCK_PPM
|
||||
CLOCK_PPM,
|
||||
PX_SAMPLING
|
||||
};
|
||||
|
||||
static const char *px_sampling_names[] = {
|
||||
"Normal",
|
||||
"Sub Sample",
|
||||
"Pixel Double"
|
||||
};
|
||||
|
||||
static param_t params[] = {
|
||||
{ H_OFFSET, "H offset", 0, 59, 1 },
|
||||
{ V_OFFSET, "V offset", 0, 39, 1 },
|
||||
{ H_WIDTH, "H width", 1, 100, 1 },
|
||||
{ V_HEIGHT, "V height", 1, 300, 1 },
|
||||
{ FB_WIDTH, "FB width", 400, 800, 1 },
|
||||
{ FB_HEIGHT, "FB height", 320, 600, 1 },
|
||||
{ FB_BPP, "FB bits/pixel", 4, 8, 4 },
|
||||
{ CLOCK, "Clock freq", 75000000, 100000000, 1 },
|
||||
{ LINE_LEN, "Line length", 1000, 9999, 1 },
|
||||
{ CLOCK_PPM, "Clock tolerance", 0, 100000, 1 },
|
||||
{ -1, NULL, 0, 0, 0 }
|
||||
{ H_OFFSET, "H offset", 0, 59, 1 },
|
||||
{ V_OFFSET, "V offset", 0, 39, 1 },
|
||||
{ H_WIDTH, "H width", 1, 100, 1 },
|
||||
{ V_HEIGHT, "V height", 1, 300, 1 },
|
||||
{ FB_WIDTH, "FB width", 400, 800, 1 },
|
||||
{ FB_HEIGHT, "FB height", 320, 600, 1 },
|
||||
{ FB_BPP, "FB bits/pixel", 4, 8, 4 },
|
||||
{ CLOCK, "Clock freq", 75000000, 100000000, 1 },
|
||||
{ LINE_LEN, "Line length", 1000, 9999, 1 },
|
||||
{ CLOCK_PPM, "Clock tolerance", 0, 100000, 1 },
|
||||
{ PX_SAMPLING, "Pixel sampling", 0, NUM_PS-1, 1 },
|
||||
{ -1, NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
@ -39,6 +47,7 @@ typedef struct {
|
|||
int clock; // cpld clock (in Hz)
|
||||
int line_len; // number of clocks per horizontal line
|
||||
int clock_ppm; // cpld tolerance (in ppm)
|
||||
int px_sampling; // pixel sampling mode
|
||||
} geometry_t;
|
||||
|
||||
static int mode7;
|
||||
|
@ -64,26 +73,28 @@ static void update_param_range() {
|
|||
|
||||
void geometry_init(int version) {
|
||||
// These are Beeb specific defaults so the geometry property can be ommitted
|
||||
mode7_geometry.h_offset = 24;
|
||||
mode7_geometry.v_offset = 21;
|
||||
mode7_geometry.h_width = 504 / (32 / 4);
|
||||
mode7_geometry.v_height = 270;
|
||||
mode7_geometry.fb_width = 504;
|
||||
mode7_geometry.fb_height = 540;
|
||||
mode7_geometry.fb_bpp = 4;
|
||||
mode7_geometry.clock = 96000000;
|
||||
mode7_geometry.line_len = 96 * 64;
|
||||
mode7_geometry.clock_ppm = 5000;
|
||||
default_geometry.h_offset = 32;
|
||||
default_geometry.v_offset = 21;
|
||||
default_geometry.h_width = 672 / (32 / 4);
|
||||
default_geometry.v_height = 270;
|
||||
default_geometry.fb_width = 672;
|
||||
default_geometry.fb_height = 540;
|
||||
default_geometry.fb_bpp = 4;
|
||||
default_geometry.clock = 96000000;
|
||||
default_geometry.line_len = 96 * 64;
|
||||
default_geometry.clock_ppm = 5000;
|
||||
mode7_geometry.h_offset = 24;
|
||||
mode7_geometry.v_offset = 21;
|
||||
mode7_geometry.h_width = 504 / (32 / 4);
|
||||
mode7_geometry.v_height = 270;
|
||||
mode7_geometry.fb_width = 504;
|
||||
mode7_geometry.fb_height = 540;
|
||||
mode7_geometry.fb_bpp = 4;
|
||||
mode7_geometry.clock = 96000000;
|
||||
mode7_geometry.line_len = 96 * 64;
|
||||
mode7_geometry.clock_ppm = 5000;
|
||||
mode7_geometry.px_sampling = PS_NORMAL;
|
||||
default_geometry.h_offset = 32;
|
||||
default_geometry.v_offset = 21;
|
||||
default_geometry.h_width = 672 / (32 / 4);
|
||||
default_geometry.v_height = 270;
|
||||
default_geometry.fb_width = 672;
|
||||
default_geometry.fb_height = 540;
|
||||
default_geometry.fb_bpp = 4;
|
||||
default_geometry.clock = 96000000;
|
||||
default_geometry.line_len = 96 * 64;
|
||||
default_geometry.clock_ppm = 5000;
|
||||
default_geometry.px_sampling = PS_NORMAL;
|
||||
// For backwards compatibility with CPLDv1
|
||||
int supports_delay = (((version >> VERSION_DESIGN_BIT) & 0x0F) == 0) &&
|
||||
(((version >> VERSION_MAJOR_BIT ) & 0x0F) >= 2);
|
||||
|
@ -123,10 +134,19 @@ int geometry_get_value(int num) {
|
|||
return geometry->line_len;
|
||||
case CLOCK_PPM:
|
||||
return geometry->clock_ppm;
|
||||
case PX_SAMPLING:
|
||||
return geometry->px_sampling;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *geometry_get_value_string(int num) {
|
||||
if (num == PX_SAMPLING) {
|
||||
return px_sampling_names[geometry_get_value(num)];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void geometry_set_value(int num, int value) {
|
||||
switch (num) {
|
||||
case H_OFFSET:
|
||||
|
@ -160,6 +180,9 @@ void geometry_set_value(int num, int value) {
|
|||
case CLOCK_PPM:
|
||||
geometry->clock_ppm = value;
|
||||
break;
|
||||
case PX_SAMPLING:
|
||||
geometry->px_sampling = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,6 +198,7 @@ void geometry_get_fb_params(capture_info_t *capinfo) {
|
|||
capinfo->width = geometry->fb_width;
|
||||
capinfo->height = geometry->fb_height;
|
||||
capinfo->bpp = geometry->fb_bpp;
|
||||
capinfo->px_sampling = geometry->px_sampling;
|
||||
}
|
||||
|
||||
void geometry_get_clk_params(clk_info_t *clkinfo) {
|
||||
|
|
|
@ -4,12 +4,20 @@
|
|||
#include "defs.h"
|
||||
#include "cpld.h"
|
||||
|
||||
void geometry_init(int version);
|
||||
void geometry_set_mode(int mode);
|
||||
int geometry_get_value(int num);
|
||||
void geometry_set_value(int num, int value);
|
||||
param_t *geometry_get_params();
|
||||
void geometry_get_fb_params(capture_info_t *capinfo);
|
||||
void geometry_get_clk_params(clk_info_t *clkinfo);
|
||||
enum {
|
||||
PS_NORMAL, // Each sampled pixel is mapped to one pixel in the frame buffer
|
||||
PS_SUBSAMPLE, // Even pixels are replicated, odd pixels are ignored
|
||||
PS_DOUBLE, // Each sampled pixel is mapped to two pixels in the frame buffer
|
||||
NUM_PS
|
||||
};
|
||||
|
||||
void geometry_init(int version);
|
||||
void geometry_set_mode(int mode);
|
||||
int geometry_get_value(int num);
|
||||
const char *geometry_get_value_string(int num);
|
||||
void geometry_set_value(int num, int value);
|
||||
param_t *geometry_get_params();
|
||||
void geometry_get_fb_params(capture_info_t *capinfo);
|
||||
void geometry_get_clk_params(clk_info_t *clkinfo);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -544,6 +544,11 @@ static const char *get_param_string(param_menu_item_t *param_item) {
|
|||
return nbuffer_names[value];
|
||||
#endif
|
||||
}
|
||||
} else if (type == I_GEOMETRY) {
|
||||
const char *value_str = geometry_get_value_string(param->key);
|
||||
if (value_str) {
|
||||
return value_str;
|
||||
}
|
||||
}
|
||||
if (is_boolean_param(param_item)) {
|
||||
return value ? "On" : "Off";
|
||||
|
|
|
@ -23,6 +23,10 @@ extern int capture_line_atom_8bpp();
|
|||
|
||||
extern int capture_line_default_4bpp();
|
||||
|
||||
extern int capture_line_default_4bpp_subsample();
|
||||
|
||||
extern int capture_line_default_4bpp_double();
|
||||
|
||||
extern int capture_line_default_8bpp();
|
||||
|
||||
extern int capture_line_mode7_4bpp();
|
||||
|
|
|
@ -1207,6 +1207,7 @@ void rgb_to_hdmi_main() {
|
|||
|
||||
int result;
|
||||
int last_mode7;
|
||||
int mode_changed;
|
||||
int fb_size_changed;
|
||||
int active_size_decreased;
|
||||
int clk_changed;
|
||||
|
@ -1313,6 +1314,7 @@ void rgb_to_hdmi_main() {
|
|||
|
||||
last_mode7 = mode7;
|
||||
mode7 = result & BIT_MODE7 & (!m7disable);
|
||||
mode_changed = (mode7 != last_mode7) || (capinfo->px_sampling != last_capinfo.px_sampling);
|
||||
|
||||
if (active_size_decreased) {
|
||||
clear = BIT_CLEAR;
|
||||
|
@ -1327,7 +1329,7 @@ void rgb_to_hdmi_main() {
|
|||
recalculate_hdmi_clock_line_locked_update();
|
||||
}
|
||||
|
||||
} while (mode7 == last_mode7 && !fb_size_changed);
|
||||
} while (!mode_changed && !fb_size_changed);
|
||||
|
||||
osd_clear();
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
# - Clock 75000000 100000000 96000000 96000000 | an Electron
|
||||
# - Line Length 1000 9999 6144 6144 |
|
||||
# - Clock tolerance 0 100000 5000 5000 |
|
||||
# - Pixel sampling 0 2 0 0 |
|
||||
#
|
||||
# Any number of these parameters can be specified but typically you would specify:
|
||||
#
|
||||
|
@ -84,6 +85,7 @@
|
|||
# - Clock: the nominal sampling clock fed to the CPLD (in Hz)
|
||||
# - Line Length: the length of a horizontal line (in sampling clocks)
|
||||
# - Clock tolerance: the maximum correctable error in the sampling clock (in ppm)
|
||||
# - Pixel sampling: 0=normal, 1=subsample, 2=pixel double
|
||||
#
|
||||
# info: the default info screen
|
||||
# - 0 is the calibration summary
|
||||
|
@ -188,10 +190,10 @@ sampling06=3 sampling7=0,2,2,2,2,2,2,0,8,5 info=1 palette=0 deinterlace=6 scanli
|
|||
#sampling=0,5,5,5,5,5,5,0 geometry=3,37,66,200,528,400,4,85909091,5472 nbuffers=2 m7disable=1
|
||||
#
|
||||
# Here's an example that might work with an Atom (CPLDv1) (wider border)
|
||||
#sampling=0,5,5,5,5,5,5,0 geometry=0,31,69,212,552,424,4,85909091,5472 nbuffers=2 m7disable=1
|
||||
#sampling=0,5,5,5,5,5,5,0 geometry=0,26,69,212,552,424,4,85909091,5472 nbuffers=2 m7disable=1
|
||||
#
|
||||
# Here's an example that might work with an Atom (CPLDv1) (wider border, 8x sampling clock)
|
||||
#sampling=0,4,4,4,4,4,4,0,8 geometry=8,26,69,212,552,424,4,114545440,7296 nbuffers=2 m7disable=1
|
||||
# Here's an example that might work with an Atom (CPLDv1) (wider border, sub-sample pixels)
|
||||
#sampling=0,5,5,5,5,5,5,0 geometry=0,26,69,212,552,424,4,85909091,5472,5000,1 nbuffers=2 m7disable=1
|
||||
#
|
||||
# Here's an example that might work with an Atom (CPLDv2) (even wider border)
|
||||
#sampling=0,5,5,5,5,5,5,0 geometry=24,16,76,240,608,480,4,85909091,5472 nbuffers=2 m7disable=1
|
||||
|
|
Ładowanie…
Reference in New Issue