Main Site Documentation

First day - spectrum analyzer working


#1

Got my panda today and implemented the code needed to read the spectrum analyzer from www.bliptronics.com.

This is obviously my first application, any feedback is welcome :slight_smile:

I had ported this form arduino to netduino … so it was an easy port to FEZ from there.

  • Note: Edited - The original post will be updated with current code (as long as it be edited)
  • Last Update: October 8th.

Overview
This shield is designed to pull 7 bands from music input. It uses an EQ chip designed for car stereos and works great. It has a built in multiplexer … so you can pull all seven bands using two Digital and one or two analog pins (stereo).

The Code

Edited

  • Note I had used a loop and setup routine mapped from the arduino world in the original code, hence the initial comments and suggestion to use Timers.

/* Code to read the Spectrum Analyzer chip from bliptronics.com
 * 
 * http://www.bliptronics.com/item.aspx?ItemID=116
 * 
 * Author: Joseph Francis - based on code from bliptronics and arduino community assistance.
 * 
 * Created: Oct 7, 2010
 * 
 * Version 1.0: Oct 7, 2010 - Initial Version
 * Version 1.1: Oct 8, 2010 - Updated to use timers and provide smoothed values / comments
 * 
 */

using System;
using System.Threading;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware;


namespace FEZPandaBliptronicsAnalyzer
{
    public class Program
    {
        //--- Strobe and Reset are hard wired on the board
        //--- there are jumpers (jp1 - 2 holes) that allow other pins to be used (advanced)
        static OutputPort spStrobe = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di4, false);
        static OutputPort spReset = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di5, false);

        //--- Stereo input means 2 chips and 2 analog reads (combined in this example)
        static AnalogIn spReadL = new AnalogIn((AnalogIn.Pin)FEZ_Pin.AnalogIn.An0);
        static AnalogIn spReadR = new AnalogIn((AnalogIn.Pin)FEZ_Pin.AnalogIn.An1);

        //--- Stores music spectrum values and smoothing variables
        static int[] Spectrum = { 0, 0, 0, 0, 0, 0, 0 };
        const int EQ_SMOOTH_COUNT = 3;
        static int[] SpectrumSmoothTots = {0, 0, 0, 0, 0, 0, 0};
        static int SpectrumSmoothAt = 0;
        static int[][] SpectrumSmoothVals = new int[][] { 
               new int[] { 0, 0, 0, 0, 0, 0, 0 }, 
               new int[] { 0, 0, 0, 0, 0, 0, 0 }, 
               new int[] { 0, 0, 0, 0, 0, 0, 0 } 
               };

        //--- Variable to account for a humm.  
        // * Lower this until you get get output when off - then raise it some.
        const int MUSIC_MIN = 190;

        //--- Used to loop a value back to zero when count is hit (i.e. looping color).  
        // * The count is 1 based but the rest of the usage is zero based
        static int incrToCount(int val, int amt, int count)
        {
            val += amt;

            if (val > count - 1)
                val -= count;

            if (val < 0)
                val += count;

            return val;
        }

        //--- Used to loop a byte - commonly used value for color (256 levels)
        static int increment(int val, int amt)
        {
            return incrToCount(val, amt, 256);
        }

        //--- Toggle the reset pin to activate the spectrum analyzer and reset to bass level (0)
        static public void setupSpecrum()
        {
            spReset.Write(true);
            Thread.Sleep(1);
            spReset.Write(false);
            Thread.Sleep(1);
        }


        //--- This toggles the strobe and reads the band values in a loop of 7 bands
        //--- Also included is smoothing - but use the following line to get the smoothed value
        //   ------>   int SpectrumVal = (SpectrumSmoothTots[i]) / EQ_SMOOTH_COUNT; 
        static public void readSpecrum()
        {
            byte Band;
            for (Band = 0; Band < 7; Band++)
            {
                //--- Trigger strobe to make multiplexer jump
                spStrobe.Write(true);
                spStrobe.Write(false);

                //--- Add the left and right values - then devide by 2
                int cVal = spReadL.Read();
                cVal += spReadR.Read();
                cVal /= 2;

                //--- Allow for a min hum
                if (cVal < MUSIC_MIN)
                {
                    cVal = 0;
                }

                //--- Set related bands (low to high = 0 through 6 for seven bands)
                Spectrum[Band] = cVal;
                int currTot = SpectrumSmoothTots[Band];
                currTot += cVal;
                currTot -= SpectrumSmoothVals[SpectrumSmoothAt][Band];
                SpectrumSmoothVals[SpectrumSmoothAt][Band] = cVal;
                SpectrumSmoothTots[Band] = currTot;
                SpectrumSmoothAt = incrToCount(SpectrumSmoothAt, 1, EQ_SMOOTH_COUNT);

            }
        }


        //--- Debug Routine: Shows the current results - real time
        static public void showResults(Object o)
        {
            string strOut = "";
            Boolean minHit = false;
            for (byte i = 0; i < 7; i++)
            {
                int SpectrumVal = Spectrum[i];
                if (!minHit && SpectrumVal > MUSIC_MIN)
                    minHit = true;

                if (strOut != "")
                    strOut = strOut + " - ";
                strOut = strOut + SpectrumVal.ToString();

            }
            strOut = "Direct Read: " + strOut + "\n";
            if (minHit)
                Debug.Print(strOut);

        }

        //--- Debug Routine: Shows the current results - smoothed
        static public void showSmoothResults(Object o)
        {
            string strOut = "";
            Boolean minHit = false;
            for (byte i = 0; i < 7; i++)
            {
                int SpectrumVal = (SpectrumSmoothTots[i]) / EQ_SMOOTH_COUNT;
                if (!minHit && SpectrumVal > MUSIC_MIN)
                    minHit = true;

                if (strOut != "")
                    strOut = strOut + " - ";
                strOut = strOut + SpectrumVal.ToString();

            }
            strOut = "Smooth: " + strOut + "\n";
            if (minHit)
                Debug.Print(strOut);

        }

        //--- Process that reads the spectrum analyzer in a timer
        static public void readProcess(Object o)
        {
            readSpecrum();
        }

        public static void Main()
        {
            //--- Reset the spectrum analyzer
            setupSpecrum();

            //--- Setup a timer to read the music input, should be quick loop
            Timer readTimer = new Timer(new TimerCallback(readProcess), null, 100, 50);

            //--- Setup another demo timer that simply shows the results
            Timer showTimer = new Timer(new TimerCallback(showResults), null, 1000, 50);
            Timer showTimerSmooth = new Timer(new TimerCallback(showSmoothResults), null, 1000, 50);

            //--- Just stop but do not end the program
            Thread.Sleep(Timeout.Infinite);

        }
    }
 }


When you turn off the music … you get nothing. When you turn on the music … you get this in debug (seven bands from low to high … left to right as you would expect).

,
Direct Read: 473 - 944 - 851 - 955 - 929 - 951 - 715
Smooth: 157 - 314 - 283 - 318 - 309 - 317 - 238
Direct Read: 777 - 1023 - 1023 - 1023 - 927 - 792 - 595
Smooth: 416 - 655 - 624 - 659 - 618 - 581 - 436
Direct Read: 626 - 1023 - 947 - 1023 - 907 - 657 - 500
Smooth: 625 - 996 - 940 - 1000 - 921 - 800 - 603
Direct Read: 696 - 1023 - 846 - 988 - 760 - 552 - 414
Smooth: 699 - 1023 - 938 - 1011 - 864 - 667 - 503
Direct Read: 637 - 1023 - 911 - 933 - 630 - 455 - 348
Smooth: 653 - 1023 - 901 - 981 - 765 - 554 - 420
Direct Read: 590 - 1023 - 1020 - 825 - 526 - 388 - 297
Smooth: 641 - 1023 - 925 - 915 - 638 - 465 - 353
Direct Read: 659 - 957 - 1023 - 771 - 440 - 1023 - 1023
Smooth: 628 - 1001 - 984 - 843 - 532 - 622 - 556
Direct Read: 617 - 932 - 1011 - 641 - 372 - 982 - 996
Smooth: 622 - 970 - 1018 - 745 - 446 - 797 - 772
Direct Read: 548 - 859 - 940 - 559 - 313 - 890 - 840
Smooth: 608 - 916 - 991 - 657 - 375 - 965 - 953
Direct Read: 526 - 890 - 840 - 466 - 305 - 747 - 694
Smooth: 563 - 893 - 930 - 555 - 330 - 873 - 843

  • Edited to show new output from new version.

#2

looks really nice! You might want to get rif of that while (true) loop, though. Use timers instead. Search the ebook.


#3

Thank you - that was just the type of input I was looking for.

Just for practice … I posted this on the projects page.
(link removed)


#4

I can see that this is a Aduino port :slight_smile:


public static void Main()
        {
            setup();
            while (true)
            {
                loop();
            }
        }

Your on the right track my friend and the more you work in the NETMF the less you want to go back to C++


#5

You are defiantly not a newbie, 300 experience points are added :slight_smile:

But like Geir said, you are now freed from the “setup/loop” jail…no need for that anymore. Just move your code in-place.


#6

Thanks so much.

I really just did the loop and setup for nostalgic purposes :slight_smile:

I program in .NET and tons of other programs - but have to say I owe alot to arduino, so my first app had to include an ode.

I will update the code and attempt to provide solid input as I learn this new environment.


#7

I updated the code to use Timers - thanks for the pointer.

In return I added comments (woo hoo!) and a smoothing mechanism *still in code review.
Edit - * Also updated the microframeworkprojects to point to here for code.

Note: I did read the e-book but the note on Timer was after 100 pages and located between graphics details (no graphics caps on Panda) and USB Host (don’t think Panda has that either), So I totally missed it the first time around. So again - thanks for giving guidance.

Also - C# is my weakest languages (even beyond JavaScript) - so any pointers on my C# code would be appreciated.

Question:
Not sure the difference / advantages between using a Timer and making another thread that runs a while (true) loop with a Thread.sleep command. Are there times when one works better than the other? Any advantages in the way of performance / memory use and the like of either one?

  • maybe a new post for this quesiton is in order - but there may be a short answer :slight_smile:

#8

thread.sleep means things can get “slightly” out of time. For instance if one pass of your code takes exceptionally long for some reason (it has a lot of data to process for instance) and then you go to sleep, the period between the execution of the same code isn’t repeatable.

A timer is a hardware way of being more repeatable no matter how long the process takes pass-by-pass. It actually is a more logical way of thinking about a periodic scanning process too, if you think about it. “Every 10 seconds I want to do this”. Not “I want to do this then snooze for 10 seconds”


#9

Great explanation of the difference - thanks!


#10

If a Timer call is not ready, does the next Timer call happen anyway? Or it only happens with the previous call is done?

Thanks, Wk