The Sound (and Sight) Of Music! Teaching Electronics With The Stm32 Nucleo

About the project

What if we could tap into this marriage of music and technology to make something even more amazing?

Project info

Items used in this project

Hardware components

STM32 Nucleo-64 development board with STM32F401RET6 MCU, supports Arduino and ST morpho connectivity STM32 Nucleo-64 development board with STM32F401RET6 MCU, supports Arduino and ST morpho connectivity x 1
Cap Aluminum Lytic 10uF 50V 20% (5 X 11mm) Radial 5mm 60mA 2000h 85?C Ammo Pack Cap Aluminum Lytic 10uF 50V 20% (5 X 11mm) Radial 5mm 60mA 2000h 85?C Ammo Pack x 2
Resistor; Metal Film; Res 10 Kilohms; Pwr-Rtg 0.125 W; Tol 1%; Axial; Tape & Reel Resistor; Metal Film; Res 10 Kilohms; Pwr-Rtg 0.125 W; Tol 1%; Axial; Tape & Reel x 2
Operational Amplifier [Texas Instruments] LM324N Operational Amplifier Operational Amplifier [Texas Instruments] LM324N Operational Amplifier x 1
Res Cermet Trimmer 10K Ohm 10% 1/2W 1(Elec)/1(Mech)Turn 3.15mm (9.53 X 9.53 X 4.83mm) Pin Thru-Hole Tube Res Cermet Trimmer 10K Ohm 10% 1/2W 1(Elec)/1(Mech)Turn 3.15mm (9.53 X 9.53 X 4.83mm) Pin Thru-Hole Tube x 2
Res Thin Film 100 Ohm 1% 0.4W ±50ppm/C Conformal Coated AXL Automotive Ammo Res Thin Film 100 Ohm 1% 0.4W ±50ppm/C Conformal Coated AXL Automotive Ammo x 3
Res Thin Film 220 Ohm 1% 0.4W ±50ppm/C Conformal Coated AXL Automotive Ammo Res Thin Film 220 Ohm 1% 0.4W ±50ppm/C Conformal Coated AXL Automotive Ammo x 6
Red Ø 5 mm 60° 30 mA 10 mcd 2 V Tinted/Diffused High Efficiency LED - T-1¾ Red Ø 5 mm 60° 30 mA 10 mcd 2 V Tinted/Diffused High Efficiency LED - T-1¾ x 6
Conn 3.5MM Stereo Jack F 5 POS 5mm Solder RA Thru-Hole 5 Terminal 1 Port Conn 3.5MM Stereo Jack F 5 POS 5mm Solder RA Thru-Hole 5 Terminal 1 Port x 1
70 Jumper Assortment Kit; Kit Contents: 70-Pcs of Pre-cut, Pre-stripped & Pre-formed #22 Gauge Insulated Solid Hook-U... 70 Jumper Assortment Kit; Kit Contents: 70-Pcs of Pre-cut, Pre-stripped & Pre-formed #22 Gauge Insulated Solid Hook-U... x 1
Breadboard 3.3X2.1X.3" 400 Pts 21-26AWG ABS Breadboard 3.3X2.1X.3" 400 Pts 21-26AWG ABS x 1
Circular Connector, MIL-C-26482 Series I (VG95328), Plug, 3, Pin, Crimp, Cable Mount Circular Connector, MIL-C-26482 Series I (VG95328), Plug, 3, Pin, Crimp, Cable Mount x 1
USB On-The-Go (OTG) Shielded I/O Cable Assembly, USB A-to-Mini B, USB 2.0, 1.50m Length, Black USB On-The-Go (OTG) Shielded I/O Cable Assembly, USB A-to-Mini B, USB 2.0, 1.50m Length, Black x 1

View all

Software apps and online services

Free mbed.org programming tool Free mbed.org programming tool

Story

Figure 1: The Nucleo Light and Sound Machine controls the music and flashes LEDs in time to the music.

Over the last fifteen years or so, music has found itself encapsulated into digital bits. What if we could tap into this marriage of music and technology to make something even more amazing?

In this project we are going to add a visual representation of our music. We will take the audio from our favorite portable music player and electronically sample its waveforms to produce a stunning light show using LEDs. This project can be done both with and without a microcontroller. The LEDs can be driven directly using an operational amplifier or sent to an ST Nucleo via analog-to-digital conversion to add even more fun effects. When setting out to design this project, we aimed to strike a balance between cost, complexity, and educational value. But most importantly, we wanted a project that captured the imagination of students and empowered them to take the basic design and hack it to meet their own unique desires. The circuit is a basic audio amplifier circuit that, in principle, is used in tons of audio products. In a circuit that fits onto a tiny breadboard we can teach Ohm’s Law, voltage dividers, potentiometers, LEDs, capacitors, current limiting, operational amplifier theory, and line level audio! The beauty of the design is that it is self-contained and can be used without having to write any code or interface with a microcontroller, except to provide power to the op amp. Of course, you could provide power to the op amp using 3 AA batteries if so desired. You can use a USB cable (mini-B to standard-A) connected to the Nucleo from a PC to power the Nucleo, as well. The Nucleo is used to power the entire set up regardless of whether you complete it with option A or B instructions.

Materials

To make things super simple we are providing a pre-built shopping cart with all the correct components. Remove the RCA and USB cables from the cart if you already have them. No worries on selecting the wrong part by accident! We’ve also labeled each item in the BOM to corresponding part in the provided schematic.

The Bill of Materials (BOM) (See above) for this project is for the electronics as shown in Figure 1. In the demo video, a smartphone or MP3 player is connected to the 3.5mm Stereo jack (smartphone/MP3 player not included!)

We will use an STM32 Nucleo F401RE microcontroller platform. The STM32 Nucleo is programmed using the C/C++ language, but we provide the code for you. Nevertheless, programming tools are free online at mbed.org.

Figure 2: The STM32 Nucleo has a detachable, reusable programming card at the top that is removed once a project is done.

Tools:

Since this project is aimed towards classrooms and not electronics laboratories, we wanted to make sure that no hand tools or electronic test equipment was required. Of course, if you are teaching a course specifically geared towards electronics and have access to a multimeter or an oscilloscope, hooking it up the outputs of the audio jack makes for a very cool visualization of sound (Figure 2.) But to be sure, this is completely optional!

Figure 3: An oscilloscope is not needed for this project, but if you have one, you can visualize the sound with the oscilloscope.

If you plan to do more with the Nucleo than what is in this project, try looking at the Nucleo site on mbed.org: https://developer.mbed.org/platforms/ST-Nucleo-F401RE/

Here, you will find other projects and any additional information, such as this pin-out diagram of the Nucleo:

Figure 4: The STM32 Nucleo pin-out and other Nucleo information and projects can be found at mbed.org

Overview

Striving for simplicity, the circuit is very straightforward. We are taking audio from a computer or mobile device via its 3.5mm audio jack and splitting left and right audio channel so we can tweak each channel individually based on our preferences. Line level audio is very low voltage and not suitable to drive our LEDs or the Nucleo directly. That is why we are taking the audio and running it through an operational amplifier, often shortened to just “op amp”. Actually, if you look carefully at the schematic (located in the Resources Section) you will notice that each channel signal is run through two op amps. The first op amp provides amplification and the second op amp provides buffering.

Op amps are one of the workhorse components of circuit design. They can be used in wonderfully simple but also incredibly complex ways. Learning op amps is a key skill. For this project we are using the op amp in a configuration known as a “non-inverting “amplifier”. The alternative is an “inverting amplifier”. To understand the difference let’s take a quick look at the parts of analog signal.

Figure 5: Parts of an analog signal.

In a non-inverting amplifier the output will remain in phase with the input signal, in an inverting amplifier the output is 180-degrees out of phase. If you look at the schematic you will notice that the output of the first op amps feeds back into the inverting terminal via a small network of resistors. The arrangement of resistors is known as a voltage divider circuit. It allows us to control the amount of amplification or gain the op amp will perform on the input signal. Using a fixed resistor and variable resistor (the one we’re using is referred to as a trimming potentiometer or trimpot for short) will allow us to manually control the gain. By turning the trimpot we vary its resistance, and in turn the gain of the op amp which will cause the LEDs to glow more brightly or more dimly depending on how it’s adjusted.

Figure 6: Non-inverting op amp signal.

Figure 7: Inverting op amp signal.

At the output of the second op amp we are using a resistor and capacitor in parallel to create a high pass noise filter to get rid of any RF noise the circuit might pick up. Lastly the LED and resistor in series are there to provide the light show. The LED is obviously doing the blinking and the resistor provide current protection for the diode.

Lastly, some notes about 3.5mm Tip-Ring-Sleeve audio jacks. The signal ground is commonly found on the outermost conductor, which is called a sleeve. The left channel is typically on the tip, and the right channel is sent out over the ring (Think “R” for right and ring).

Figure 8: A 3.5mm Tip-Ring-Sleeve audio jack diagram (left), schematic of the jack (middle), and PC speaker input (right) to play the music using built-in PC speakers if you don’t have portable speakers. Audio jack part number: 172-2208 or 172-8362-E.

The Build (Building the Electronics)

Conveniently all the components will fit on a single, small breadboard. The build is very straightforward. The first nine steps are used regardless if you are going to use the Nucleo or not. The final steps will vary depending if you desire to use the Nucleo or not. Option A will simply drive two LEDs without the Nucleo (using AA batteries instead of the Nucleo to power it.) Option B will require a computer to program the Nucleo and then perform the light show as we have programmed in our code. If you stop after implementing Option A, then you can still use the Nucleo for power.

Figure 9: Schematic of the STM32 Nucleo Sight and Sound open source hardware project. (NucleoLightSoundEducationSchematic.png)

Instructions: Print out the schematic as listed in the Resources section.

  1. Carefully place the op-amp favoring one end of the breadboard, but leave about 3 rows available on the end you choose. Be aware that each pin has a different purpose. The datasheet will show you what each pin does and how they interconnect internally. Notice that DIP ICs have a dot (either printed or a depression on the package) near pin 1. There also tends to be a small “U”-shaped depression towards the top of the chip, with pin 1 being to the left. I cannot stress enough the importance of buying an extra IC or two when ordering your parts. From bent pins that break off, to reversing Vcc and GND, once chips are broken there is no repair. Have a few extra on hand will give you peace of mind when experimenting with a design.
  2. Next place the trimpot so that the central wiper pin is connected to op amp pin 5, and that an outer pin of the trimpot connects to op amp pin 2. Recall, we are splitting out the left and right audio channel so we are going to repeat this for the other side of the op amp. This time, the central wiper pin is connected to op amp pin 10 and that an outer pin of the trimpot connects to op amp pin 13.
  3. Add the fixed resistor to each trimpot, with one end of the resistor attaching to the trimpots and the other to GND. Connect to the same outer pin of the trimpots that you used in step 2.
  4. Place the 3.5 mm audio jack onto the breadboard. Be sure to align the audio jack so each pin gets its own row on the breadboard.
  5. Connect pin 5 of the audio jack (tip, left channel) to pin 12 of the op amp.
  6. Connect pin 2 of the audio jack (ring, right channel) to pin 3 of the op amp.
  7. Connect pin 1 of the audio jack (sleeve, ground channel) to pin 11 of the op amp.
  8. Connect pin 6 of the op amp to pin 7 of the op amp chip. (This is the feedback loop)
  9. Connect pin 8 of the op amp to pin 9 of the op amp chip. (This is the feedback loop)
  10. Connect pin 1 of the op amp to pin 5 of the op amp.
  11. Connect pin 10 of the op amp to pin 14 of the op amp.

Continue on with at least Option A, which does not require code (but requires the Nucleo for its power source.) You can add Option B which controls many more LEDs and uses the MCU of the Nucleo and includes programming as included in the Software section.

Option A: LEDs driven by the output of the op amp

  1. Place a 100-ohm resistor, 220-ohm resistor, and a 0.1uF capacitor onto the board so that they all share a common node (the positive lead of the capacitor). Replace this 220-ohm resistor with the extra 100-ohm resistor if the LED isn’t bright enough.
  2. Connect the anode of the LEDs to the other end of the 220-ohm resistor.
  3. Connect the cathode of the LED, the negative lead of the capacitor and the free end of the 100-ohm resistor to a common node. Wire this node to ground.
  4. Repeat steps 1 through 3.
  5. Wire the output of op amp pin 7 to the common node shared by the two resistors and positive lead of the capacitor. This will show the intensity of the right channel.
  6. Wire the output of op amp pin 8 to the common node shared by the other two resistors and positive lead of the second capacitor. This will show the intensity of the left channel.
  7. Skip the software section if you do not continue to Option B.

Option B: LEDs driven by the Nucleo

  1. Place six 220-ohm resistors on the breadboard.
  2. Place six LEDs on the board, each one with the anode connected to one end of a 220-ohm resistor. The cathode of all LEDs can share a common ground.
  3. Take the free ends of the first three resistors and attach one to Nucleo pin D2, one to pin D3, and the last one to pin D4.
  4. Take the free ends of the remaining resistors and connect one to Nucleo pin D5, one to pin D6, and the last one to pin D7.
  5. Connect op amp pin 7 (output from the left channel) to Nucleo pin A0.
  6. Connect op amp pin 8 (output from the right channel) to Nucleo pin A1.

Software

When you are ready to integrate the Nucleo into the project, we will need to first program the Nucleo to do what we desire. In this example, we will sample the output of each channel's audio using the onboard analog-to-digital converter. Depending on the intensity of each channel's audio, and in turn the voltage level of the op amp’s output, we will drive 1, 2, or 3 LEDs per channel. So if the audio is very low we will drive 1 LED, and if it is very loud we will drive 3 LEDs.

The program we are running on the Nucleo is pretty straightforward:

  1. Sample the analog value of both the left and right channel and digitize.
  2. Assign the digitized values to a variable so we can use it throughout the current loop iteration.
  3. Look at the digitized value of the channel and determine if its volume is low, medium, or high.
  4. You can tweak the values of the variables that trigger the low, medium, and high LEDs. You can read more in the software section, look for the discussion on lowCutoff, mediumCutoff, and highCutoff. For now, the default logic is as follows:

a. If the channel is sampled to be below 10, then it is nearly perfectly quiet, turn off all the LEDs

b. If the channel is sampled to be between 10 and 1000, then turn on just one LED since the volume is low.

c. If the channel is sampled to be between 1000 and 2000, then turn on two LEDs since the volume is medium.

d. If the channel is sampled to be greater than 2000, then turn on all three LEDs since the volume is high.

The program code for the Nucleo is listed below and can also be found in the Resources section as main.cpp or as a text file named LightSound_NucleoCode.txt:

  1. #include "mbed.h"
  2.  
  3.  
  4.  
  5. AnalogIn leftChannel(A0); // left channel
  6.  
  7. AnalogIn rightChannel(A1); // right channel
  8.  
  9.  
  10.  
  11. DigitalOut leftLED_LOW(D2);
  12.  
  13. DigitalOut leftLED_MED(D3);
  14.  
  15. DigitalOut leftLED_HIGH(D4);
  16.  
  17.  
  18.  
  19. DigitalOut rightLED_LOW(D5);
  20.  
  21. DigitalOut rightLED_MED(D6);
  22.  
  23. DigitalOut rightLED_HIGH(D7);
  24.  
  25.  
  26.  
  27. void setLeftLED_OFF();
  28.  
  29. void setLeftLED_LOW();
  30.  
  31. void setLeftLED_MED();
  32.  
  33. void setLeftLED_HIGH();
  34.  
  35. void setRightLED_OFF();
  36.  
  37. void setRightLED_LOW();
  38.  
  39. void setRightLED_MED();
  40.  
  41. void setRightLED_HIGH();
  42.  
  43. int main() {
  44.  
  45. float leftChannelSignal;
  46.  
  47. float rightChannelSignal;
  48.  
  49. float lowCutoff = 10;
  50.  
  51. float mediumCutoff = 1000;
  52.  
  53. float highCutoff = 2000;
  54.  
  55. printf("nTurn Sound Into Lightn");
  56.  
  57.  
  58.  
  59. while(1) {
  60.  
  61. leftChannelSignal = leftChannel.read(); // Converts and read the analog input value (value from 0.0 to 1.0)
  62.  
  63. rightChannelSignal = rightChannel.read(); // Converts and read the analog input value (value from 0.0 to 1.0)
  64.  
  65. leftChannelSignal = leftChannelSignal * 3300; // Change the value to be in the 0 to 3300 range
  66.  
  67. rightChannelSignal = rightChannelSignal * 3300; // Change the value to be in the 0 to 3300 range
  68.  
  69. printf("L Channel = %.0f mVn", leftChannelSignal);
  70.  
  71. printf("R Channel = %.0f mVn", rightChannelSignal);
  72.  
  73. //LEFT CHANNEL
  74.  
  75. if (leftChannelSignal <= lowCutoff) {
  76.  
  77. setLeftLED_OFF();
  78.  
  79. }
  80.  
  81.  
  82.  
  83. else if (leftChannelSignal > lowCutoff && leftChannelSignal <= mediumCutoff) {
  84.  
  85. setLeftLED_LOW();
  86.  
  87. }
  88.  
  89.  
  90.  
  91. else if (leftChannelSignal > mediumCutoff && leftChannelSignal <= highCutoff) {
  92.  
  93. setLeftLED_MED();
  94.  
  95. }
  96.  
  97.  
  98.  
  99. else {
  100.  
  101. setLeftLED_HIGH();
  102.  
  103. }
  104.  
  105. //RIGHT CHANNEL
  106.  
  107. if (rightChannelSignal <= lowCutoff) {
  108.  
  109. setRightLED_OFF();
  110.  
  111. }
  112.  
  113.  
  114.  
  115. else if (rightChannelSignal > lowCutoff && rightChannelSignal <= mediumCutoff) {
  116.  
  117. setRightLED_LOW();
  118.  
  119. }
  120.  
  121.  
  122.  
  123. else if (rightChannelSignal > mediumCutoff && rightChannelSignal <= highCutoff) {
  124.  
  125. setRightLED_MED();
  126.  
  127. }
  128.  
  129.  
  130.  
  131. else {
  132.  
  133. setRightLED_HIGH();
  134.  
  135. }
  136.  
  137. //wait(0.2); // 200 ms
  138.  
  139. }
  140.  
  141. }
  142.  
  143.  
  144.  
  145. //LEFT CHANNEL
  146.  
  147. void setLeftLED_OFF(){
  148.  
  149. leftLED_LOW = 0;
  150.  
  151. leftLED_MED = 0;
  152.  
  153. leftLED_HIGH = 0;
  154.  
  155. }
  156.  
  157.  
  158.  
  159. void setLeftLED_LOW(){
  160.  
  161. leftLED_LOW = 1;
  162.  
  163. leftLED_MED = 0;
  164.  
  165. leftLED_HIGH = 0;
  166.  
  167. }
  168.  
  169.  
  170.  
  171. void setLeftLED_MED(){
  172.  
  173. leftLED_LOW = 1;
  174.  
  175. leftLED_MED = 1;
  176.  
  177. leftLED_HIGH = 0;
  178.  
  179. }
  180.  
  181.  
  182.  
  183. void setLeftLED_HIGH(){
  184.  
  185. leftLED_LOW = 1;
  186.  
  187. leftLED_MED = 1;
  188.  
  189. leftLED_HIGH = 1;
  190.  
  191. }
  192.  
  193.  
  194.  
  195. //RIGHT CHANNEL
  196.  
  197. void setRightLED_OFF(){
  198.  
  199. rightLED_LOW = 0;
  200.  
  201. rightLED_MED = 0;
  202.  
  203. rightLED_HIGH = 0;
  204.  
  205. }
  206.  
  207.  
  208.  
  209. void setRightLED_LOW(){
  210.  
  211. rightLED_LOW = 1;
  212.  
  213. rightLED_MED = 0;
  214.  
  215. rightLED_HIGH = 0;
  216.  
  217. }
  218.  
  219.  
  220.  
  221. void setRightLED_MED(){
  222.  
  223. rightLED_LOW = 1;
  224.  
  225. rightLED_MED = 1;
  226.  
  227. rightLED_HIGH = 0;
  228.  
  229. }
  230.  
  231.  
  232.  
  233. void setRightLED_HIGH(){
  234.  
  235. rightLED_LOW = 1;
  236.  
  237. rightLED_MED = 1;
  238.  
  239. rightLED_HIGH = 1;
  240.  
  241. }

Good coding practice would dictate that since the left and right channels are performing similar tasks that we could incorporate both into a single functions. However, we kept them separate to help with understanding what’s going on with each channel and so you can create different effects for each channel independently.

Now that we understand what the code is doing, let’s have quick discussion of what is needed to actually get the code onto the Nucleo. To make things as simple as possible to start, you can simply copy the code we’ve provided above and paste into the tool.

Figure 9: The free mbed.org programming tool for the Nucleo. Shown is the Works Space Manager window. (mbed_workspaceManager.png)

First you will need to download the USB driver for the Nucelo-F401RE. Click on Software and then Development Tool Software to find the “part number” for the download package: STSW-LINK009. Or, you can find it by starting from here: https://developer.mbed.org/platforms/ST-Nucleo-F401RE. This site is also good for more information on the Nucleo, including firmware upgrades. You should check for the latest firmware upgrade every time you get a new board as good practice. Full instructions are offered on how to make these downloads if you are using the Nucleo for the first time, or with a new PC.

You can head over to mbed.org and create a free account. The nice thing about the Nucleo is that you can use the programming environment in the browser so it’s always up to date. Once you are logged in you should see the “Compiler” link in the top right of the website, click on that. This will open up your workspace where all your projects will reside. From here follow these steps:

1. In the top left click on “New” and select “New Program”.

2. In the dialog box make sure the following are set:

  1. Platform: “NUCLEO-F401RE”
  2. Template: “Empty program”
  3. Program Name: Whatever you wish. I chose “LightsAndSounds”

3. This will create your default files needed, including “main.cpp”. Double click that file to open the editor.

4. Paste in the code we’ve provided.

5. Click “Save All”

6. Click “Compile”. This will create the necessary .bin file that you will drop onto your STM32 Nucleo. You will be asked where you want to save the file to on your computer. Usually I choose the Desktop.

7. Installing code on the STM32 Nucleo is as simple as dragging the file from wherever you saved it onto the STM32 Nucleo, just as you would click-and-drag any file onto a USB thumb drive.

That’s it. After the .bin file is transferred the Nucleo will automatically reboot and start running your application.

Assembly

There is no additional assembly required! Just hook up your audio source to the audio jack of your circuit. Of course, you could take this project and if you had the resources to teach 3D printing you could have students print an enclosure to house breadboard. But again, it is not required and the circuit will work happily with no enclosure.

I am using a 3.5mm splitter on the output of my phone so that I can send the sound to both the circuit we’ve built and a small speaker so I can hear the music as well as see it. I am using 3.5mm male-to-male extender cable from the splitter into the audio jack. Even if we didn’t use the Nucleo as part of the circuit before, we are going to use it now to provide power to the op amps if nothing else. Insert the USB cable into your computer and the other end into the Nucleo. You should notice the little LEDs on the board begin to glow. Simply attach the Vcc and GND rails of the breadboard to the Vcc and GND pins on the Nucleo. When you are comfortable to move on to interfacing your circuit with the Nucleo, don’t forget to wire the outputs of the op amps into the analog inputs of the Nucleo as discussed previously.

Project in Action

Finally, it’s time to fire up your music app of choice, select your favorite tunes and watch the LEDs begin to rhythmically glow in beat with your music. Depending on how your music file (e.g. MP3, WAV) was created audio may not appear on both channels. That’s okay, you just might not see both LEDs flashing to beat of the music. If the 3.5mm jack is not plugged in you might notice the LEDs glowing, that’s fine! It’s an aspect of line level audio and our circuit.

Schematics, diagrams and documents

Light Sound Schematic

Code

LightSound_NucleoCode

main

Credits

Photo of mbparks

mbparks

Mike Parks is the owner of Green Shoe Garage, a custom electronics design studio and security research lab located in Southern Maryland. He produces content for the Gears of Resistance which shares news and tips for those interested in the maker movement, open-source hardware and software, STEAM education, citizen science, and digital citizenship. He is also an extra class ham radio operator, a licensed Professional Engineer in the state of Maryland, and most notably a dad.

   

Leave your feedback...