LED Matrix Sound Visualizer

What is a Sound Visualizer?

In this tutorial, we want to use a microphone to record the ambient sound, then filter different frequencies out of the sound. This is done by a so called "fast Fourier transform" and is usualy a complex operation, but can quickly be made by an FPGA. Finaly, we want to display the result with an LED matrix.

What you need

Important: These links below are only for German products.

1. Electronics

  1. VHDPlus Core MAX10
  2. 1 8x32 LED matrix*
  3. 1 MEMS Microphone
  4. 1 Level shifter*
  5. Some jumper cables*

*These links are Affiliate Links, by purchasing with them, you support us and our work. As a customer, you pay the same price, we receive part of their revenue through commission.

The hardware


As there are no cheap level shifter boards pre-soldere, I highly recommend learning some soldering skills. You could go ahead and plug the headers in the holes, but this doesn't ensure a connection and that the headers stay in place. Also soldering is has multiple benefits and can be used for many possible projects. Here is a cheap soldering station.

Alternatively, here is a more expensive level shifter that comes pre-soldered.

Here is an example of how to solder the headers to the level shifter.


The led matrix* has to be connected with through a level shifter with the FPGA board, as the matrix works with 5V. The level shifter converts the 3.3V outputs of the FPGA to 5V outputs. Here you can see how to connect the matrix: Motor connect

5V and GND have to be conected with HV and GND of the level shifter and VCC and GND of the matrix. 3.3V has to be connected with LV of the level shifter. The 3 I/Os of the FPGA have to be connected with the LV I/Os of the level shifter. The LV I/Os then with the matrix.

To connect the microphone, all you need to do is connect 3.3V and GND of the microphone with 3.3V and GND of the FPGA and connect the rest of the pins (except for SEL) with the FPGA I/Os.

The software

Start by creating a new project, and import the LED_Matrix library folder, the Spectrum_Analyzer library folder, the I2S_IN and the SPI library. Important: make sure that you assign Brightness and Shutdown values or remove them from NewComponent. Also Config has to change from '0' to '1' when the matrix is connected. Now you can copy this example:

--MEMS Microphone
--LED Matrix
CONSTANT volume_divider : NATURAL := 8; -- lower value = higehr volume
CONSTANT offset : INTEGER := 6130; -- Microphone value += offset, so median is 0
--Reads the Microphone library
SIGNAL I2S_Interface_IN_Data_L : STD_LOGIC_VECTOR (18-1 downto 0);
SIGNAL I2S_Interface_IN_Data_R : STD_LOGIC_VECTOR (18-1 downto 0);
SIGNAL I2S_Interface_IN_Ready : STD_LOGIC;
NewComponent I2S_Interface_IN
CLK_Frequency => 12000000,
Sampling_Frequency => 32000,
Data_Width => 18,
Sample_Bits => 32,
BCLK_Edge => '1',
Reset => '0',
Data => Data,
Data_L => I2S_Interface_IN_Data_L,
Data_R => I2S_Interface_IN_Data_R,
Ready => I2S_Interface_IN_Ready,
--Analyzes the micophone data
SIGNAL Spectrum_Analyzer_data_o : Spectrum_Type;
SIGNAL Spectrum_Analyzer_New_Data : STD_LOGIC;
NewComponent Spectrum_Analyzer
CLK_Frequency => 12000000,
Sample_Frequency => 10000,
Frequency_Numbers => 16,
Range_Multiplier => 2,
adc_in => resize((SIGNED(I2S_Interface_IN_Data_L)+offset)/volume_divider, 8),
New_Data => Spectrum_Analyzer_New_Data,
data_o => Spectrum_Analyzer_data_o,
--Create the LED Matix bitmap and initialize the matrix
Process ()
--Load settings (brightness and shutdown)
LED_Matrix_Config <= '0'; --Wait on start (not absolutely necessary)
LED_Matrix_Config <= '1'; --Send settings
Step{ LED_Matrix_Config <= '0'; }
ParFor(i IN 0 to 31)
If(Spectrum_Analyzer_data_o(i) > 127){LED_Matrix_Panel_Bitmap(i)(0) <= '1';}Else{LED_Matrix_Panel_Bitmap(i)(0) <= '0';}
If(Spectrum_Analyzer_data_o(i) > 64) {LED_Matrix_Panel_Bitmap(i)(1) <= '1';}Else{LED_Matrix_Panel_Bitmap(i)(1) <= '0';}
If(Spectrum_Analyzer_data_o(i) > 31) {LED_Matrix_Panel_Bitmap(i)(2) <= '1';}Else{LED_Matrix_Panel_Bitmap(i)(2) <= '0';}
If(Spectrum_Analyzer_data_o(i) > 15) {LED_Matrix_Panel_Bitmap(i)(3) <= '1';}Else{LED_Matrix_Panel_Bitmap(i)(3) <= '0';}
If(Spectrum_Analyzer_data_o(i) > 7) {LED_Matrix_Panel_Bitmap(i)(4) <= '1';}Else{LED_Matrix_Panel_Bitmap(i)(4) <= '0';}
If(Spectrum_Analyzer_data_o(i) > 3) {LED_Matrix_Panel_Bitmap(i)(5) <= '1';}Else{LED_Matrix_Panel_Bitmap(i)(5) <= '0';}
If(Spectrum_Analyzer_data_o(i) > 1) {LED_Matrix_Panel_Bitmap(i)(6) <= '1';}Else{LED_Matrix_Panel_Bitmap(i)(6) <= '0';}
If(Spectrum_Analyzer_data_o(i) > 0) {LED_Matrix_Panel_Bitmap(i)(7) <= '1';}Else{LED_Matrix_Panel_Bitmap(i)(7) <= '0';}
--Update image -> show already defined image
LED_Matrix_Update <= '0';
Step { LED_Matrix_Update <= '1'; }
--Wait for new data
While(Spectrum_Analyzer_New_Data = '0') {}
--Output the matrix data
SIGNAL LED_Matrix_Panel_Bitmap : LED_Matrix_Array ((4*8)-1 downto 0);
NewComponent LED_Matrix
CLK_Frequency => 12000000,
Panels => 4,
Rotate_seg => '1',
Mirror => '1',
Reset => '0',
CS_O => CS_O,
Panel_Bitmap => LED_Matrix_Panel_Bitmap,
Update => LED_Matrix_Update,
Config => LED_Matrix_Config,

This example displays the analyzed frequencies with an 8x32 LED matrix.

Make sure that you choose the correct FPGA Pins that are connected with DIN, CL and CLK, that 3.3V is connected with the level shifter and that 5V is connected with the level shifter and the matrix.

You can find the full example here.


This is one example of a cool usefull project with an LED matrix. Here are some more:

  1. Text/Image displayer
  2. Clock with timer
  3. Custom text displayer

Possible problems

Matrix is dark

  1. Check is everything connected properly. (Is 3.3V, 5V and GND connected? Does the level shifter have a connection? Are the correct pins used?)
  2. Is the program correct? (Shutdown => '0'? Does LED_Matrix_Config change from '0' to '1' when the matrix has power?)
  3. Does the matrix have a MAX7219 IC?
  4. Check if the I2S_Interface_IN_Data_L data changes, so the microphone works properly. This code outputs the value with the matrix:
For(i IN 0 to 17)
LED_Matrix_Panel_Bitmap(i)(0) <= I2S_Interface_IN_Data_L(i);
--Update image -> show already defined image
LED_Matrix_Update <= '0';
Step { LED_Matrix_Update <= '1'; }

Last column always on

Try to play around with the offset constant. The last column is the one for the lowest frequency and an offset is interpreted as a very low frequency.

Not sensitive enought

You can set a lower value as volume_divider to increase sensitivity.

We hope you enjoyed the tutorial and feel free to check out

Last updated on by Leon Beier