Skip to content

Instantly share code, notes, and snippets.

@t-mat
Created December 7, 2017 14:50
Show Gist options
  • Save t-mat/8a49185147bae6a4dc4b6be0d5611aa5 to your computer and use it in GitHub Desktop.
Save t-mat/8a49185147bae6a4dc4b6be0d5611aa5 to your computer and use it in GitHub Desktop.
[ESP32] Minimum VGA test
/*
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