First day - spectrum analyzer working

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.

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

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)

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++

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.

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.

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:

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”

Great explanation of the difference - thanks!

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