Skip to content

FPGA + RGB LED Matrix

I was just recently aquired an 8×8 RGB LED matrix, similar to this one. I though it would be good practice to wire up the Papilio board to it an write up some VHDL to drive the display.

2013-10-02 23.55.48

As you can see on the datasheet, this is a common anode display, meaning that the positive voltage will be supplied to the 8 common terminals to operate. The pinout is pretty simple, 1 through 8 are the blue cathodes, which I connected to pins B0-B7 on the board. 9 through 16 are the green cathodes, which are connected to pins A8-A15 board. Pins 21 through 28, are the red cathodes and are connected to the boards B15-B8 pins. Pins 17,18,19,20,29,30,31,32 are the anodes and are connected to pins A0-A7 on the board. I included some small 360 ohm resistors on the anodes, just to limit the current. However the LEDs are not very bright as such. Its much brighter, and I *think* it’s safe to drive the outputs directly from the pins. Otherwise some simple buffer drivers I’m sure would produce a much brighter result.

As for the code, I started off with some of the same stuff from the last LED matrix. The PWM drive is the same, but I changed the counter from 8 bit to 4 bit. It simply counts up, and as long as the counter is less than the set value, the output bit is on.


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;


entity PWM is
    Port ( Value_In : in  integer range 0 to 15 ; --input for pwm value
           Bit_Out : out  STD_LOGIC;					--pwm output
			  clk : in STD_LOGIC);							--system clock
end PWM;

architecture Behavioral of PWM is

begin

	pwm: process(clk)
		variable count: integer range 0 to 15 := 0; --variable, internal to process, 8 bit counter
	begin
		if rising_edge(clk) then 
			--increment count variable (note variable uses := not <=
			count := count + 1;
			
			if count < Value_In then 
			   --while the counter is less than value, set bit
				--this ensures duty cycle is proportional to value
				Bit_Out <= '1';
			else
				--off during other half of cycle, while counter is greater than value
				Bit_Out <= '0';
			end if;		
				
		end if;
	
	end process;
	


end Behavioral;

For the main code, I decided to just have it display all one color, where the RGB values are cycled through at different rates. I also tried to pull out as much as I could from the main process block, to avoid some of the confusion of values being set after the process completes, which caused actions to be one step behind where I thought they would be. The way I understand it, statements in the architecture block are “wired up” so that changes propagate almost instantly. I added three processes to handle the cycling of the RGB values. The signal ‘counter’ just serves as a delay to time the scanning process. The signal ‘row’ is a 24 bit mask for the cathode pins, where the 0 indicates the pin that is active. The signal ‘col’ is an 8 bit mask for the anode pins, where 1 indicates the active pin. The signal ‘rgb’ is a 3 bit flag which is rotated to keep track of which value, red, green, or blue, should be applied to the currently active cathode pin. ‘col’ is rotated left whenever ‘counter’ rolls back to zero, ‘row’ and ‘rgb’ are rotated left when after ‘col’ is rotated back to its original value. A WITH … SELECT syntax is used to map the different color values into ‘value’ depending on the value of ‘rgb’. ‘value’ is mapped into the PW generator, and ‘pwm_bit’ is mapped as its output. A WHEN … ELSE style assignment is used to enable or disable the ‘col’ flags on the output, which is what ties the PWM drive to the output.


--Standard includes
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

--Entity definiton
entity First is
    Port ( A : out  STD_LOGIC_VECTOR (15 downto 0); -- maps to pins 0 to 16 of port A
				B : out STD_LOGIC_VECTOR (15 downto 0); --
			  clk : in STD_LOGIC); --clock signal
end First;

--architecture definition
architecture Behavioral of First is

--component definition for the PWM
component PWM is
    Port ( Value_In : in  integer range 0 to 15 ;
           Bit_Out : out  STD_LOGIC;
			  clk : in STD_LOGIC);
end component;
			  
 --Interial signals
 --counter to control state and delay
 signal counter : STD_LOGIC_VECTOR(8 downto 0) := (others => '0'); 
 --signal for LED "rows", anodes. 0 provides ground for selected row
 signal row : STD_LOGIC_VECTOR(23 downto 0) := "111111111111111111111110";				
 --signal for LED "columns", common cathodes. 1 provides + volts for selected column.
 signal col : STD_LOGIC_VECTOR(7 downto 0) := "00000001";				--signal for LED columns
 
 --rgb flag, for selecting R,G,B values to send to selected output
 signal rgb : STD_LOGIC_VECTOR(2 downto 0) := "001";

 --rolling color values																	
 signal red_value : integer range 0 to 15 := 0;		 
 signal green_value : integer range 0 to 15 := 0;					
 signal blue_value : integer range 0 to 15 := 0;					
 --used to retrieve value from array, mapped to PWM input
 signal value : integer range 0 to 15 := 0;	
 
 --counters for timing color changes
 signal red_counter : STD_LOGIC_VECTOR(20 downto 0) := (others => '0');
 signal green_counter : STD_LOGIC_VECTOR(19 downto 0) := (others => '0');
 signal blue_counter : STD_LOGIC_VECTOR(18 downto 0) := (others => '0');
	
 --signal to be mapped to PWM output	
 signal pwm_bit : STD_LOGIC;												

begin 

	--port map for linking to the PWM
	PW1 : PWM port map(Value_In => value, 
							 Bit_out => pwm_bit,
							 clk => clk);
							 

	--route row masks to outputs
	A(15 downto 8) <=  row(22) & row(19) & row(16) & row(13) & row(10) & row(7) & row(4) & row(1); -- green
	B(15 downto 8) <= row(21) & row(18) & row(15) & row(12) & row(9) & row(6) & row(3) & row(0); -- red
	B(7 downto 0) <= row(23) & row(20) & row(17) & row(14) & row(11) & row(8) & row(5) & row(2); -- blue
	
	--route column masks to outputs, only if PWM bit is on
	A(7 downto 0) <= col WHEN pwm_bit = '1' 
								ELSE "00000000";
	
	--route proper RGB value to PWM generator
	WITH rgb SELECT
		value <= red_value WHEN "001",
					green_value WHEN "010",
					blue_value WHEN "100",
				   0 WHEN OTHERS;
					
					
	--Process Definition
	scan_matrix: process(clk)
   begin
		-- triggers action on rising edge of clock signal
     if rising_edge(clk) then
	    --increment counter
       counter <= counter+1;
		 --clock period is 31.25ns, counter is 9 bits, should scan whole matrix in < 1ms
			--trigger each time counter rolls over back to zero 
			if counter = 0 then 
				-- Left Rotate col
				col <= col(6 downto 0) & col(7);

				-- Trigger when last column becomes active
				if col = "10000000" then
					-- Left rotate row
					row <= row(22 downto 0) & row(23);
					-- increment row count
					rgb <= rgb(1 downto 0) & rgb(2);

				end if;
				
			end if;
					
     end if; 	  	  
   end process;
						
		
	--Process Definition
	red: process(clk)
   begin
		-- triggers action on rising edge of clock signal
     if rising_edge(clk) then
			red_counter <= red_counter + 1;
			if red_counter = 0 then 
				red_value <= red_value + 1;
			end if;
	  end if;
	end process;
	  
	  	--Process Definition
	blue: process(clk)
   begin
		-- triggers action on rising edge of clock signal
     if rising_edge(clk) then
			blue_counter <= blue_counter + 1;
			if blue_counter = 0 then 
				blue_value <= blue_value + 1;
			end if;
	  end if;
	end process;
	
		--Process Definition
	green: process(clk)
   begin
		-- triggers action on rising edge of clock signal
     if rising_edge(clk) then
			green_counter <= green_counter + 1;
			if green_counter = 0 then 
				green_value <= green_value + 1;
			end if;
	  end if;
	end process;
	
	
		
	
end Behavioral;

1 thought on “FPGA + RGB LED Matrix”

Leave a Reply

Your email address will not be published. Required fields are marked *

 characters available