5 changed files with 347 additions and 238 deletions
@ -0,0 +1,208 @@ |
|||||
|
#ifndef INCLUDED_MAX_EDID |
||||
|
#define INCLUDED_MAX_EDID |
||||
|
|
||||
|
#include <stdio.h> |
||||
|
#include <stdint.h> |
||||
|
#include <string.h> |
||||
|
#include <stdlib.h> |
||||
|
#include "frozen/frozen.h" |
||||
|
|
||||
|
#define EDID_LEN 128 |
||||
|
#define EDID_DISPLAY_DESCRIPTOR_DATA_LEN 13 |
||||
|
|
||||
|
// EDID data structure
|
||||
|
|
||||
|
typedef struct __attribute__ (( packed )) { |
||||
|
uint8_t x_resolution; |
||||
|
uint8_t vertical_frequency:6; |
||||
|
uint8_t aspect_ratio :2; |
||||
|
} standard_timing_information_t; |
||||
|
|
||||
|
typedef struct __attribute__ (( packed )) { |
||||
|
uint16_t pixel_clock; // 0-1
|
||||
|
uint8_t horizontal_active_pixels_lsbs; // 2
|
||||
|
uint8_t horizontal_blanking_pixels_lsbs; // 3
|
||||
|
uint8_t horizontal_blanking_pixels_msbs :4; // 4
|
||||
|
uint8_t horizontal_active_pixels_msbs :4; |
||||
|
uint8_t vertical_active_lines_lsbs; // 5
|
||||
|
uint8_t vertical_blanking_lines_lsbs; // 6
|
||||
|
uint8_t vertical_blanking_lines_msbs :4; // 7
|
||||
|
uint8_t vertical_active_lines_msbs :4; |
||||
|
uint8_t horizontal_front_porch_pixels_lsbs; // 8
|
||||
|
uint8_t horizontal_sync_pulse_pixels_lsbs; // 9
|
||||
|
uint8_t vertical_sync_pulse_lines_lsbs :4; // 10
|
||||
|
uint8_t vertical_front_porch_lines_lsbs :4; |
||||
|
uint8_t vertical_sync_pulse_lines_msbs :2; // 11
|
||||
|
uint8_t vertical_front_porch_lines_msbs :2; |
||||
|
uint8_t horizontal_sync_pulse_pixels_msbs :2; |
||||
|
uint8_t horizontal_front_porch_pixels_msbs :2; |
||||
|
uint8_t horizontal_image_size_lsbs; // 12
|
||||
|
uint8_t vertical_image_size_lsbs; |
||||
|
uint8_t vertical_image_size_msbs :4; |
||||
|
uint8_t horizontal_image_size_msbs :4; |
||||
|
uint8_t horizontal_border_pixels; |
||||
|
uint8_t vertical_border_lines; |
||||
|
// Feature bitmap
|
||||
|
union __attribute__ (( packed )) { |
||||
|
struct __attribute__ (( packed )) { |
||||
|
uint8_t stereo_mode_lsb :1; |
||||
|
uint8_t sync_on_red_blue :1; |
||||
|
uint8_t vertical_sync_serration :1; |
||||
|
uint8_t sync_type :1; |
||||
|
uint8_t analog_sync :1; |
||||
|
uint8_t stereo_mode_msbs :2; |
||||
|
uint8_t interlaced :1; |
||||
|
} analog; |
||||
|
struct __attribute__ (( packed )) { |
||||
|
uint8_t stereo_mode_lsb :1; |
||||
|
uint8_t reserved :1; |
||||
|
uint8_t vertical_sync_polarity :1; |
||||
|
uint8_t digital_composite_sync :2; |
||||
|
uint8_t stereo_mode_msbs :2; |
||||
|
uint8_t interlaced :1; |
||||
|
} digital_composite; |
||||
|
struct __attribute__ (( packed )) { |
||||
|
uint8_t stereo_mode_lsb :1; |
||||
|
uint8_t horizontal_sync_polarity :1; |
||||
|
uint8_t vertical_sync_serration :1; |
||||
|
uint8_t digital_seperate_sync :2; |
||||
|
uint8_t stereo_mode_msbs :2; |
||||
|
uint8_t interlaced :1; |
||||
|
} digital_seperate; |
||||
|
} features; |
||||
|
} detailed_timing_descriptor_t; |
||||
|
|
||||
|
typedef struct __attribute__ (( packed )) { |
||||
|
uint16_t display_descriptor; |
||||
|
uint8_t reserved; |
||||
|
uint8_t display_range_limits_descriptor; |
||||
|
struct __attribute__ (( packed )) { |
||||
|
uint8_t vertical :2; |
||||
|
uint8_t horizontal :2; |
||||
|
uint8_t reserved :4; |
||||
|
} rate_offsets; |
||||
|
struct __attribute__ (( packed )) { |
||||
|
uint8_t minimum; |
||||
|
uint8_t maximum; |
||||
|
} vertical_field_rate; |
||||
|
struct __attribute__ (( packed )) { |
||||
|
uint8_t minimum; |
||||
|
uint8_t maximum; |
||||
|
} horizontal_line_rate; |
||||
|
uint8_t maximum_pixel_clock_mhz; // In 10 MHz units
|
||||
|
uint8_t extended_timing_information_type; |
||||
|
uint8_t video_timing_params[7]; |
||||
|
} range_limits_descriptor_t; |
||||
|
|
||||
|
typedef struct __attribute__ (( packed )) { |
||||
|
uint16_t display_descriptor; |
||||
|
uint8_t reserved0; |
||||
|
uint8_t descriptor_type; |
||||
|
uint8_t reserved1; |
||||
|
uint8_t descriptor_data[EDID_DISPLAY_DESCRIPTOR_DATA_LEN]; |
||||
|
} display_descriptor_t; |
||||
|
|
||||
|
typedef struct __attribute__ (( packed )) { |
||||
|
/*! Header information, 20 bytes */ |
||||
|
struct __attribute__ (( packed )) { |
||||
|
uint64_t preamble; |
||||
|
uint8_t manufacturer_id[2]; |
||||
|
uint16_t product_code; |
||||
|
uint32_t serial_number; |
||||
|
uint8_t week_of_manufacture; |
||||
|
uint8_t year_of_manufacture; |
||||
|
uint8_t edid_version; |
||||
|
uint8_t edid_revision; |
||||
|
} header; |
||||
|
/*! Basic display parameters, 5 bytes */ |
||||
|
struct __attribute__ (( packed )) { |
||||
|
union __attribute__ (( packed )) { |
||||
|
struct __attribute__ (( packed )) { |
||||
|
uint8_t video_interface : 4; |
||||
|
uint8_t bit_depth : 3; |
||||
|
uint8_t input_type : 1; // 1 for digital
|
||||
|
} digital; |
||||
|
struct __attribute__ (( packed )) { |
||||
|
uint8_t vsync_serrated: 1; |
||||
|
uint8_t sync_on_green : 1; |
||||
|
uint8_t composite_sync: 1; |
||||
|
uint8_t seperate_sync : 1; |
||||
|
uint8_t blank_to_black: 1; |
||||
|
uint8_t levels : 2; |
||||
|
uint8_t input_type : 1; // 0 for analog
|
||||
|
} analog; |
||||
|
} video_input_parameters; // 1 byte
|
||||
|
uint8_t horizontal_screen_size; |
||||
|
uint8_t vertical_screen_size; |
||||
|
uint8_t gamma; |
||||
|
struct __attribute__ (( packed )) { |
||||
|
uint8_t continuous_timings : 1; |
||||
|
uint8_t preferred_timing_mode : 1; |
||||
|
uint8_t standard_srgb : 1; |
||||
|
uint8_t display_type : 2; |
||||
|
uint8_t dpms_active_off_supported : 1; |
||||
|
uint8_t dpms_suspend_supported : 1; |
||||
|
uint8_t dpms_standby_supported : 1; |
||||
|
} features; |
||||
|
} basic_display_parameters; |
||||
|
/*! Chromaticity coordinates. 10-bit CIE 1931 xy coordinates for red, green,
|
||||
|
* blue, and white point, 10 bytes */ |
||||
|
struct __attribute__ (( packed )) { |
||||
|
struct __attribute__ (( packed )) { |
||||
|
uint8_t green_y : 2; |
||||
|
uint8_t green_x : 2; |
||||
|
uint8_t red_y : 2; |
||||
|
uint8_t red_x : 2; |
||||
|
} red_green_lsbs; |
||||
|
struct __attribute__ (( packed )) { |
||||
|
uint8_t white_y : 2; |
||||
|
uint8_t white_x : 2; |
||||
|
uint8_t blue_y : 2; |
||||
|
uint8_t blue_x : 2; |
||||
|
} blue_white_lsbs; |
||||
|
uint8_t red_x_msbs; |
||||
|
uint8_t red_y_msbs; |
||||
|
uint8_t green_x_msbs; |
||||
|
uint8_t green_y_msbs; |
||||
|
uint8_t blue_x_msbs; |
||||
|
uint8_t blue_y_msbs; |
||||
|
uint8_t white_x_msbs; |
||||
|
uint8_t white_y_msbs; |
||||
|
} chromaticity_coordinates; |
||||
|
/*! Established timing bitmap. Supported bitmap for (formerly) very common
|
||||
|
timing modes. 3 bytes */ |
||||
|
struct __attribute__ (( packed )) { |
||||
|
uint8_t m800_600_60 : 1; |
||||
|
uint8_t m800_600_56 : 1; |
||||
|
uint8_t m640_480_75 : 1; |
||||
|
uint8_t m640_480_72 : 1; |
||||
|
uint8_t m640_480_67 : 1; |
||||
|
uint8_t m640_480_60 : 1; |
||||
|
uint8_t m720_400_88 : 1; |
||||
|
uint8_t m720_400_70 : 1; |
||||
|
uint8_t m1280_1024_75: 1; |
||||
|
uint8_t m1024_768_75 : 1; |
||||
|
uint8_t m1024_768_70 : 1; |
||||
|
uint8_t m1024_768_60 : 1; |
||||
|
uint8_t m1024_768_87 : 1; |
||||
|
uint8_t m832_624_75 : 1; |
||||
|
uint8_t m800_600_75 : 1; |
||||
|
uint8_t m800_600_72 : 1; |
||||
|
uint8_t reserved : 7; |
||||
|
uint8_t m1152_870_75 : 1; |
||||
|
} common_timing_modes; |
||||
|
/*! Standard timing information. Up to 8 2-byte fields describing standard
|
||||
|
display modes. Unused fields are filled with 01 01 hex. 16 bytes */ |
||||
|
standard_timing_information_t timings[8]; |
||||
|
detailed_timing_descriptor_t detailed_timing_descriptor; |
||||
|
range_limits_descriptor_t range_limits_descriptor; |
||||
|
display_descriptor_t display_name_descriptor; |
||||
|
display_descriptor_t display_serial_number_descriptor; |
||||
|
uint8_t number_extensions; |
||||
|
uint8_t checksum; |
||||
|
} edid_t; |
||||
|
|
||||
|
// Interface
|
||||
|
int generate_edid(edid_t* const edid, const char* const filename); |
||||
|
|
||||
|
#endif |
Binary file not shown.
@ -0,0 +1,78 @@ |
|||||
|
#include <stdio.h> |
||||
|
#include "edid.h" |
||||
|
|
||||
|
#define FAILURE(buf_str, line) \ |
||||
|
fprintf(stderr, "X Failed on line %d: [%s]\n", line, buf_str); \ |
||||
|
return EXIT_FAILURE; |
||||
|
|
||||
|
#define SUCCESS(buf_str, line) \ |
||||
|
fprintf(stdout, "✓ Success on line %d: [%s]\n", line, buf_str); |
||||
|
|
||||
|
#define CHECK_TRUE(expr) \ |
||||
|
if (!(expr)) { \ |
||||
|
FAILURE(#expr, __LINE__); \ |
||||
|
} else { \ |
||||
|
SUCCESS(#expr, __LINE__); \ |
||||
|
} |
||||
|
|
||||
|
static const uint8_t i2c_data_screen_0[EDID_LEN] = { |
||||
|
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1e, 0x6d, 0xd5, 0x59, 0x04, 0x45, 0x09, 0x00, |
||||
|
0x03, 0x17, 0x01, 0x03, 0x68, 0x35, 0x1e, 0x78, 0xea, 0x33, 0x31, 0xa4, 0x57, 0x51, 0xa0, 0x26, |
||||
|
0x10, 0x50, 0x54, 0xa7, 0x6b, 0x80, 0xb3, 0x00, 0x81, 0x80, 0x95, 0x00, 0x71, 0x4f, 0xa9, 0xc0, |
||||
|
0x81, 0x00, 0x81, 0xc0, 0x90, 0x40, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c, |
||||
|
0x45, 0x00, 0x09, 0x25, 0x21, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x38, 0x4b, 0x1e, |
||||
|
0x53, 0x0f, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x32, |
||||
|
0x34, 0x45, 0x4e, 0x33, 0x33, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xff, |
||||
|
0x00, 0x33, 0x30, 0x33, 0x4e, 0x44, 0x51, 0x41, 0x48, 0x56, 0x34, 0x39, 0x32, 0x0a, 0x00, 0xf1 |
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
* @brief Helper function to compare EDID data structure with golden design data structure extracted from real |
||||
|
* VGA screen. |
||||
|
*/ |
||||
|
static int compare_edid(const uint8_t* const edid, const uint8_t* const edid_golden) |
||||
|
{ |
||||
|
for (int sanny=0; sanny<EDID_LEN; sanny++) { |
||||
|
CHECK_TRUE(edid[sanny] == edid_golden[sanny]); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* @brief Helper function to show buffer |
||||
|
*/ |
||||
|
static void disp_buf(uint8_t *buf, int len) |
||||
|
{ |
||||
|
int i; |
||||
|
for (i = 0; i < len; i++) { |
||||
|
printf("%02x ", buf[i]); |
||||
|
if ((i + 1) % 16 == 0) { |
||||
|
printf("\n"); |
||||
|
} |
||||
|
} |
||||
|
printf("\n"); |
||||
|
} |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
edid_t edith; |
||||
|
const char* const json_file = "edid0.json"; |
||||
|
|
||||
|
/* 1) If check fails the structure has been build up in the wrong way on the target platform.
|
||||
|
*/ |
||||
|
CHECK_TRUE(sizeof(edid_t) == EDID_LEN); |
||||
|
/* 2) If check fails the EDID data structure could not be generated.
|
||||
|
*/ |
||||
|
CHECK_TRUE(generate_edid(&edith, json_file) == 0); |
||||
|
/* 3) 128 checks in one function to probe every single byte.
|
||||
|
*/ |
||||
|
int ret = 0; |
||||
|
if (ret = compare_edid((uint8_t*)&edith, i2c_data_screen_0)) { |
||||
|
printf("ret> %d\n", ret); |
||||
|
return ret; |
||||
|
} |
||||
|
printf("\n"); |
||||
|
printf("Generated EDID data from %s:\n", json_file); |
||||
|
disp_buf((uint8_t*)&edith, EDID_LEN); |
||||
|
return 0; |
||||
|
} |
Loading…
Reference in new issue