Video Signals And Timing
Work in progress. Is currently a dump of Brendan's worked out formulae
Brendan's Posts
>Any problems if I wikify this? None at all - IMHO this information is required just to use VBE reliably; along with EDID (but you can find version 1.1 of the EDID data structures on Wikipedia) and details for the VBE DDC function (which VESA will let you have for free).
However, I should point out that this information is incomplete - the value of certain constants are missing from my original post. The default values for these constants are: CELL_GRAN_RND = 8, MARGIN_PRECENT = 1.8, MIN_PORCH_RND = 1, MIN_V_SYNC_AND_BACK_PORCH = 550, C_PRIME = 40 and M_PRIME = 600. I'd also mention that for my version of the formulas REFRESH_RATE_REQUIRED, V_FIELD_RATE_REQUIRED, H_FREQ_REQUIRED, PIXEL_FREQ_REQUIRED, V_FIELD_RATE, H_FREQ, PIXEL_FREQ are all in Hz (and not a mixture of Hz, KHz and MHz), which helps to simplify the formulas.
There's also some strange things that can happen with these formulas. For example, if any of the calculations give a negative result then it indicates invalid input (e.g. if the PIXEL_FREQ_REQUIRED input parameter is too low, then you can end up with horizontal blanking that takes "negative N us"). In practice, some of these calculations probably have an allowed range (e.g. things like "horizontal blanking must be >= 20% of the horizontal total") but I've been unable to find anything indicating what the allowed ranges for anything is. :(
This is for my own reference, and in case anyone is wondering what they look like... The GTF formulas.
There's actually 3 separate calculations here - finding all timing parameters from X & Y resolution and desired refresh rate, finding all timing parameters from X & Y resolution and desired horizontal frequency, and finding all timing parameters from X & Y resolution and desired pixel clock frequency.
GTF Formulas For Using Desired Refresh Rate
H_PIXELS_RND = ( ROUND ( H_PIXELS / CELL_GRAN_RND ) ) * CELL_GRAN_RND IF ( INTERLACE_REQUIRED == "y") { V_LINES_RND = ROUND ( V_LINES / 2 ) V_FIELD_RATE_REQUIRED = REFRESH_RATE_REQUIRED * 2 INTERLACE = 0.5 } else { V_LINES_RND = ROUND ( V_LINES) ) V_FIELD_RATE_REQUIRED = REFRESH_RATE_REQUIRED INTERLACE = 0 } IF ( MARGINS_REQUIRED == "y" ) { TOP_MARGIN_LINES = ROUND ( MARGIN_PRECENT / 100 * V_LINES_RND ) BOTTOM_MARGIN_LINES = ROUND ( MARGIN_PRECENT / 100 * V_LINES_RND ) LEFT_MARGIN_PIXELS = ( ROUND ( ( H_PIXELS_RND * MARGIN_PRECENT / 100 / CELL_GRAN_RND ) , 0 ) ) * CELL_GRAN_RND RIGHT_MARGIN_PIXELS = ( ROUND ( ( H_PIXELS_RND * MARGIN_PRECENT / 100 / CELL_GRAN_RND ) , 0 ) ) * CELL_GRAN_RND } else { TOP_MARGIN_LINES = 0 BOTTOM_MARGIN_LINES = 0 LEFT_MARGIN_PIXELS = 0 RIGHT_MARGIN_PIXELS = 0 } H_PERIOD_ESTIMATE = ( 1 / V_FIELD_RATE_REQUIRED - MIN_V_SYNC_AND_BACK_PORCH / 1000000 ) / ( V_LINES_RND + 2 * TOP_MARGIN_LINES + MIN_PORCH_RND + INTERLACE ) * 1000000 V_SYNC_AND_BACK_PORCH = ROUND ( MIN_V_SYNC_AND_BACK_PORCH / H_PERIOD_ESTIMATE ) V_BACK_PORCH = V_SYNC_AND_BACK_PORCH - V_SYNC_RND TOTAL_V_LINES = V_LINES_RND + TOP_MARGIN_LINES + BOTTOM_MARGIN_LINES + V_SYNC_AND_BACK_PORCH + INTERLACE + MIN_PORCH_RND V_FIELD_RATE_ESTIMATE = 1000000 / H_PERIOD_ESTIMATE / TOTAL_V_LINES H_PERIOD = H_PERIOD_ESTIMATE * V_FIELD_RATE_ESTIMATE / V_FIELD_RATE_REQUIRED V_FIELD_RATE = 1000000 / H_PERIOD / TOTAL_V_LINES IF ( INTERLACE_REQUIRED == "y") { V_FRAME_RATE = V_FIELD_RATE / 2 } else { V_FRAME_RATE = V_FIELD_RATE } TOTAL_ACTIVE_PIXELS = H_PIXELS_RND + LEFT_MARGIN_PIXELS + RIGHT_MARGIN_PIXELS IDEAL_DUTY_CYCLE = C_PRIME - M_PRIME * H_PERIOD / 1000 H_BLANK_PIXELS = ( ROUND ( ( TOTAL_ACTIVE_PIXELS * IDEAL_DUTY_CYCLE / ( 100 - IDEAL_DUTY_CYCLE ) / ( 2 * CELL_GRAN_RND ) ) ) ) * 2 * CELL_GRAN_RND TOTAL_PIXELS = TOTAL_ACTIVE_PIXELS + H_BLANK_PIXELS PIXEL_FREQ = TOTAL_PIXELS / H_PERIOD * 1000000 H_FREQ = 1 / H_PERIOD
GTF Formulas For Using Horizontal Frequency
H_PIXELS_RND = ( ROUND ( H_PIXELS / CELL_GRAN_RND ) ) * CELL_GRAN_RND IF ( INTERLACE_REQUIRED == "y") { V_LINES_RND = ROUND ( V_LINES / 2 ) INTERLACE = 0.5 } else { V_LINES_RND = ROUND ( V_LINES) ) INTERLACE = 0 } IF ( MARGINS_REQUIRED == "y" ) { TOP_MARGIN_LINES = ROUND ( MARGIN_PRECENT / 100 * V_LINES_RND ) BOTTOM_MARGIN_LINES = ROUND ( MARGIN_PRECENT / 100 * V_LINES_RND ) LEFT_MARGIN_PIXELS = ( ROUND ( ( H_PIXELS_RND * MARGIN_PRECENT / 100 / CELL_GRAN_RND ) , 0 ) ) * CELL_GRAN_RND RIGHT_MARGIN_PIXELS = ( ROUND ( ( H_PIXELS_RND * MARGIN_PRECENT / 100 / CELL_GRAN_RND ) , 0 ) ) * CELL_GRAN_RND } else { TOP_MARGIN_LINES = 0 BOTTOM_MARGIN_LINES = 0 LEFT_MARGIN_PIXELS = 0 RIGHT_MARGIN_PIXELS = 0 } H_FREQ = H_FREQ_REQUIRED V_SYNC_AND_BACK_PORCH = ROUND ( MIN_V_SYNC_AND_BACK_PORCH * H_FREQ / 1000000 ) V_BACK_PORCH = V_SYNC_AND_BACK_PORCH - V_SYNC_RND TOTAL_V_LINES = V_LINES_RND + TOP_MARGIN_LINES + BOTTOM_MARGIN_LINES + INTERLACE + V_SYNC_AND_BACK_PORCH + MIN_PORCH_RND V_FIELD_RATE = H_FREQ / TOTAL_V_LINES IF ( INTERLACE_REQUIRED == "y") { V_FRAME_RATE = V_FIELD_RATE / 2 } else { V_FRAME_RATE = V_FIELD_RATE } TOTAL_ACTIVE_PIXELS = H_PIXELS_RND + RIGHT_MARGIN_PIXELS + LEFT_MARGIN_PIXELS IDEAL_DUTY_CYCLE = C_PRIME - ( M_PRIME / H_FREQ ) H_BLANK_PIXELS = ( ROUND ( TOTAL_ACTIVE_PIXELS * IDEAL_DUTY_CYCLE / ( 100 - IDEAL_DUTY_CYCLE ) / ( 2 * CELL_GRAN_RND ) ) ) * 2 * CELL_GRAN_RND TOTAL_PIXELS = TOTAL_ACTIVE_PIXELS + H_BLANK_PIXELS H_PERIOD = 1 / H_FREQ PIXEL_FREQ = TOTAL_PIXELS * H_FREQ
GTF Formulas For Using Pixel Clock Frequency
H_PIXELS_RND = ( ROUND ( H_PIXELS / CELL_GRAN_RND ) ) * CELL_GRAN_RND IF ( INTERLACE_REQUIRED == "y") { V_LINES_RND = ROUND ( V_LINES / 2 ) INTERLACE = 0.5 } else { V_LINES_RND = ROUND ( V_LINES) ) INTERLACE = 0 } PIXEL_FREQ = PIXEL_FREQ_REQUIRED IF ( MARGINS_REQUIRED == "y" ) { TOP_MARGIN_LINES = ROUND ( MARGIN_PRECENT / 100 * V_LINES_RND ) BOTTOM_MARGIN_LINES = ROUND ( MARGIN_PRECENT / 100 * V_LINES_RND ) LEFT_MARGIN_PIXELS = ( ROUND ( ( H_PIXELS_RND * MARGIN_PRECENT / 100 / CELL_GRAN_RND ) , 0 ) ) * CELL_GRAN_RND RIGHT_MARGIN_PIXELS = ( ROUND ( ( H_PIXELS_RND * MARGIN_PRECENT / 100 / CELL_GRAN_RND ) , 0 ) ) * CELL_GRAN_RND } else { TOP_MARGIN_LINES = 0 BOTTOM_MARGIN_LINES = 0 LEFT_MARGIN_PIXELS = 0 RIGHT_MARGIN_PIXELS = 0 } TOTAL_ACTIVE_PIXELS = H_PIXELS_RND + RIGHT_MARGIN_PIXELS + LEFT_MARGIN_PIXELS IDEAL_H_PERIOD = ( ( C_PRIME - 100 ) + ( SQRT ( ( ( 100 - C_PRIME ) ^ 2 ) + ( 0.4 * M_PRIME * ( TOTAL_ACTIVE_PIXELS + RIGHT_MARGIN_PIXELS + LEFT_MARGIN_PIXELS ) / PIXEL_FREQ / 1000000 ) ) ) ) / 2 / M_PRIME * 1000 IDEAL_DUTY_CYCLE = C_PRIME - ( M_PRIME * IDEAL_H_PERIOD / 1000 ) H_BLANK_PIXELS = ( ROUND ( TOTAL_ACTIVE_PIXELS * IDEAL_DUTY_CYCLE / ( 100 - IDEAL_DUTY_CYCLE ) / ( 2 * CELL_GRAN_RND ) ) ) * 2 * CELL_GRAN_RND TOTAL_PIXELS = TOTAL_ACTIVE_PIXELS + H_BLANK_PIXELS H_FREQ = PIXEL_FREQ / TOTAL_PIXELS H_PERIOD = 1 / H_FREQ V_SYNC_AND_BACK_PORCH = ROUND ( MIN_V_SYNC_AND_BACK_PORCH * H_FREQ / 1000000 ) V_BACK_PORCH = V_SYNC_AND_BACK_PORCH - V_SYNC_RND TOTAL_V_LINES = V_LINES_RND + TOP_MARGIN_LINES + BOTTOM_MARGIN_LINES + INTERLACE + V_SYNC_AND_BACK_PORCH + MIN_PORCH_RND V_FIELD_RATE = H_FREQ / TOTAL_V_LINES IF ( INTERLACE_REQUIRED == "y") { V_FRAME_RATE = V_FIELD_RATE / 2 } else { V_FRAME_RATE = V_FIELD_RATE }
Note: The "round()" function here rounds to the nearest integer (it doesn't round down or round up).
Cheers,
Brendan