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.

Revisions

  1. t-mat created this gist Dec 7, 2017.
    214 changes: 214 additions & 0 deletions esp32_vga_test.ino
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,214 @@
    /*
    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>();
    }
    }
    }