{"id":218,"date":"2013-06-06T00:29:40","date_gmt":"2013-06-06T05:29:40","guid":{"rendered":"http:\/\/kratzindustries.com\/CodeRedBlog\/?p=218"},"modified":"2014-03-27T04:34:05","modified_gmt":"2014-03-27T04:34:05","slug":"learn-with-me-fpga-led-matrix-part-2","status":"publish","type":"post","link":"https:\/\/burnt-traces.com\/?p=218","title":{"rendered":"FPGA + LED Matrix, Part 2"},"content":{"rendered":"<p>In the second part of this article, we&#8217;re going to try and get a little more interesting stuff going on with our FPGA powered LED matrix. To start, we will try to get a simple image to display on the matrix. To do this we will need a way to store the image. VHDL allows for array types so we can accomplish this by creating an eight element array of eight bit vectors, giving us one bit per pixel. We can then use each of these vectors as a mask value to AND with the col signal. This is a little confusing (at least in my head), as each col value contains a bit for each row in the column, so we AND that with the col_mask value, which is essential the pixels for a row of the display. Starting with the same setup from last time, we are adding these new signals to the architecture.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n\r\n type display_t is array(7 downto 0) of STD_LOGIC_VECTOR(7 downto 0);\r\n signal display : display_t := (&quot;00000000&quot; ,    -- A simple image to display\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;01100110&quot; , \t-- stored in an array\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;01100110&quot; ,\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;00000000&quot; ,\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;00000000&quot; ,\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;11000011&quot; ,\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;00111100&quot; ,\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;00000000&quot;);\r\n\r\n signal col_mask : STD_LOGIC_VECTOR(7 downto 0) := &quot;00000000&quot;;\t\t--mask value used to activate only desired pixels\r\n signal row_count : unsigned(2 downto 0) := &quot;000&quot;;\t\t\t\t\t\t--pointer for array\r\n\r\n<\/pre>\n<p>Note that for the array, you have do declare an array type first, then declare an array of that type. Like many languages, we are allowed to instantiate the array with some values. Notice the nice smiley face. Also note that the array is declared 7 downto 0, meaning the first element essentially is the last one in the instantiation list. Since row 0 of our display is at the bottom, this means the image should appear just as the bits appear in the code. I also added a row_count signal, declared as unsigned because it will be used numerically. This will just count up as we scan the matrix rows and serve as a pointer to our array. Also added is the col_mask signal. This signal stores the current row loaded from the array. Below is the added code to increment the row_count and retrieve the col_mask. Note that the row_count is declared as 3 bits, meaning it will automatically rollover back to zero after 7.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n\r\n\t\t\t\t\t-- increment row count\r\n\t\t\t\t\trow_count &lt;= row_count + 1;\r\n\t\t\t\t\t-- get column mask from current position in array\r\n\t\t\t\t\tcol_mask &lt;= display(conv_integer(row_count));\r\n\r\n<\/pre>\n<p>And then of course we AND the mask to the output.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n\r\n\t\t\t--combine column with mask to only display selected pixels\r\n\t\t\tA(15 downto 8) &lt;= (col AND col_mask);\r\n<\/pre>\n<p>Here is the complete code for this example.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n--Standard includes\r\nlibrary IEEE;\r\nuse IEEE.STD_LOGIC_1164.ALL;\r\nuse IEEE.STD_LOGIC_ARITH.ALL;\r\nuse IEEE.STD_LOGIC_UNSIGNED.ALL;\r\n\r\n--Entity definiton\r\nentity First is\r\n    Port ( A : out  STD_LOGIC_VECTOR (16 downto 0); -- maps to pins 0 to 16 of port A\r\n\t\t\t  clk : in STD_LOGIC); --clock signal\r\nend First;\r\n\r\n--architecture definition\r\narchitecture Behavioral of First is\r\n --Interial signals\r\n signal counter : STD_LOGIC_VECTOR(8 downto 0) := (others =&gt; '0'); --counter to control state and delay\r\n signal row : STD_LOGIC_VECTOR(7 downto 0) := &quot;11111110&quot;;\t\t\t\t--signal for LED rows\r\n signal col : STD_LOGIC_VECTOR(7 downto 0) := &quot;00000001&quot;;\t\t\t\t--signal for LED columns\r\n type display_t is array(7 downto 0) of STD_LOGIC_VECTOR(7 downto 0);\r\n signal display : display_t := (&quot;00000000&quot; ,    -- A simple image to display\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;01100110&quot; , \t-- stored in an array\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;01100110&quot; ,\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;00000000&quot; ,\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;00000000&quot; ,\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;11000011&quot; ,\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;00111100&quot; ,\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;00000000&quot;);\r\n\r\n signal col_mask : STD_LOGIC_VECTOR(7 downto 0) := &quot;00000000&quot;;\t\t--mask value used to activate only desired pixels\r\n signal row_count : unsigned(2 downto 0) := &quot;000&quot;;\t\t\t\t\t\t--pointer for array\r\n\r\nbegin\r\n\t--Process Definition\r\n\tcount: process(clk)\r\n   begin\r\n\t\t-- triggers action on rising edge of clock signal\r\n     if rising_edge(clk) then\r\n\t    --increment counter\r\n       counter &lt;= counter+1;\r\n\t\t --clock period is 31.25ns, counter is 9 bits, should scan whole matrix in &lt; 1ms\r\n\t\t\t--trigger each time counter rolls over back to zero\r\n\t\t\tif counter = 0 then\r\n\t\t\t\t-- Left Rotate col\r\n\t\t\t\tcol &lt;= col(6 downto 0) &amp; col(7);\r\n\t\t\t\t-- Trigger when last column becomes active\r\n\t\t\t\tif col = &quot;10000000&quot; then\r\n\t\t\t\t\t-- Left rotate row\r\n\t\t\t\t\trow &lt;= row(6 downto 0) &amp; row(7);\r\n\t\t\t\t\t-- increment row count\r\n\t\t\t\t\trow_count &lt;= row_count + 1;\r\n\t\t\t\t\t-- get column mask from current position in array\r\n\t\t\t\t\tcol_mask &lt;= display(conv_integer(row_count));\r\n\t\t\t\tend if;\r\n\t\t\tend if;\r\n\t\t\t--copy signals to outputs\r\n\t\t\tA(7 downto 0) &lt;= row;\r\n\t\t\t--combine column with mask to only display selected pixels\r\n\t\t\tA(15 downto 8) &lt;= (col AND col_mask);\r\n     end if;\r\n   end process;\r\n\r\n\r\nend Behavioral;\r\n<\/pre>\n<p>This give the following output.<\/p>\n<p><a href=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2013\/06\/2013-06-05-23.36.04.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2013\/06\/2013-06-05-23.36.04-300x169.jpg\" alt=\"\" title=\"FPGA LED Matrix Smiley 1\" width=\"300\" height=\"169\" class=\"aligncenter size-medium wp-image-219\" srcset=\"https:\/\/burnt-traces.com\/wp-content\/uploads\/2013\/06\/2013-06-05-23.36.04-300x169.jpg 300w, https:\/\/burnt-traces.com\/wp-content\/uploads\/2013\/06\/2013-06-05-23.36.04-1024x577.jpg 1024w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Now if you noticed, it looks good, but that&#8217;s not the image we intended. Its shifted up by one row! See <a href=\"http:\/\/stackoverflow.com\/questions\/16976562\/vhdl-execution-order\/16976746?noredirect=1#16976746\">my question on Stack Overflow<\/a> for an explanation of where I went wrong. Apparently signals are updated at the end of the process, so the value is definitely updated after the value is retrieved from the array. The fix is pretty simple, I just instantiate my row_count to 1 to compensate.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n signal row_count : unsigned(2 downto 0) := &quot;001&quot;;\t\t\t\t\t\t--pointer for array\r\n<\/pre>\n<p>Now it displays correctly.<\/p>\n<p><a href=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2013\/06\/2013-06-05-23.55.41.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2013\/06\/2013-06-05-23.55.41-300x169.jpg\" alt=\"\" title=\"FPGA LED MATRIX, Smiley Corrected\" width=\"300\" height=\"169\" class=\"aligncenter size-medium wp-image-220\" srcset=\"https:\/\/burnt-traces.com\/wp-content\/uploads\/2013\/06\/2013-06-05-23.55.41-300x169.jpg 300w, https:\/\/burnt-traces.com\/wp-content\/uploads\/2013\/06\/2013-06-05-23.55.41-1024x577.jpg 1024w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Now for one more experiment in this installment, lets create a vertical scrolling effect. In the above example where I screwed it up the first time, having the wrong value for row_count shifts the image up and down. We can use this to create our scrolling effect. My first thought was to add a second process with a delay counter and just subtract one from the row_count value. However, that produces a compile error, &#8220;this signal is connected to multiple drivers.&#8221; I&#8217;m guessing that means its illegal to set a signal from multiple processes. So, instead we will add a new signal, row_offset, same type as row_count. Then we will use the second process to increment that, and just subtract it from row_count when indexing the array.<\/p>\n<p>We add these two new signals.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n signal row_offset : unsigned(2 downto 0) := &quot;000&quot;;\t\t\t\t\t--offset to control vertical scrolling\r\n signal scroll_delay : STD_LOGIC_VECTOR(22 downto 0) := (others =&gt; '0'); --counter for vertical scroll delay\r\n<\/pre>\n<p>And we add this new process to the same architecture.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n\tvscroll: process(clk)\r\n\t\tbegin\r\n\r\n\t\t\tif rising_edge(clk) then\r\n\t\t\t\t--counter is 23 bits, will rollover at .26 seconds\r\n\t\t\t\tscroll_delay &lt;= scroll_delay+1;\r\n\r\n\t\t\t\tif scroll_delay = 0 then\r\n\t\t\t\t\t--decrement to mis-align row count, to give a vertical scrolling effect\r\n\t\t\t\t\trow_offset &lt;= row_offset+1;\r\n\t\t\t\tend if;\r\n\t\t\tend if;\r\n\t\tend process;\r\n<\/pre>\n<p>The we modify the array access like this.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n\t\t\t\t\t-- get column mask from current position in array\r\n\t\t\t\t\tcol_mask &lt;= display(conv_integer(row_count) - conv_integer(row_offset));\r\n<\/pre>\n<p>I had to use the two separate conv_integer functions as the compiler complained of trying to do the math first, then calling conv_integer. Here is the complete code.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n--Standard includes\r\nlibrary IEEE;\r\nuse IEEE.STD_LOGIC_1164.ALL;\r\nuse IEEE.STD_LOGIC_ARITH.ALL;\r\nuse IEEE.STD_LOGIC_UNSIGNED.ALL;\r\n\r\n--Entity definiton\r\nentity First is\r\n    Port ( A : out  STD_LOGIC_VECTOR (16 downto 0); -- maps to pins 0 to 16 of port A\r\n\t\t\t  clk : in STD_LOGIC); --clock signal\r\nend First;\r\n\r\n--architecture definition\r\narchitecture Behavioral of First is\r\n --Interial signals\r\n signal counter : STD_LOGIC_VECTOR(8 downto 0) := (others =&gt; '0'); --counter to control state and delay\r\n signal row : STD_LOGIC_VECTOR(7 downto 0) := &quot;11111110&quot;;\t\t\t\t--signal for LED rows\r\n signal col : STD_LOGIC_VECTOR(7 downto 0) := &quot;00000001&quot;;\t\t\t\t--signal for LED columns\r\n type display_t is array(7 downto 0) of STD_LOGIC_VECTOR(7 downto 0);\r\n signal display : display_t := (&quot;00000000&quot; ,    -- A simple image to display\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;01100110&quot; , \t-- stored in an array\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;01100110&quot; ,\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;00000000&quot; ,\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;00000000&quot; ,\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;11000011&quot; ,\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;00111100&quot; ,\r\n\t\t\t\t\t\t\t\t\t\t\t&quot;00000000&quot;);\r\n\r\n signal col_mask : STD_LOGIC_VECTOR(7 downto 0) := &quot;00000000&quot;;\t\t--mask value used to activate only desired pixels\r\n signal row_count : unsigned(2 downto 0) := &quot;001&quot;;\t\t\t\t\t\t--pointer for array\r\n signal row_offset : unsigned(2 downto 0) := &quot;000&quot;;\t\t\t\t\t--offset to control vertical scrolling\r\n signal scroll_delay : STD_LOGIC_VECTOR(22 downto 0) := (others =&gt; '0'); --counter for vertical scroll delay\r\n\r\nbegin\r\n\t--Process Definition\r\n\tcount: process(clk)\r\n   begin\r\n\t\t-- triggers action on rising edge of clock signal\r\n     if rising_edge(clk) then\r\n\t    --increment counter\r\n       counter &lt;= counter+1;\r\n\t\t --clock period is 31.25ns, counter is 9 bits, should scan whole matrix in &lt; 1ms\r\n\t\t\t--trigger each time counter rolls over back to zero\r\n\t\t\tif counter = 0 then\r\n\t\t\t\t-- Left Rotate col\r\n\t\t\t\tcol &lt;= col(6 downto 0) &amp; col(7);\r\n\t\t\t\t-- Trigger when last column becomes active\r\n\t\t\t\tif col = &quot;10000000&quot; then\r\n\t\t\t\t\t-- Left rotate row\r\n\t\t\t\t\trow &lt;= row(6 downto 0) &amp; row(7);\r\n\t\t\t\t\t-- increment row count\r\n\t\t\t\t\trow_count &lt;= row_count + 1;\r\n\t\t\t\t\t-- get column mask from current position in array\r\n\t\t\t\t\tcol_mask &lt;= display(conv_integer(row_count) - conv_integer(row_offset));\r\n\t\t\t\tend if;\r\n\t\t\tend if;\r\n\t\t\t--copy signals to outputs\r\n\t\t\tA(7 downto 0) &lt;= row;\r\n\t\t\t--combine column with mask to only display selected pixels\r\n\t\t\tA(15 downto 8) &lt;= (col AND col_mask);\r\n     end if;\r\n   end process;\r\n\r\n\tvscroll: process(clk)\r\n\t\tbegin\r\n\r\n\t\t\tif rising_edge(clk) then\r\n\t\t\t\t--counter is 23 bits, will rollover at .26 seconds\r\n\t\t\t\tscroll_delay &lt;= scroll_delay+1;\r\n\r\n\t\t\t\tif scroll_delay = 0 then\r\n\t\t\t\t\t--decrement to mis-align row count, to give a vertical scrolling effect\r\n\t\t\t\t\trow_offset &lt;= row_offset+1;\r\n\t\t\t\tend if;\r\n\t\t\tend if;\r\n\t\tend process;\r\n\r\n\r\nend Behavioral;\r\n\r\n\r\n\r\n<\/pre>\n<p>And here is the scrolling effect in action.<br \/>\n<a href=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2013\/06\/2013-06-06-00.17.08.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2013\/06\/2013-06-06-00.17.08-300x170.jpg\" alt=\"\" title=\"FPGA LED MATRIX Scrolling Simley\" width=\"300\" height=\"170\" class=\"aligncenter size-medium wp-image-221\" srcset=\"https:\/\/burnt-traces.com\/wp-content\/uploads\/2013\/06\/2013-06-06-00.17.08-300x170.jpg 300w, https:\/\/burnt-traces.com\/wp-content\/uploads\/2013\/06\/2013-06-06-00.17.08-1024x582.jpg 1024w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Next time we will see about making a simple animation with several frames. See you then!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the second part of this article, we&#8217;re going to try and get a little more interesting stuff going on with our FPGA powered LED matrix. To start, we will try to get a simple image to display on the matrix. To do this we will need a way to store the image. VHDL allows&hellip;&nbsp;<a href=\"https:\/\/burnt-traces.com\/?p=218\" class=\"\" rel=\"bookmark\">Read More &raquo;<span class=\"screen-reader-text\">FPGA + LED Matrix, Part 2<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","footnotes":""},"categories":[3],"tags":[29,31,32,33,38],"class_list":["post-218","post","type-post","status-publish","format-standard","hentry","category-electronics","tag-fpga","tag-learn-with-me","tag-led","tag-matrix","tag-vhdl"],"_links":{"self":[{"href":"https:\/\/burnt-traces.com\/index.php?rest_route=\/wp\/v2\/posts\/218","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/burnt-traces.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/burnt-traces.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/burnt-traces.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/burnt-traces.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=218"}],"version-history":[{"count":1,"href":"https:\/\/burnt-traces.com\/index.php?rest_route=\/wp\/v2\/posts\/218\/revisions"}],"predecessor-version":[{"id":324,"href":"https:\/\/burnt-traces.com\/index.php?rest_route=\/wp\/v2\/posts\/218\/revisions\/324"}],"wp:attachment":[{"href":"https:\/\/burnt-traces.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=218"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/burnt-traces.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=218"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/burnt-traces.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=218"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}