Created
December 7, 2017 14:50
-
-
Save t-mat/8a49185147bae6a4dc4b6be0d5611aa5 to your computer and use it in GitHub Desktop.
[ESP32] Minimum VGA test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Pixel | |
Pixel frequency 25.175M Hz | |
Seconds per pixel 1/25.175M = 39.72194637537239324727 ns | |
HSYNC | |
... --|-- HActive video (640pix) --|-- HFront porch (16pix) --| | |
|-- HPulse (96pix) --|-- HBack porch (48pix) --|-- HActive video (640pix) --|-- HFront porch (16pix) --| | |
|-- HPulse (96pix) --|-- HBack porch (48pix) --|-- ... | |
HPulse[0,95]: 96pix, 3.813us = 3813.30685ns | |
All video pins should be LOW. | |
H-Sync pin should be LOW. | |
HBack porch[96,143]: 48pix, 1.906us = 1906.653ns | |
All video pins should be LOW. | |
H-Sync pin should be HIGH. | |
HActive video[144,783]: 640pix, 25422.0 ns = 25.422 us | |
All video pins can be used for video signal. | |
H-Sync pin should be HIGH. | |
HFront porch[784,799]: 16pix, 635.55ns = 0.636 us | |
All video pins should be LOW. | |
H-Sync pin should be HIGH. | |
Total: 800pix, 31777.55710029791459781529 ns = 31.778 us | |
VSYNC | |
... --|-- VActive video (480lines) --|-- VFront porch (10lines) --| | |
|-- VPulse (2lines) --|-- VBack porch (33lines) --|-- VActive video (480lines) --|-- VFront porch (10lines) --| | |
|-- VPulse (2lines) --|-- VBack porch (33lines) --|-- ... | |
VPulse[0,1]: 2 lines, 0.063555114200596 ms | |
All video pins should be LOW | |
V-Sync pin should be LOW | |
VBack porch[2,34]: 33 lines, 1.0486593843098 ms | |
All video pins should be LOW | |
V-Sync pin should be HIGH | |
Active video[35,514]: 480 lines, 15.253227408143 ms | |
All video pins can be used for video signal. | |
V-Sync pin should be HIGH | |
VFront porch[515,524]: 10 lines, 0.31777557100298 ms | |
All video pins should be LOW | |
V-Sync pin should be HIGH | |
Total: 525 lines, 16.683217477656 (59.94Hz) | |
*/ | |
/////////////////////////////////////////////////////////////////////////// | |
namespace Pins { | |
const int vSync = 18; // VSYNC white GPIO18 | |
const int hSync = 19; // HSYNC gray GPIO19 | |
const int red = 25; // R red GPIO25 | |
const int green = 33; // G green GPIO33 | |
const int blue = 32; // B blue GPIO32 | |
const int led = LED_BUILTIN; // Builtin LED GPIO2 | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
inline void SetGpioByMask(uint32_t port, uint32_t maskPattern) { | |
if(port == 0) { | |
* (volatile uint32_t*) GPIO_OUT_W1TS_REG = (uint32_t) maskPattern; | |
} else { | |
* (volatile uint32_t*) GPIO_OUT1_W1TS_REG = (uint32_t) maskPattern; | |
} | |
} | |
inline void ClearGpioByMask(uint32_t port, uint32_t maskPattern) { | |
if(port == 0) { | |
* (volatile uint32_t*) GPIO_OUT_W1TC_REG = maskPattern; | |
} else { | |
* (volatile uint32_t*) GPIO_OUT1_W1TC_REG = maskPattern; | |
} | |
} | |
inline void SetGpio(uint32_t ioNumber) { | |
if(ioNumber <= 31) { | |
SetGpioByMask(0, 1 << ioNumber); | |
} else { | |
SetGpioByMask(1, 1 << (ioNumber-32)); | |
} | |
} | |
inline void ClearGpio(uint32_t ioNumber) { | |
if(ioNumber <= 31) { | |
ClearGpioByMask(0, 1 << ioNumber); | |
} else { | |
ClearGpioByMask(1, 1 << (ioNumber-32)); | |
} | |
} | |
inline void digitalWriteFast(uint32_t ioNumber, int isHigh) { | |
if(isHigh) { | |
SetGpio(ioNumber); | |
} else { | |
ClearGpio(ioNumber); | |
} | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
const double cycleCounterRate = 240.0 * 1000.0 * 1000.0; // 240M Cycles/sec | |
const double cycleCountPerSecond = cycleCounterRate; | |
const double cycleCountPerMillisecond = cycleCounterRate / (1000.0); | |
const double cycleCountPerMicrosecond = cycleCounterRate / (1000.0 * 1000.0); | |
const double cycleCountPerNanosecond = cycleCounterRate / (1000.0 * 1000.0 * 1000.0); | |
const double PixelFrequency = 25.175 * 1000.0 * 1000.0; // 25.175M Hz | |
const double SecondsPerPixel = 1.0 / PixelFrequency; | |
static uint32_t originOfLine; | |
static inline uint32_t getCycleCount() { | |
uint32_t ccount; | |
__asm__ __volatile__("esync; rsr %0,ccount":"=a" (ccount)); | |
return ccount; | |
} | |
inline void beginPixels() { | |
originOfLine = getCycleCount(); | |
} | |
template<uint32_t X> | |
inline void waitForPixels() { | |
const uint64_t th = static_cast<uint32_t>(X * SecondsPerPixel * cycleCountPerSecond); | |
while(getCycleCount() - originOfLine < th) {} | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
void setup() { | |
Serial.begin(115200); | |
Serial.printf("System FREQ = %d MHz\n", ESP.getCpuFreqMHz()); | |
Serial.printf("Pins::vSync = %d\n", Pins::vSync); | |
Serial.printf("Pins::hSync = %d\n", Pins::hSync); | |
Serial.printf("Pins::red = %d\n", Pins::red); | |
Serial.printf("Pins::green = %d\n", Pins::green); | |
Serial.printf("Pins::blue = %d\n", Pins::blue); | |
Serial.printf("Pins::led = %d\n", Pins::led); | |
pinMode(Pins::hSync , OUTPUT); | |
pinMode(Pins::vSync , OUTPUT); | |
pinMode(Pins::red , OUTPUT); | |
pinMode(Pins::green , OUTPUT); | |
pinMode(Pins::blue , OUTPUT); | |
pinMode(Pins::led , OUTPUT); | |
digitalWrite(Pins::hSync, HIGH); | |
digitalWrite(Pins::vSync, HIGH); | |
digitalWrite(Pins::red , LOW); | |
digitalWrite(Pins::green, LOW); | |
digitalWrite(Pins::blue , LOW); | |
digitalWrite(Pins::led , HIGH); | |
for(int i = 0; i < 31; ++i) { | |
ESP_INTR_DISABLE(i); | |
} | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
void loop() { | |
int vCount = 0; | |
for(;;) { | |
digitalWriteFast(Pins::led, (++vCount >> 5) & 1 ? HIGH : LOW); | |
for(int h = 0; h < 525; ++h) { | |
beginPixels(); | |
// Set HSYNC pulse | |
digitalWriteFast(Pins::hSync, LOW); | |
if(h == 0) { | |
digitalWriteFast(Pins::vSync, LOW); | |
} else if(h == 2) { | |
digitalWriteFast(Pins::vSync, HIGH); | |
} | |
// HSYNC Pulse (96pixels, 3.813us = 3813.30685ns) | |
waitForPixels<96>(); | |
// End of HSYNC pulse | |
digitalWriteFast(Pins::hSync, HIGH); | |
// Wait for Horizontal Backporch timing | |
waitForPixels<96 + 48>(); | |
// We can send video signal within [35,514] lines | |
if(h >= 2+33 && h < 2+33+480) { | |
const int c = (h - (2+33)) / 8; | |
digitalWriteFast(Pins::red , c & 1 ? HIGH : LOW); | |
digitalWriteFast(Pins::green , c & 2 ? HIGH : LOW); | |
digitalWriteFast(Pins::blue , c & 4 ? HIGH : LOW); | |
} | |
// Wait for Horizontal backporch timing | |
waitForPixels<96 + 48 + 640>(); | |
// Horizontal Backporch (48pixels, 2us) | |
digitalWriteFast(Pins::red , LOW); | |
digitalWriteFast(Pins::green , LOW); | |
digitalWriteFast(Pins::blue , LOW); | |
// Horizontal sync timing | |
waitForPixels<800>(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment