FabGL
ESP32 Display Controller and Graphics Library
VGA/ModelineStudio/ModelineStudio.ino

Test VGA output at predefined resolutions or custom resolution by specifying linux-like modelines

/*
Created by Fabrizio Di Vittorio (fdivitto2013@gmail.com) - <http://www.fabgl.com>
Copyright (c) 2019-2022 Fabrizio Di Vittorio.
All rights reserved.
* Please contact fdivitto2013@gmail.com if you need a commercial license.
* This library and related software is available under GPL v3.
FabGL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
FabGL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with FabGL. If not, see <http://www.gnu.org/licenses/>.
*/
#include "fabgl.h"
const char * PresetResolutions[] = {
VGA_320x200_60HzD,
};
int currentResolution = 24; // VESA_640x480_75Hz
int moveX = 0;
int moveY = 0;
int shrinkX = 0;
int shrinkY = 0;
fabgl::VGA2Controller VGAController;
void printHelp()
{
Serial.printf("Modeline studio\n");
Serial.printf("Chip Revision: %d Chip Frequency: %d MHz\n\n", ESP.getChipRevision(), ESP.getCpuFreqMHz());
Serial.printf("%s\n", VGAController.getResolutionTimings()->label);
Serial.printf("\nScreen move:\n");
Serial.printf(" w = Move Up z = Move Down a = Move Left s = Move Right\n");
Serial.printf("Screen shrink:\n");
Serial.printf(" n = Dec Horiz N = Inc Horiz m = Dec Vert M = Inc Vert\n");
Serial.printf("Resolutions:\n");
Serial.printf(" + = Next resolution - = Prev resolution x = Restore modeline\n");
Serial.printf("Modeline change:\n");
Serial.printf(" Just insert a modline. Example: \"640x350@70Hz\" 25.175 640 656 752 800 350 366 462 510 -HSync -VSync\n");
Serial.printf(" e = Decrease horiz. Front Porch E = Increase horiz. Front Porch\n");
Serial.printf(" r = Decrease horiz. Sync Pulse R = Increase horiz. Sync Pulse\n");
Serial.printf(" t = Decrease horiz. Bach Porch T = Increase horiz. Back Porch\n");
Serial.printf(" y = Decrease vert. Front Porch Y = Increase vert. Front Porch\n");
Serial.printf(" u = Decrease vert. Sync Pulse U = Increase vert. Sync Pulse\n");
Serial.printf(" i = Decrease vert. Bach Porch I = Increase vert. Back Porch\n");
//*/
Serial.printf(" o = Decrease frequency by 5KHz O = Increase frequency by 5KHz\n");
Serial.printf(" . = Change horiz. signals order\n");
Serial.printf("Various:\n");
Serial.printf(" h = Print This help\n\n");
}
void printInfo()
{
auto t = VGAController.getResolutionTimings();
Serial.printf("Modeline \"%s\" %2.8g %d %d %d %d %d %d %d %d %cHSync %cVSync %s %s\n",
t->label,
t->frequency / 1000000.0,
t->HVisibleArea,
t->HVisibleArea + t->HFrontPorch,
t->HVisibleArea + t->HFrontPorch + t->HSyncPulse,
t->HVisibleArea + t->HFrontPorch + t->HSyncPulse + t->HBackPorch,
t->VVisibleArea,
t->VVisibleArea + t->VFrontPorch,
t->VVisibleArea + t->VFrontPorch + t->VSyncPulse,
t->VVisibleArea + t->VFrontPorch + t->VSyncPulse + t->VBackPorch,
t->HSyncLogic, t->VSyncLogic,
t->scanCount == 2 ? "DoubleScan" : "",
t->HStartingBlock == VGAScanStart::FrontPorch ? "FrontPorchBegins" :
(t->HStartingBlock == VGAScanStart::Sync ? "SyncBegins" :
(t->HStartingBlock == VGAScanStart::BackPorch ? "BackPorchBegins" : "VisibleBegins")));
//Serial.printf("VFront = %d, VSync = %d, VBack = %d\n", t->VFrontPorch, t->VSyncPulse, t->VBackPorch);
if (moveX || moveY)
Serial.printf("moveScreen(%d, %d)\n", moveX, moveY);
if (shrinkX || shrinkY)
Serial.printf("shrinkScreen(%d, %d)\n", shrinkX, shrinkY);
Serial.printf("Screen size : %d x %d\n", VGAController.getScreenWidth(), VGAController.getScreenHeight());
Serial.printf("Viewport size : %d x %d\n", VGAController.getViewPortWidth(), VGAController.getViewPortHeight());
Serial.printf("Free memory (total, min, largest): %d, %d, %d\n\n", heap_caps_get_free_size(MALLOC_CAP_32BIT),
heap_caps_get_minimum_free_size(MALLOC_CAP_32BIT),
heap_caps_get_largest_free_block(MALLOC_CAP_32BIT));
}
void updateScreen()
{
Canvas cv(&VGAController);
cv.setPenColor(Color::White);
cv.setBrushColor(Color::Black);
cv.clear();
cv.fillRectangle(0, 0, cv.getWidth() - 1, cv.getHeight() - 1);
cv.drawRectangle(0, 0, cv.getWidth() - 1, cv.getHeight() - 1);
cv.selectFont(&fabgl::FONT_8x8);
cv.setGlyphOptions(GlyphOptions().FillBackground(true).DoubleWidth(1));
cv.drawText(40, 20, VGAController.getResolutionTimings()->label);
cv.setGlyphOptions(GlyphOptions());
cv.drawTextFmt(40, 40, "Screen Size : %d x %d", VGAController.getScreenWidth(), VGAController.getScreenHeight());
cv.drawTextFmt(40, 60, "Viewport Size : %d x %d", cv.getWidth(), cv.getHeight());
cv.drawText(40, 80, "Commands (More on UART):");
cv.drawText(40, 100, " w = Move Up z = Move Down");
cv.drawText(40, 120, " a = Move Left s = Move Right");
cv.drawText(40, 140, " + = Next Resolution");
cv.drawRectangle(35, 15, 310, 155);
}
void setup()
{
Serial.begin(115200);
// avoid garbage into the UART
delay(500);
VGAController.begin();
VGAController.setResolution(PresetResolutions[currentResolution]);
updateScreen();
printHelp();
printInfo();
}
void loop()
{
if (Serial.available() > 0) {
char c = Serial.read();
switch (c) {
case 'h':
printHelp();
break;
case 'w':
--moveY;
VGAController.moveScreen(0, -1);
printInfo();
break;
case 'z':
++moveY;
VGAController.moveScreen(0, +1);
printInfo();
break;
case 'a':
--moveX;
VGAController.moveScreen(-1, 0);
printInfo();
break;
case 's':
++moveX;
VGAController.moveScreen(+1, 0);
printInfo();
break;
case 'x':
moveX = moveY = shrinkX = shrinkY = 0;
VGAController.setResolution(PresetResolutions[currentResolution]);
updateScreen();
printInfo();
break;
case '+':
case '-':
moveX = moveY = shrinkX = shrinkY = 0;
currentResolution = (c == '+' ? currentResolution + 1 : currentResolution - 1);
if (currentResolution == sizeof(PresetResolutions) / sizeof(const char *))
currentResolution = 0;
if (currentResolution < 0)
currentResolution = sizeof(PresetResolutions) / sizeof(const char *) - 1;
VGAController.setResolution(PresetResolutions[currentResolution]);
updateScreen();
printInfo();
break;
case '"':
moveX = moveY = shrinkX = shrinkY = 0;
VGAController.setResolution( (String("\"") + Serial.readStringUntil('\n')).c_str() );
updateScreen();
printInfo();
break;
case 'e':
case 'E':
t = *VGAController.getResolutionTimings();
t.HFrontPorch = (c == 'e' ? t.HFrontPorch - 1 : t.HFrontPorch + 1);
t.HBackPorch = (c == 'e' ? t.HBackPorch + 1 : t.HBackPorch - 1);
VGAController.setResolution(t);
updateScreen();
printInfo();
break;
case 'r':
case 'R':
t = *VGAController.getResolutionTimings();
t.HSyncPulse = (c == 'r' ? t.HSyncPulse - 1 : t.HSyncPulse + 1);
t.HBackPorch = (c == 'r' ? t.HBackPorch + 1 : t.HBackPorch - 1);
VGAController.setResolution(t);
updateScreen();
printInfo();
break;
case 't':
case 'T':
t = *VGAController.getResolutionTimings();
t.HBackPorch = (c == 't' ? t.HBackPorch - 1 : t.HBackPorch + 1);
t.HFrontPorch = (c == 't' ? t.HFrontPorch + 1 : t.HFrontPorch - 1);
VGAController.setResolution(t);
updateScreen();
printInfo();
break;
case 'y':
case 'Y':
t = *VGAController.getResolutionTimings();
t.VFrontPorch = (c == 'y' ? t.VFrontPorch - 1 : t.VFrontPorch + 1);
t.VBackPorch = (c == 'y' ? t.VBackPorch + 1 : t.VBackPorch - 1);
VGAController.setResolution(t);
updateScreen();
printInfo();
break;
case 'u':
case 'U':
t = *VGAController.getResolutionTimings();
t.VSyncPulse = (c == 'u' ? t.VSyncPulse - 1 : t.VSyncPulse + 1);
t.VBackPorch = (c == 'u' ? t.VBackPorch + 1 : t.VBackPorch - 1);
VGAController.setResolution(t);
updateScreen();
printInfo();
break;
case 'i':
case 'I':
t = *VGAController.getResolutionTimings();
t.VBackPorch = (c == 'i' ? t.VBackPorch - 1 : t.VBackPorch + 1);
t.VFrontPorch = (c == 'i' ? t.VFrontPorch + 1 : t.VFrontPorch - 1);
VGAController.setResolution(t);
updateScreen();
printInfo();
break;
//*/
case 'o':
case 'O':
t = *VGAController.getResolutionTimings();
t.frequency = (c == 'o' ? t.frequency - 5000 : t.frequency + 5000);
VGAController.setResolution(t);
updateScreen();
printInfo();
break;
case '.':
t = *VGAController.getResolutionTimings();
switch (t.HStartingBlock) {
break;
break;
break;
break;
}
VGAController.setResolution(t);
updateScreen();
printInfo();
break;
case 'n':
++shrinkX;
VGAController.shrinkScreen(+1, 0);
updateScreen();
printInfo();
break;
case 'N':
--shrinkX;
VGAController.shrinkScreen(-1, 0);
updateScreen();
printInfo();
break;
case 'm':
++shrinkY;
VGAController.shrinkScreen(0, +1);
updateScreen();
printInfo();
break;
case 'M':
--shrinkY;
VGAController.shrinkScreen(0, -1);
updateScreen();
printInfo();
break;
}
}
}
int getScreenHeight()
Determines the screen height in pixels.
int getViewPortHeight()
Determines vertical size of the viewport.
int getViewPortWidth()
Determines horizontal size of the viewport.
int getScreenWidth()
Determines the screen width in pixels.
Represents the VGA 2 colors bitmapped controller.
GlyphOptions & DoubleWidth(uint8_t value)
Helper method to set or reset doubleWidth.
GlyphOptions & FillBackground(bool value)
Helper method to set or reset fillBackground.
This file is the all in one include file. Application can just include this file to use FabGL library...
#define VGA_320x200_75Hz
Definition: fabglconf.h:183
#define VGA_640x480_60HzAlt1
Definition: fabglconf.h:249
#define SVGA_800x600_56Hz
Definition: fabglconf.h:297
#define SVGA_800x300_60Hz
Definition: fabglconf.h:294
#define SVGA_800x600_60Hz
Definition: fabglconf.h:300
#define VGA_640x480_60Hz
Definition: fabglconf.h:246
#define VESA_640x350_85Hz
Definition: fabglconf.h:231
#define VGA_720x348_73Hz
Definition: fabglconf.h:273
#define SVGA_1024x768_60Hz
Definition: fabglconf.h:306
#define VGA_640x480_73Hz
Definition: fabglconf.h:255
#define SVGA_960x540_60Hz
Definition: fabglconf.h:303
#define VGA_720x348_50HzD
Definition: fabglconf.h:267
#define SVGA_1280x768_50Hz
Definition: fabglconf.h:324
#define VGA_640x350_70Hz
Definition: fabglconf.h:225
#define SVGA_1280x720_60Hz
Definition: fabglconf.h:318
#define VGA_480x300_75Hz
Definition: fabglconf.h:195
#define VGA_640x200_60HzD
Definition: fabglconf.h:210
#define PAL_720x576_50Hz
Definition: fabglconf.h:285
#define VGA_256x384_60Hz
Definition: fabglconf.h:175
#define VGA_400x300_60Hz
Definition: fabglconf.h:192
#define VESA_768x576_60Hz
Definition: fabglconf.h:291
#define VGA_640x400_70Hz
Definition: fabglconf.h:240
#define VGA_640x240_60Hz
Definition: fabglconf.h:219
#define VGA_512x384_60Hz
Definition: fabglconf.h:201
#define QVGA_320x240_60Hz
Definition: fabglconf.h:189
#define VESA_720x400_85Hz
Definition: fabglconf.h:282
#define VGA_640x384_60Hz
Definition: fabglconf.h:237
#define VGA_320x200_70Hz
Definition: fabglconf.h:180
#define VGA_512x448_60Hz
Definition: fabglconf.h:204
#define SVGA_1280x600_60Hz
Definition: fabglconf.h:315
#define VGA_640x200_70Hz
Definition: fabglconf.h:213
#define VGA_720x400_70Hz
Definition: fabglconf.h:279
#define VGA_640x480_60HzD
Definition: fabglconf.h:252
#define VESA_640x480_75Hz
Definition: fabglconf.h:258
#define VGA_640x400_60Hz
Definition: fabglconf.h:243
#define VGA_640x350_70HzAlt1
Definition: fabglconf.h:228
#define VGA_512x512_58Hz
Definition: fabglconf.h:207
#define SVGA_1280x720_60HzAlt1
Definition: fabglconf.h:321
#define SVGA_1024x768_75Hz
Definition: fabglconf.h:312
#define SVGA_1024x768_70Hz
Definition: fabglconf.h:309
#define VGA_512x192_60Hz
Definition: fabglconf.h:198
#define VGA_640x382_60Hz
Definition: fabglconf.h:234
VGAScanStart HStartingBlock
Specifies the VGA timings. This is a modeline decoded.