<!doctype html>

<html class="html-note-page" lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Generating Video</title>
    <meta name="dcterms.date" content="2020-04-07" />

    <link rel="stylesheet" href="/assets/style.css">
    <link rel="icon" type="image/x-icon" href="/assets/favicon.svg">
    <link rel="icon" type="image/png" href="/assets/favicon.png">
    <link rel="alternate" type="application/atom+xml" title="Fryzek Concepts" href="/feed.xml">
</head>

<body>
    <div class="header-bar">
        <a href="/index.html">
            <img src="/assets/favicon.svg" alt="frycon logo">
        </a>
        <div class="header-links">
                        <a href="/now.html" class="header-link">Now</a>
            <a href="/about.html" class="header-link">About</a>
            <a rel="me" href="https://mastodon.social/@hazematman" class="header-link">Social</a>
            <a href="https://git.fryzekconcepts.com" class="header-link">Code</a>
        </div>
    </div>
    <main>
<div class="page-title-header-container">
    <h1 class="page-title-header">Generating Video</h1>
        <div class="page-info-container">
                    <div class="plant-status">
                    <img src="/assets/evergreen.svg">
                    <div class="plant-status-text">
                    <p>evergreen</p>
                    </div>
                    </div>
                <div class="page-info-date-container">
            <p class="page-info-date">Published: 2020-04-07</p>
            <p class="page-info-date">Last Edited: 2022-01-20</p>
        </div>
    </div>
    </div>
<div class="note-divider"></div>
<div class="main-container">
    <div class="note-body">
<p>One thing I’m very interested in is computer graphics. This could be
complex 3D graphics or simple 2D graphics. The idea of getting a
computer to display visual data fascinates me. One fundamental part of
showing visual data is interfacing with a computer monitor. This can be
accomplished by generating a video signal that the monitor understands.
Below I have written instructions on how an FPGA can be used to generate
a video signal. I have specifically worked with the iCEBreaker FPGA but
the theory contained within this should work with any FPGA or device
that you can generate the appropriate timings for.</p>
<h3 id="tools">Tools</h3>
<p>Hardware used (<a
href="https://www.crowdsupply.com/1bitsquared/icebreaker-fpga">link for
board</a>):</p>
<ul>
<li>iCEBreaker FPGA</li>
<li>iCEBreaker 12-Bit DVI Pmod</li>
</ul>
<p>Software Used:</p>
<ul>
<li>IceStorm FPGA toolchain (<a
href="https://github.com/esden/summon-fpga-tools">follow install
instructions here</a>)</li>
</ul>
<h3 id="theory">Theory</h3>
<p>A video signal is composed of several parts, primarily the colour
signals and the sync signals. For this DVI Pmod, there is also a data
enable signal for the visible screen area. For the example here we are
going to be generating a 640x480 60 Hz video signal. Below is a table
describing the important data for our video signal.</p>
<table>
<tbody>
<tr>
<td>
Pixel Clock
</td>
<td>
25.175 MHz
</td>
</tr>
<tr>
<td>
Pixels Per Line
</td>
<td>
800 Pixels
</td>
</tr>
<tr>
<td>
Pixels Visible Per Line
</td>
<td>
640 Pixels
</td>
</tr>
<tr>
<td>
Horizontal Sync Front Porch Length
</td>
<td>
16 Pixels
</td>
</tr>
<tr>
<td>
Horizontal Sync Length
</td>
<td>
96 Pixels
</td>
</tr>
<tr>
<td>
Horizontal Sync Back Porch Length
</td>
<td>
48 Pixels
</td>
</tr>
<tr>
<td>
Lines Per Frame
</td>
<td>
525 Lines
</td>
</tr>
<tr>
<td>
Lines Visible Per Frame
</td>
<td>
480 Lines
</td>
</tr>
<tr>
<td>
Vertical Front Porch Length
</td>
<td>
10 Lines
</td>
</tr>
<tr>
<td>
Vertical Sync Length
</td>
<td>
2 Lines
</td>
</tr>
<tr>
<td>
Vertical Back Porch Length
</td>
<td>
33 Lines
</td>
</tr>
</tbody>
</table>
<p>Sourced from http://www.tinyvga.com/vga-timing/640x480@60Hz</p>
<p>The data from this table raises a few questions:</p>
<ol type="1">
<li>What is the Pixel Clock?</li>
<li>What is the difference between “Pixels/Lines” and “Visible
Pixels/Lines”?</li>
<li>What is “Front Porch”, “Sync”, and “Back Porch”?</li>
</ol>
<h4 id="pixel-clock">Pixel Clock</h4>
<p>The pixel clock is a fairly straightforward idea; this is the rate at
which we generate pixels. For video signal generation, the “pixel” is a
fundamental building block and we count things in the number of pixels
it takes up. Every time the pixel clock “ticks” we have incremented the
number of pixels we have processed. So for a 640x480 video signal, a
full line is 800 pixels, or 800 clock ticks. For the full 800x525 frame
there is 800 ticks x 525 lines, or 420000 clock ticks. If we are running
the display at 60 Hz, 420000 pixels per frame are generated 60 times per
second. Therefore, 25200000 pixels or clock ticks will pass in one
second. From this we can see the pixel clock frequency of 25.175 MHz is
roughly equal to 25200000 clock ticks. There is a small deviance from
the “true” values here, but monitors are flexible enough to accept this
video signal (my monitor reports it as 640x480@60Hz), and all
information I can find online says that 25.175 MHz is the value you want
to use. Later on we will see that the pixel clock is not required to be
exactly 25.175 Mhz.</p>
<h4 id="visible-area-vs-invisible-area">Visible Area vs Invisible
Area</h4>
<p><img
src="/assets/2020-04-07-generating-video/visible_invisible.png" /></p>
<p>From the above image we can see that a 640x480 video signal actually
generates a resolution larger than 640x480. The true resolution we
generate is 800x525, but only a 640x480 portion of that signal is
visible. The area that is not visible is where we generate the sync
signal. In other words, every part of the above image that is black is
where a sync signal is being generated.</p>
<h4 id="front-porch-back-porch-sync">Front Porch, Back Porch &amp;
Sync</h4>
<p>To better understand the front porch, back porch and sync signal,
let’s look at what the horizontal sync signal looks like during the
duration of a line:</p>
<p><img src="/assets/2020-04-07-generating-video/sync.png" /></p>
<p>From this we can see that the “Front Porch” is the invisible pixels
between the visible pixels and the sync pixels, and is represented by a
logical one or high signal. The “Sync” is the invisible pixels between
the front porch and back porch, and is represented by a logical zero or
low signal. The “Back Porch” is the invisible pixels after the sync
signal, and is represented by a logical one. For the case of 640x480
video, the visible pixel section lasts for 640 pixels. The front porch
section lasts for 16 pixels, after which the sync signal will become a
logical zero. This logical zero sync will last for 96 pixels, after
which the sync signal will become a logical one again. The back porch
will then last for 48 pixels. If you do a quick calculation right now of
640 + 16 + 96 + 48, we get 800 pixels which represents the full
horizontal resolution of the display. The vertical sync signal works
almost exactly the same, except the vertical sync signal acts on
lines.</p>
<h3 id="implementation">Implementation</h3>
<p>The first thing we can do that is going to simplify a lot of the
following logic is to keep track of which pixel, and which line we are
on. The below code block creates two registers to keep track of the
current pixel on the line (column) and the current line (line):</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode verilog"><code class="sourceCode verilog"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>logic <span class="op">[</span><span class="dv">9</span><span class="op">:</span><span class="dv">0</span><span class="op">]</span> line<span class="op">;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>logic <span class="op">[</span><span class="dv">9</span><span class="op">:</span><span class="dv">0</span><span class="op">]</span> column<span class="op">;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">always</span> <span class="op">@(</span><span class="kw">posedge</span> clk <span class="dt">or</span> <span class="kw">posedge</span> reset<span class="op">)</span> <span class="kw">begin</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">if</span><span class="op">(</span>reset <span class="op">==</span> <span class="dv">1</span><span class="op">)</span> <span class="kw">begin</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>        line <span class="op">&lt;=</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>        column <span class="op">&lt;=</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">end</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">else</span> <span class="kw">begin</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>        <span class="kw">if</span><span class="op">(</span>column <span class="op">==</span> <span class="dv">799</span> <span class="op">&amp;&amp;</span> line <span class="op">==</span> <span class="dv">524</span><span class="op">)</span> <span class="kw">begin</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>            line <span class="op">&lt;=</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>            column <span class="op">&lt;=</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>        <span class="kw">end</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>        <span class="kw">else</span> <span class="kw">if</span><span class="op">(</span>column <span class="op">==</span> <span class="dv">799</span><span class="op">)</span> <span class="kw">begin</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>            line <span class="op">&lt;=</span> line <span class="op">+</span> <span class="dv">1</span><span class="op">;</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>            column <span class="op">&lt;=</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>        <span class="kw">end</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>        <span class="kw">else</span> <span class="kw">begin</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>            column <span class="op">&lt;=</span> column <span class="op">+</span> <span class="dv">1</span><span class="op">;</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>        <span class="kw">end</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>    <span class="kw">end</span></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a><span class="kw">end</span></span></code></pre></div>
<p>This block of Verilog works by first initializing the line and column
register to zero on a reset. This is important to make sure that we
start from known values, otherwise the line and column register could
contain any value and our logic would not work. Next, we check if we are
at the bottom of the screen by comparing the current column to 799 (the
last pixel in the line) and the current line is 524 (the last line in
the frame). If these conditions are both true then we reset the line and
column back to zero to signify that we are starting a new frame. The
next block checks if the current column equals 799. Because the above if
statement failed,we know that we are at the end of the line but not the
end of the frame. If this is true we increment the current line count
and set the column back to zero to signify that we are starting a new
line. The final block simply increments the current pixel count. If we
reach this block ,we are neither at the end of the line or the end of
the frame so we can simply increment to the next pixel.</p>
<p>Now that we are keeping track of the current column and current line,
we can use this information to generate the horizontal and vertical sync
signals. From the theory above we know that the sync signal is only low
when we are between the front and back porch, at all other times the
signal is high. From this we can generate the sync signal with an OR and
two compares.</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode verilog"><code class="sourceCode verilog"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>logic horizontal_sync<span class="op">;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>logic vertical_sync<span class="op">;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> horizontal_sync <span class="op">=</span> column <span class="op">&lt;</span> <span class="dv">656</span> <span class="op">||</span> column <span class="op">&gt;=</span> <span class="dv">752</span><span class="op">;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> vertical_sync <span class="op">=</span> line <span class="op">&lt;</span> <span class="dv">490</span> <span class="op">||</span> line <span class="op">&gt;=</span> <span class="dv">492</span><span class="op">;</span></span></code></pre></div>
<p>Let’s examine the horizontal sync signal more closely. This statement
will evaluate to true if the current column is less than 656 or the
current column is greater than or equal to 752. This means that the
horizontal sync signal will be true except for when the current column
is between 656 and 751 inclusively. That is starting on column 656 the
horizontal sync signal will become false (low) and will remain that way
for the next 96 pixels until we reach pixel 752 where it will return to
being true (high). The vertical sync signal will work in the same way
except it is turned on based on the current line. Therefore, the signal
will remain high when the line is less than 490 and greater than or
equal to 492, and will remain low between lines 490 and 491
inclusive.</p>
<h4 id="putting-it-all-together">Putting It All Together</h4>
<p>Now that we have generated the video signal, we need to route it
towards the video output connectors on the iCEBreaker 12-bit DVI Pmod.
We also need to configure the iCEBreaker FPGA to have the appropriate
pixel clock frequency. First to get the correct pixel clock we are going
to use the following block of code:</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode verilog"><code class="sourceCode verilog"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>SB_PLL40_PAD #<span class="op">(</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  .DIVR<span class="op">(</span><span class="bn">4&#39;b0000</span><span class="op">),</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  .DIVF<span class="op">(</span><span class="bn">7&#39;b1000010</span><span class="op">),</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  .DIVQ<span class="op">(</span><span class="bn">3&#39;b101</span><span class="op">),</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>  .FILTER_RANGE<span class="op">(</span><span class="bn">3&#39;b001</span><span class="op">),</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>  .FEEDBACK_PATH<span class="op">(</span><span class="st">&quot;SIMPLE&quot;</span><span class="op">),</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>  .DELAY_ADJUSTMENT_MODE_FEEDBACK<span class="op">(</span><span class="st">&quot;FIXED&quot;</span><span class="op">),</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>  .FDA_FEEDBACK<span class="op">(</span><span class="bn">4&#39;b0000</span><span class="op">),</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>  .DELAY_ADJUSTMENT_MODE_RELATIVE<span class="op">(</span><span class="st">&quot;FIXED&quot;</span><span class="op">),</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>  .FDA_RELATIVE<span class="op">(</span><span class="bn">4&#39;b0000</span><span class="op">),</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>  .SHIFTREG_DIV_MODE<span class="op">(</span><span class="bn">2&#39;b00</span><span class="op">),</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>  .PLLOUT_SELECT<span class="op">(</span><span class="st">&quot;GENCLK&quot;</span><span class="op">),</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>  .ENABLE_ICEGATE<span class="op">(</span><span class="bn">1&#39;b0</span><span class="op">)</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a><span class="op">)</span> usb_pll_inst <span class="op">(</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>  .PACKAGEPIN<span class="op">(</span>CLK<span class="op">),</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>  .PLLOUTCORE<span class="op">(</span>pixel_clock<span class="op">),</span></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a>  .EXTFEEDBACK<span class="op">(),</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a>  .DYNAMICDELAY<span class="op">(),</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a>  .RESETB<span class="op">(</span><span class="bn">1&#39;b1</span><span class="op">),</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a>  .BYPASS<span class="op">(</span><span class="bn">1&#39;b0</span><span class="op">),</span></span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a>  .LATCHINPUTVALUE<span class="op">(),</span></span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a><span class="op">);</span></span></code></pre></div>
<p>This block is mainly a copy paste of the PLL setup code from the
iCEBreaker examples, but with a few important changes. The DIVR, DIVF,
and DIVQ values are changed to create a 25.125 MHz. This is not exactly
25.175 MHz, but it is close enough that the monitor is happy enough and
recognizes it as a 640x480@60 Hz signal. These values were found through
the “icepll” utility, below is an example of calling this utility from
the command line:</p>
<pre><code>$ icepll -i 12 -o 25.175

F_PLLIN:    12.000 MHz (given)
F_PLLOUT:   25.175 MHz (requested)
F_PLLOUT:   25.125 MHz (achieved)

FEEDBACK: SIMPLE
F_PFD:   12.000 MHz
F_VCO:  804.000 MHz

DIVR:  0 (4&#39;b0000)
DIVF: 66 (7&#39;b1000010)
DIVQ:  5 (3&#39;b101)

FILTER_RANGE: 1 (3&#39;b001)</code></pre>
<p>From here we can see we had an input clock of 12 MHz (This comes from
the FTDI chip on the iCEBreaker board), and we wanted to get a 25.175
MHz output clock. The closest the PLL could generate was a 25.125 MHz
clock with the settings provided for the DIVR, DIVF, and DIVQ
values.</p>
<p>Now that we have a pixel clock we can wire up the necessary signals
for the DVI video out. The DVI Pmod has the following mapping for all of
its connectors:</p>
<table>
<tbody>
<tr>
<td>
PMOD 1
</td>
<td>
</td>
<td>
PMOD 2
</td>
<td>
</td>
</tr>
<tr>
<td>
<strong>P1A1</strong>
</td>
<td>
Red bit 4
</td>
<td>
<strong>P1B1</strong>
</td>
<td>
Blue bit 4
</td>
</tr>
<tr>
<td>
<strong>P1A2</strong>
</td>
<td>
Red bit 3
</td>
<td>
<strong>P1B2</strong>
</td>
<td>
Pixel clock
</td>
</tr>
<tr>
<td>
<strong>P1A3</strong>
</td>
<td>
Green bit 4
</td>
<td>
<strong>P1B3</strong>
</td>
<td>
Blue bit 3
</td>
</tr>
<tr>
<td>
<strong>P1A4</strong>
</td>
<td>
Green bit 3
</td>
<td>
<strong>P1B4</strong>
</td>
<td>
Horizontal Sync
</td>
</tr>
<tr>
<td>
<strong>P1A7</strong>
</td>
<td>
Red bit 2
</td>
<td>
<strong>P1B7</strong>
</td>
<td>
Blue bit 2
</td>
</tr>
<tr>
<td>
<strong>P1A8</strong>
</td>
<td>
Red bit 1
</td>
<td>
<strong>P1B8</strong>
</td>
<td>
Blue bit 1
</td>
</tr>
<tr>
<td>
<strong>P1A9</strong>
</td>
<td>
Green bit 2
</td>
<td>
<strong>P1B9</strong>
</td>
<td>
Data Enable
</td>
</tr>
<tr>
<td>
<strong>P1A10</strong>
</td>
<td>
Green bit 1
</td>
<td>
<strong>P1B10</strong>
</td>
<td>
Vertical Sync
</td>
</tr>
</tbody>
</table>
<p>From this we can see that we need 4 bits for each colour channel, a
horizontal sync signal, a vertical sync signal, and additionally a data
enable signal. The data enable signal is not part of a standard video
signal and is just used by the DVI transmitter chip on the Pmod to
signify when we are in visible pixel area or invisible pixel area.
Therefore we will set the Date enable line when the current column is
less than 640 and the current line is less than 480. Based on this we
can connect the outputs like so:</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode verilog"><code class="sourceCode verilog"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>logic <span class="op">[</span><span class="dv">3</span><span class="op">:</span><span class="dv">0</span><span class="op">]</span> r<span class="op">;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>logic <span class="op">[</span><span class="dv">3</span><span class="op">:</span><span class="dv">0</span><span class="op">]</span> g<span class="op">;</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>logic <span class="op">[</span><span class="dv">3</span><span class="op">:</span><span class="dv">0</span><span class="op">]</span> b<span class="op">;</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>logic data_enable<span class="op">;</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> data_enable <span class="op">=</span> column <span class="op">&lt;</span> <span class="dv">640</span> <span class="op">&amp;&amp;</span> line <span class="op">&lt;</span> <span class="dv">480</span><span class="op">;</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> <span class="op">{</span>P1A1<span class="op">,</span>   P1A2<span class="op">,</span>   P1A3<span class="op">,</span>   P1A4<span class="op">,</span>   P1A7<span class="op">,</span>   P1A8<span class="op">,</span>   P1A9<span class="op">,</span>   P1A10<span class="op">}</span> <span class="op">=</span> </span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>       <span class="op">{</span>r<span class="op">[</span><span class="dv">3</span><span class="op">],</span>   r<span class="op">[</span><span class="dv">2</span><span class="op">],</span>   g<span class="op">[</span><span class="dv">3</span><span class="op">],</span>   g<span class="op">[</span><span class="dv">2</span><span class="op">],</span>   r<span class="op">[</span><span class="dv">1</span><span class="op">],</span>   r<span class="op">[</span><span class="dv">0</span><span class="op">],</span>   g<span class="op">[</span><span class="dv">1</span><span class="op">],</span>   g<span class="op">[</span><span class="dv">0</span><span class="op">]};</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> <span class="op">{</span>P1B1<span class="op">,</span>   P1B2<span class="op">,</span>   P1B3<span class="op">,</span>   P1B4<span class="op">,</span>   P1B7<span class="op">,</span>   P1B8<span class="op">,</span>   P1B9<span class="op">,</span>   P1B10<span class="op">}</span> <span class="op">=</span> </span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>       <span class="op">{</span>b<span class="op">[</span><span class="dv">3</span><span class="op">],</span>   pixel_clock<span class="op">,</span> b<span class="op">[</span><span class="dv">2</span><span class="op">],</span>   horizontal_sync<span class="op">,</span> b<span class="op">[</span><span class="dv">1</span><span class="op">],</span>   b<span class="op">[</span><span class="dv">0</span><span class="op">],</span>   data_enable<span class="op">,</span> vertical_sync<span class="op">};</span></span></code></pre></div>
<p>Now for testing purposes we are going to set the output colour to be
fixed to pure red so additional logic to pick a pixel colour is not
required for this example. We can do this as shown below:</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode verilog"><code class="sourceCode verilog"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> r <span class="op">=</span> <span class="bn">4&#39;b1111</span><span class="op">;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> g <span class="op">=</span> <span class="bn">4&#39;b0000</span><span class="op">;</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> b <span class="op">=</span> <span class="bn">4&#39;b0000</span><span class="op">;</span></span></code></pre></div>
<p>Putting all of the above code together with whatever additional
inputs are required for the iCEBreaker FPGA gives us the following block
of code:</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode verilog"><code class="sourceCode verilog"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> top</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="op">(</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="dt">input</span> CLK<span class="op">,</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="dt">output</span> LEDR_N<span class="op">,</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="dt">output</span> LEDG_N<span class="op">,</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="dt">input</span> BTN_N<span class="op">,</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="dt">output</span> P1A1<span class="op">,</span> P1A2<span class="op">,</span> P1A3<span class="op">,</span> P1A4<span class="op">,</span> P1A7<span class="op">,</span> P1A8<span class="op">,</span> P1A9<span class="op">,</span> P1A10<span class="op">,</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="dt">output</span> P1B1<span class="op">,</span> P1B2<span class="op">,</span> P1B3<span class="op">,</span> P1B4<span class="op">,</span> P1B7<span class="op">,</span> P1B8<span class="op">,</span> P1B9<span class="op">,</span> P1B10</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="op">);</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a><span class="ot">`define PIXELS_PER_LINE 10&#39;d800</span></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a><span class="ot">`define PIXELS_VISIBLE_PER_LINE 10&#39;d640</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a><span class="ot">`define LINES_PER_FRAME 10&#39;d525</span></span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a><span class="ot">`define LINES_VISIBLE_PER_FRAME 10&#39;d480</span></span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a><span class="ot">`define HORIZONTAL_FRONTPORCH 10&#39;d656</span></span>
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a><span class="ot">`define HORIZONTAL_BACKPORCH 10&#39;d752</span></span>
<span id="cb7-17"><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a><span class="ot">`define VERTICAL_FRONTPORCH 10&#39;d490</span></span>
<span id="cb7-18"><a href="#cb7-18" aria-hidden="true" tabindex="-1"></a><span class="ot">`define VERTICAL_BACKPORCH 10&#39;d492</span></span>
<span id="cb7-19"><a href="#cb7-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-20"><a href="#cb7-20" aria-hidden="true" tabindex="-1"></a>logic <span class="op">[</span><span class="dv">9</span><span class="op">:</span><span class="dv">0</span><span class="op">]</span> line<span class="op">;</span></span>
<span id="cb7-21"><a href="#cb7-21" aria-hidden="true" tabindex="-1"></a>logic <span class="op">[</span><span class="dv">9</span><span class="op">:</span><span class="dv">0</span><span class="op">]</span> column<span class="op">;</span></span>
<span id="cb7-22"><a href="#cb7-22" aria-hidden="true" tabindex="-1"></a>logic horizontal_sync<span class="op">;</span></span>
<span id="cb7-23"><a href="#cb7-23" aria-hidden="true" tabindex="-1"></a>logic vertical_sync<span class="op">;</span></span>
<span id="cb7-24"><a href="#cb7-24" aria-hidden="true" tabindex="-1"></a>logic data_enable<span class="op">;</span></span>
<span id="cb7-25"><a href="#cb7-25" aria-hidden="true" tabindex="-1"></a>logic pixel_clock<span class="op">;</span></span>
<span id="cb7-26"><a href="#cb7-26" aria-hidden="true" tabindex="-1"></a>logic reset<span class="op">;</span></span>
<span id="cb7-27"><a href="#cb7-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-28"><a href="#cb7-28" aria-hidden="true" tabindex="-1"></a>logic <span class="op">[</span><span class="dv">3</span><span class="op">:</span><span class="dv">0</span><span class="op">]</span> r<span class="op">;</span></span>
<span id="cb7-29"><a href="#cb7-29" aria-hidden="true" tabindex="-1"></a>logic <span class="op">[</span><span class="dv">3</span><span class="op">:</span><span class="dv">0</span><span class="op">]</span> g<span class="op">;</span></span>
<span id="cb7-30"><a href="#cb7-30" aria-hidden="true" tabindex="-1"></a>logic <span class="op">[</span><span class="dv">3</span><span class="op">:</span><span class="dv">0</span><span class="op">]</span> b<span class="op">;</span></span>
<span id="cb7-31"><a href="#cb7-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-32"><a href="#cb7-32" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> horizontal_sync <span class="op">=</span> column <span class="op">&lt;</span> <span class="op">(</span><span class="ot">`HORIZONTAL_FRONTPORCH</span><span class="op">)</span> <span class="op">||</span> column <span class="op">&gt;=</span> <span class="op">(</span><span class="ot">`HORIZONTAL_BACKPORCH</span><span class="op">);</span></span>
<span id="cb7-33"><a href="#cb7-33" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> vertical_sync <span class="op">=</span> line <span class="op">&lt;</span> <span class="op">(</span><span class="ot">`VERTICAL_FRONTPORCH</span><span class="op">)</span> <span class="op">||</span> line <span class="op">&gt;=</span> <span class="op">(</span><span class="ot">`VERTICAL_BACKPORCH</span><span class="op">);</span></span>
<span id="cb7-34"><a href="#cb7-34" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> data_enable <span class="op">=</span> <span class="op">(</span>column <span class="op">&lt;</span> <span class="ot">`PIXELS_VISIBLE_PER_LINE</span><span class="op">)</span> <span class="op">&amp;&amp;</span> <span class="op">(</span>line <span class="op">&lt;</span> <span class="ot">`LINES_VISIBLE_PER_FRAME</span><span class="op">);</span></span>
<span id="cb7-35"><a href="#cb7-35" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-36"><a href="#cb7-36" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> reset <span class="op">=</span> <span class="op">~</span>BTN_N<span class="op">;</span></span>
<span id="cb7-37"><a href="#cb7-37" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> LEDR_N <span class="op">=</span> <span class="dv">1</span><span class="op">;</span></span>
<span id="cb7-38"><a href="#cb7-38" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> LEDG_N <span class="op">=</span> <span class="dv">1</span><span class="op">;</span></span>
<span id="cb7-39"><a href="#cb7-39" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-40"><a href="#cb7-40" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> r <span class="op">=</span> <span class="bn">4&#39;b1111</span><span class="op">;</span></span>
<span id="cb7-41"><a href="#cb7-41" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> g <span class="op">=</span> <span class="bn">4&#39;b0000</span><span class="op">;</span></span>
<span id="cb7-42"><a href="#cb7-42" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> b <span class="op">=</span> <span class="bn">4&#39;b0000</span><span class="op">;</span></span>
<span id="cb7-43"><a href="#cb7-43" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-44"><a href="#cb7-44" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> <span class="op">{</span>P1A1<span class="op">,</span>   P1A2<span class="op">,</span>   P1A3<span class="op">,</span>   P1A4<span class="op">,</span>   P1A7<span class="op">,</span>   P1A8<span class="op">,</span>   P1A9<span class="op">,</span>   P1A10<span class="op">}</span> <span class="op">=</span> </span>
<span id="cb7-45"><a href="#cb7-45" aria-hidden="true" tabindex="-1"></a>       <span class="op">{</span>r<span class="op">[</span><span class="dv">3</span><span class="op">],</span>   r<span class="op">[</span><span class="dv">2</span><span class="op">],</span>   g<span class="op">[</span><span class="dv">3</span><span class="op">],</span>   g<span class="op">[</span><span class="dv">2</span><span class="op">],</span>   r<span class="op">[</span><span class="dv">1</span><span class="op">],</span>   r<span class="op">[</span><span class="dv">0</span><span class="op">],</span>   g<span class="op">[</span><span class="dv">1</span><span class="op">],</span>   g<span class="op">[</span><span class="dv">0</span><span class="op">]};</span></span>
<span id="cb7-46"><a href="#cb7-46" aria-hidden="true" tabindex="-1"></a><span class="kw">assign</span> <span class="op">{</span>P1B1<span class="op">,</span>   P1B2<span class="op">,</span>   P1B3<span class="op">,</span>   P1B4<span class="op">,</span>   P1B7<span class="op">,</span>   P1B8<span class="op">,</span>   P1B9<span class="op">,</span>   P1B10<span class="op">}</span> <span class="op">=</span> </span>
<span id="cb7-47"><a href="#cb7-47" aria-hidden="true" tabindex="-1"></a>       <span class="op">{</span>b<span class="op">[</span><span class="dv">3</span><span class="op">],</span>   pixel_clock<span class="op">,</span> b<span class="op">[</span><span class="dv">2</span><span class="op">],</span>   horizontal_sync<span class="op">,</span> b<span class="op">[</span><span class="dv">1</span><span class="op">],</span>   b<span class="op">[</span><span class="dv">0</span><span class="op">],</span>   data_enable<span class="op">,</span> vertical_sync<span class="op">};</span></span>
<span id="cb7-48"><a href="#cb7-48" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-49"><a href="#cb7-49" aria-hidden="true" tabindex="-1"></a><span class="co">// Pixel and line counter</span></span>
<span id="cb7-50"><a href="#cb7-50" aria-hidden="true" tabindex="-1"></a><span class="kw">always</span> <span class="op">@(</span><span class="kw">posedge</span> pixel_clock <span class="dt">or</span> <span class="kw">posedge</span> reset<span class="op">)</span> <span class="kw">begin</span></span>
<span id="cb7-51"><a href="#cb7-51" aria-hidden="true" tabindex="-1"></a>    <span class="kw">if</span><span class="op">(</span>reset <span class="op">==</span> <span class="dv">1</span><span class="op">)</span> <span class="kw">begin</span></span>
<span id="cb7-52"><a href="#cb7-52" aria-hidden="true" tabindex="-1"></a>        line <span class="op">&lt;=</span> <span class="ot">`LINES_PER_FRAME</span> <span class="op">-</span> <span class="dv">2</span><span class="op">;</span></span>
<span id="cb7-53"><a href="#cb7-53" aria-hidden="true" tabindex="-1"></a>        column <span class="op">&lt;=</span> <span class="ot">`PIXELS_PER_LINE</span> <span class="op">-</span> <span class="dv">16</span><span class="op">;</span></span>
<span id="cb7-54"><a href="#cb7-54" aria-hidden="true" tabindex="-1"></a>    <span class="kw">end</span></span>
<span id="cb7-55"><a href="#cb7-55" aria-hidden="true" tabindex="-1"></a>    <span class="kw">else</span> <span class="kw">begin</span></span>
<span id="cb7-56"><a href="#cb7-56" aria-hidden="true" tabindex="-1"></a>        <span class="kw">if</span><span class="op">(</span>column <span class="op">==</span> <span class="op">(</span><span class="ot">`PIXELS_PER_LINE</span> <span class="op">-</span> <span class="dv">1</span><span class="op">)</span> <span class="op">&amp;&amp;</span> line <span class="op">==</span> <span class="op">(</span><span class="ot">`LINES_PER_FRAME</span> <span class="op">-</span> <span class="dv">1</span><span class="op">))</span> <span class="kw">begin</span></span>
<span id="cb7-57"><a href="#cb7-57" aria-hidden="true" tabindex="-1"></a>            line <span class="op">&lt;=</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb7-58"><a href="#cb7-58" aria-hidden="true" tabindex="-1"></a>            column <span class="op">&lt;=</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb7-59"><a href="#cb7-59" aria-hidden="true" tabindex="-1"></a>        <span class="kw">end</span></span>
<span id="cb7-60"><a href="#cb7-60" aria-hidden="true" tabindex="-1"></a>        <span class="kw">else</span> <span class="kw">if</span><span class="op">(</span>column <span class="op">==</span> <span class="ot">`PIXELS_PER_LINE</span> <span class="op">-</span> <span class="dv">1</span><span class="op">)</span> <span class="kw">begin</span></span>
<span id="cb7-61"><a href="#cb7-61" aria-hidden="true" tabindex="-1"></a>            line <span class="op">&lt;=</span> line <span class="op">+</span> <span class="dv">1</span><span class="op">;</span></span>
<span id="cb7-62"><a href="#cb7-62" aria-hidden="true" tabindex="-1"></a>            column <span class="op">&lt;=</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb7-63"><a href="#cb7-63" aria-hidden="true" tabindex="-1"></a>        <span class="kw">end</span></span>
<span id="cb7-64"><a href="#cb7-64" aria-hidden="true" tabindex="-1"></a>        <span class="kw">else</span> <span class="kw">begin</span></span>
<span id="cb7-65"><a href="#cb7-65" aria-hidden="true" tabindex="-1"></a>            column <span class="op">&lt;=</span> column <span class="op">+</span> <span class="dv">1</span><span class="op">;</span></span>
<span id="cb7-66"><a href="#cb7-66" aria-hidden="true" tabindex="-1"></a>        <span class="kw">end</span></span>
<span id="cb7-67"><a href="#cb7-67" aria-hidden="true" tabindex="-1"></a>    <span class="kw">end</span></span>
<span id="cb7-68"><a href="#cb7-68" aria-hidden="true" tabindex="-1"></a><span class="kw">end</span></span>
<span id="cb7-69"><a href="#cb7-69" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-70"><a href="#cb7-70" aria-hidden="true" tabindex="-1"></a>SB_PLL40_PAD #<span class="op">(</span></span>
<span id="cb7-71"><a href="#cb7-71" aria-hidden="true" tabindex="-1"></a>  .DIVR<span class="op">(</span><span class="bn">4&#39;b0000</span><span class="op">),</span></span>
<span id="cb7-72"><a href="#cb7-72" aria-hidden="true" tabindex="-1"></a>  .DIVF<span class="op">(</span><span class="bn">7&#39;b1000010</span><span class="op">),</span></span>
<span id="cb7-73"><a href="#cb7-73" aria-hidden="true" tabindex="-1"></a>  .DIVQ<span class="op">(</span><span class="bn">3&#39;b101</span><span class="op">),</span></span>
<span id="cb7-74"><a href="#cb7-74" aria-hidden="true" tabindex="-1"></a>  .FILTER_RANGE<span class="op">(</span><span class="bn">3&#39;b001</span><span class="op">),</span></span>
<span id="cb7-75"><a href="#cb7-75" aria-hidden="true" tabindex="-1"></a>  .FEEDBACK_PATH<span class="op">(</span><span class="st">&quot;SIMPLE&quot;</span><span class="op">),</span></span>
<span id="cb7-76"><a href="#cb7-76" aria-hidden="true" tabindex="-1"></a>  .DELAY_ADJUSTMENT_MODE_FEEDBACK<span class="op">(</span><span class="st">&quot;FIXED&quot;</span><span class="op">),</span></span>
<span id="cb7-77"><a href="#cb7-77" aria-hidden="true" tabindex="-1"></a>  .FDA_FEEDBACK<span class="op">(</span><span class="bn">4&#39;b0000</span><span class="op">),</span></span>
<span id="cb7-78"><a href="#cb7-78" aria-hidden="true" tabindex="-1"></a>  .DELAY_ADJUSTMENT_MODE_RELATIVE<span class="op">(</span><span class="st">&quot;FIXED&quot;</span><span class="op">),</span></span>
<span id="cb7-79"><a href="#cb7-79" aria-hidden="true" tabindex="-1"></a>  .FDA_RELATIVE<span class="op">(</span><span class="bn">4&#39;b0000</span><span class="op">),</span></span>
<span id="cb7-80"><a href="#cb7-80" aria-hidden="true" tabindex="-1"></a>  .SHIFTREG_DIV_MODE<span class="op">(</span><span class="bn">2&#39;b00</span><span class="op">),</span></span>
<span id="cb7-81"><a href="#cb7-81" aria-hidden="true" tabindex="-1"></a>  .PLLOUT_SELECT<span class="op">(</span><span class="st">&quot;GENCLK&quot;</span><span class="op">),</span></span>
<span id="cb7-82"><a href="#cb7-82" aria-hidden="true" tabindex="-1"></a>  .ENABLE_ICEGATE<span class="op">(</span><span class="bn">1&#39;b0</span><span class="op">)</span></span>
<span id="cb7-83"><a href="#cb7-83" aria-hidden="true" tabindex="-1"></a><span class="op">)</span> usb_pll_inst <span class="op">(</span></span>
<span id="cb7-84"><a href="#cb7-84" aria-hidden="true" tabindex="-1"></a>  .PACKAGEPIN<span class="op">(</span>CLK<span class="op">),</span></span>
<span id="cb7-85"><a href="#cb7-85" aria-hidden="true" tabindex="-1"></a>  .PLLOUTCORE<span class="op">(</span>pixel_clock<span class="op">),</span></span>
<span id="cb7-86"><a href="#cb7-86" aria-hidden="true" tabindex="-1"></a>  .EXTFEEDBACK<span class="op">(),</span></span>
<span id="cb7-87"><a href="#cb7-87" aria-hidden="true" tabindex="-1"></a>  .DYNAMICDELAY<span class="op">(),</span></span>
<span id="cb7-88"><a href="#cb7-88" aria-hidden="true" tabindex="-1"></a>  .RESETB<span class="op">(</span><span class="bn">1&#39;b1</span><span class="op">),</span></span>
<span id="cb7-89"><a href="#cb7-89" aria-hidden="true" tabindex="-1"></a>  .BYPASS<span class="op">(</span><span class="bn">1&#39;b0</span><span class="op">),</span></span>
<span id="cb7-90"><a href="#cb7-90" aria-hidden="true" tabindex="-1"></a>  .LATCHINPUTVALUE<span class="op">(),</span></span>
<span id="cb7-91"><a href="#cb7-91" aria-hidden="true" tabindex="-1"></a><span class="op">);</span></span>
<span id="cb7-92"><a href="#cb7-92" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-93"><a href="#cb7-93" aria-hidden="true" tabindex="-1"></a><span class="kw">endmodule</span></span></code></pre></div>
<p>To build this, you will require a .pcf file describing the pin
mapping of the iCEBreaker board. I grabbed mine from the iCEBreaker
examples <a
href="https://raw.githubusercontent.com/icebreaker-fpga/icebreaker-examples/master/icebreaker.pcf">here</a>.
Grab that file and put it in the same folder as the file for the code
provided above. We can the run the following commands to generate a
binary to program onto the FPGA:</p>
<pre><code>yosys -ql out.log  -p &#39;synth_ice40 -top top -json out.json&#39; top.sv
nextpnr-ice40 --up5k   --json out.json --pcf icebreaker.pcf --asc out.asc
icetime  -d up5k -mtr out.rpt out.asc
icepack out.asc out.bin</code></pre>
<p>This will generate an out.bin file that we will need to flash onto
the board. Make sure your iCEBreaker FPGA is connected via USB to your
computer and you can program it with the following commands.</p>
<pre><code>iceprog out.bin</code></pre>
<p>Now connect up a video cable (my DVI Pmod has an HDMI connector, but
it only carries the DVI video signal) to the board and monitor and you
should get results like this:</p>
<p><img
src="/assets/2020-04-07-generating-video/IMG_20200407_172119-1-1024x768.jpg" /></p>
<p>You can also see from the monitor settings menu that the video signal
was recognized as 640x480@60 Hz. Now the code presented in this post is
specific to the iCEBreaker board and the DVI Pmod, but the theory can be
applied to any FPGA and any connector that uses a video signal like
this. For example you could wire up a DAC with a resistor ladder to
generate a VGA signal. The logic for the timings here would be exactly
the same if you wanted a 640x480@60 Hz VGA signal.</p>
    </div>
</div>    </main>
</body>
</html>