FFT LED Spectrum analyzer on PIC32

Thread Starter

stefan646

Joined Dec 16, 2011
28
So i have 4 op amps.
I will use them in this order feeding the next one: 1 for the signal amplifier-1 for the filter-1 for ADC buffer and then to my microcontroller ADC. You recommended to me a 4 op amp IC. The extra one where i should use? I am thinking on a second filter so my anti aliasing filter will be second(2) order right?


No I understand what does it mean ADC buffer but I don't understand what this actually do, and what is his working principle(I am in the second year of electronic faculty and I am very curious) . I tried to read many thing on the internet but I have not found a simple explanation...only how many types they are, they electrical scheme, etc. So if you can make me a brief summary I will remain grateful
 

thatoneguy

Joined Feb 19, 2009
6,359
The op amps aren't strictly needed, but they will help.

The idea is to get the signal to go from Ground to 3.3V, and no higher, during peaks.

You need to amplify the input, so there would be a stage with variable gain, after that, cut off all frequencies above 20kHz since you have the spare op amp. Third, buffer the output of the filter with the third op amp for the Vin of the ADC. The 4th can be unused.

In your code, you will set up the ADC to start running and filling the stack with acqusitions. 20 times per second, take what's on the stack, run the FFT on that data and parse it into "frequency buckets" for display, so you have frequency/amplitude pairs after the FFT, instead of time/volume pairs from the ADC output.

Please read the source code for the completed version that runs up to 10kHz I posted on the last page, it is very well commented.
 

thatoneguy

Joined Feb 19, 2009
6,359
I've attached the source code for the PIC18 10kHz implementation, from This Source Some people were having issues downloading the archive.

This is a great FREE compression/decompression tool for .zip/.rar/.gz/bz2 files called 7-Zip Use this program to unzip the .zip file above.

The heart of the source code- FFT.c and it's header file:

FFT.c
Rich (BB code):
/************************************************************************
    fft.c

    FFT Audio Analysis
    Copyright (C) 2011 Simon Inns

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Email: simon.inns@gmail.com

************************************************************************/

#ifndef FFT_C
#define FFT_C

#include <htc.h>
#include "fft.h"

// fix_fft.c - Fixed-point in-place Fast Fourier Transform

// All data are fixed-point short integers, in which -32768
// to +32768 represent -1.0 to +1.0 respectively. Integer
// arithmetic is used for speed, instead of the more natural
// floating-point.
//
// For the forward FFT (time -> freq), fixed scaling is
// performed to prevent arithmetic overflow, and to map a 0dB
// sine/cosine wave (i.e. amplitude = 32767) to two -6dB freq
// coefficients.
//
// Written by:  Tom Roberts  11/8/89
// Made portable:  Malcolm Slaney 12/15/94 malcolm@interval.com
// Enhanced:  Dimitrios P. Bouras  14 Jun 2006 dbouras@ieee.org
// Ported to PIC18F:  Simon Inns 20110104

/*
  fix_fft() - perform forward fast Fourier transform.
  fr[n],fi[n] are real and imaginary arrays, both INPUT AND
  RESULT (in-place FFT), with 0 <= n < 2**m
*/
void fix_fft(short fr[], short fi[], short m)
{
    long int mr = 0, nn, i, j, l, k, istep, n, shift;
    short qr, qi, tr, ti, wr, wi;

    n = 1 << m;
    nn = n - 1;

    /* max FFT size = N_WAVE */
    //if (n > N_WAVE) return -1;

    /* decimation in time - re-order data */
    for (m=1; m<=nn; ++m)
    {
        l = n;
        do
        {
            l >>= 1;
        } while (mr+l > nn);
        
        mr = (mr & (l-1)) + l;
        if (mr <= m) continue;
        
        tr = fr[m];
        fr[m] = fr[mr];
        fr[mr] = tr;
        ti = fi[m];
        fi[m] = fi[mr];
        fi[mr] = ti;
    }

    l = 1;
    k = LOG2_N_WAVE-1;
    
    while (l < n)
    {
        /*
          fixed scaling, for proper normalization --
          there will be log2(n) passes, so this results
          in an overall factor of 1/n, distributed to
          maximize arithmetic accuracy.

          It may not be obvious, but the shift will be
          performed on each data point exactly once,
          during this pass.
        */
        
        // Variables for multiplication code
        long int c;
        short b;
        
        istep = l << 1;
        for (m=0; m<l; ++m)
        {
            j = m << k;
            /* 0 <= j < N_WAVE/2 */
            wr =  Sinewave[j+N_WAVE/4];
            wi = -Sinewave[j];

            wr >>= 1;
            wi >>= 1;
            
            for (i=m; i<n; i+=istep)
            {
                j = i + l;
                
                // Here I unrolled the multiplications to prevent overhead
                // for procedural calls (we don't need to be clever about 
                // the actual multiplications since the pic has an onboard
                // 8x8 multiplier in the ALU):
                
                // tr = FIX_MPY(wr,fr[j]) - FIX_MPY(wi,fi[j]);
                c = ((long int)wr * (long int)fr[j]);
                c = c >> 14;
                b = c & 0x01;
                tr = (c >> 1) + b;
                
                c = ((long int)wi * (long int)fi[j]);
                c = c >> 14;
                b = c & 0x01;
                tr = tr - ((c >> 1) + b);
                
                // ti = FIX_MPY(wr,fi[j]) + FIX_MPY(wi,fr[j]);
                c = ((long int)wr * (long int)fi[j]);
                c = c >> 14;
                b = c & 0x01;
                ti = (c >> 1) + b;
                
                c = ((long int)wi * (long int)fr[j]);
                c = c >> 14;
                b = c & 0x01;
                ti = ti + ((c >> 1) + b);
                
                qr = fr;
                qi = fi;
                qr >>= 1;
                qi >>= 1;

                fr[j] = qr - tr;
                fi[j] = qi - ti;
                fr = qr + tr;
                fi = qi + ti;
            }
        }
        
        --k;
        l = istep;
    }
}

#endif 
 

Attachments

thatoneguy

Joined Feb 19, 2009
6,359
For FFT.c to make sense, here is the header file for that module.



FFT.h
Rich (BB code):
/************************************************************************
    fft.h

    FFT Audio Analysis
    Copyright (C) 2011 Simon Inns

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Email: simon.inns@gmail.com

************************************************************************/

#ifndef _FFT_H
#define _FFT_H

// Definitions
#define N_WAVE      1024    // full length of Sinewave[]
#define LOG2_N_WAVE 10      // log2(N_WAVE)

// Since we only use 3/4 of N_WAVE, we define only
// this many samples, in order to conserve data space.
const short Sinewave[N_WAVE-N_WAVE/4] = {
      0,    201,    402,    603,    804,   1005,   1206,   1406,
   1607,   1808,   2009,   2209,   2410,   2610,   2811,   3011,
   3211,   3411,   3611,   3811,   4011,   4210,   4409,   4608,
   4807,   5006,   5205,   5403,   5601,   5799,   5997,   6195,
   6392,   6589,   6786,   6982,   7179,   7375,   7571,   7766,
   7961,   8156,   8351,   8545,   8739,   8932,   9126,   9319,
   9511,   9703,   9895,  10087,  10278,  10469,  10659,  10849,
  11038,  11227,  11416,  11604,  11792,  11980,  12166,  12353,
  12539,  12724,  12909,  13094,  13278,  13462,  13645,  13827,
  14009,  14191,  14372,  14552,  14732,  14911,  15090,  15268,
  15446,  15623,  15799,  15975,  16150,  16325,  16499,  16672,
  16845,  17017,  17189,  17360,  17530,  17699,  17868,  18036,
  18204,  18371,  18537,  18702,  18867,  19031,  19194,  19357,
  19519,  19680,  19840,  20000,  20159,  20317,  20474,  20631,
  20787,  20942,  21096,  21249,  21402,  21554,  21705,  21855,
  22004,  22153,  22301,  22448,  22594,  22739,  22883,  23027,
  23169,  23311,  23452,  23592,  23731,  23869,  24006,  24143,
  24278,  24413,  24546,  24679,  24811,  24942,  25072,  25201,
  25329,  25456,  25582,  25707,  25831,  25954,  26077,  26198,
  26318,  26437,  26556,  26673,  26789,  26905,  27019,  27132,
  27244,  27355,  27466,  27575,  27683,  27790,  27896,  28001,
  28105,  28208,  28309,  28410,  28510,  28608,  28706,  28802,
  28897,  28992,  29085,  29177,  29268,  29358,  29446,  29534,
  29621,  29706,  29790,  29873,  29955,  30036,  30116,  30195,
  30272,  30349,  30424,  30498,  30571,  30643,  30713,  30783,
  30851,  30918,  30984,  31049,  31113,  31175,  31236,  31297,
  31356,  31413,  31470,  31525,  31580,  31633,  31684,  31735,
  31785,  31833,  31880,  31926,  31970,  32014,  32056,  32097,
  32137,  32176,  32213,  32249,  32284,  32318,  32350,  32382,
  32412,  32441,  32468,  32495,  32520,  32544,  32567,  32588,
  32609,  32628,  32646,  32662,  32678,  32692,  32705,  32717,
  32727,  32736,  32744,  32751,  32757,  32761,  32764,  32766,
  32767,  32766,  32764,  32761,  32757,  32751,  32744,  32736,
  32727,  32717,  32705,  32692,  32678,  32662,  32646,  32628,
  32609,  32588,  32567,  32544,  32520,  32495,  32468,  32441,
  32412,  32382,  32350,  32318,  32284,  32249,  32213,  32176,
  32137,  32097,  32056,  32014,  31970,  31926,  31880,  31833,
  31785,  31735,  31684,  31633,  31580,  31525,  31470,  31413,
  31356,  31297,  31236,  31175,  31113,  31049,  30984,  30918,
  30851,  30783,  30713,  30643,  30571,  30498,  30424,  30349,
  30272,  30195,  30116,  30036,  29955,  29873,  29790,  29706,
  29621,  29534,  29446,  29358,  29268,  29177,  29085,  28992,
  28897,  28802,  28706,  28608,  28510,  28410,  28309,  28208,
  28105,  28001,  27896,  27790,  27683,  27575,  27466,  27355,
  27244,  27132,  27019,  26905,  26789,  26673,  26556,  26437,
  26318,  26198,  26077,  25954,  25831,  25707,  25582,  25456,
  25329,  25201,  25072,  24942,  24811,  24679,  24546,  24413,
  24278,  24143,  24006,  23869,  23731,  23592,  23452,  23311,
  23169,  23027,  22883,  22739,  22594,  22448,  22301,  22153,
  22004,  21855,  21705,  21554,  21402,  21249,  21096,  20942,
  20787,  20631,  20474,  20317,  20159,  20000,  19840,  19680,
  19519,  19357,  19194,  19031,  18867,  18702,  18537,  18371,
  18204,  18036,  17868,  17699,  17530,  17360,  17189,  17017,
  16845,  16672,  16499,  16325,  16150,  15975,  15799,  15623,
  15446,  15268,  15090,  14911,  14732,  14552,  14372,  14191,
  14009,  13827,  13645,  13462,  13278,  13094,  12909,  12724,
  12539,  12353,  12166,  11980,  11792,  11604,  11416,  11227,
  11038,  10849,  10659,  10469,  10278,  10087,   9895,   9703,
   9511,   9319,   9126,   8932,   8739,   8545,   8351,   8156,
   7961,   7766,   7571,   7375,   7179,   6982,   6786,   6589,
   6392,   6195,   5997,   5799,   5601,   5403,   5205,   5006,
   4807,   4608,   4409,   4210,   4011,   3811,   3611,   3411,
   3211,   3011,   2811,   2610,   2410,   2209,   2009,   1808,
   1607,   1406,   1206,   1005,    804,    603,    402,    201,
      0,   -201,   -402,   -603,   -804,  -1005,  -1206,  -1406,
  -1607,  -1808,  -2009,  -2209,  -2410,  -2610,  -2811,  -3011,
  -3211,  -3411,  -3611,  -3811,  -4011,  -4210,  -4409,  -4608,
  -4807,  -5006,  -5205,  -5403,  -5601,  -5799,  -5997,  -6195,
  -6392,  -6589,  -6786,  -6982,  -7179,  -7375,  -7571,  -7766,
  -7961,  -8156,  -8351,  -8545,  -8739,  -8932,  -9126,  -9319,
  -9511,  -9703,  -9895, -10087, -10278, -10469, -10659, -10849,
 -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353,
 -12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827,
 -14009, -14191, -14372, -14552, -14732, -14911, -15090, -15268,
 -15446, -15623, -15799, -15975, -16150, -16325, -16499, -16672,
 -16845, -17017, -17189, -17360, -17530, -17699, -17868, -18036,
 -18204, -18371, -18537, -18702, -18867, -19031, -19194, -19357,
 -19519, -19680, -19840, -20000, -20159, -20317, -20474, -20631,
 -20787, -20942, -21096, -21249, -21402, -21554, -21705, -21855,
 -22004, -22153, -22301, -22448, -22594, -22739, -22883, -23027,
 -23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143,
 -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201,
 -25329, -25456, -25582, -25707, -25831, -25954, -26077, -26198,
 -26318, -26437, -26556, -26673, -26789, -26905, -27019, -27132,
 -27244, -27355, -27466, -27575, -27683, -27790, -27896, -28001,
 -28105, -28208, -28309, -28410, -28510, -28608, -28706, -28802,
 -28897, -28992, -29085, -29177, -29268, -29358, -29446, -29534,
 -29621, -29706, -29790, -29873, -29955, -30036, -30116, -30195,
 -30272, -30349, -30424, -30498, -30571, -30643, -30713, -30783,
 -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297,
 -31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735,
 -31785, -31833, -31880, -31926, -31970, -32014, -32056, -32097,
 -32137, -32176, -32213, -32249, -32284, -32318, -32350, -32382,
 -32412, -32441, -32468, -32495, -32520, -32544, -32567, -32588,
 -32609, -32628, -32646, -32662, -32678, -32692, -32705, -32717,
 -32727, -32736, -32744, -32751, -32757, -32761, -32764, -32766,
};

// Function prototypes
void fix_fft(short fr[], short fi[], short m);

#endif
 

thatoneguy

Joined Feb 19, 2009
6,359
Also below is main.c, which has the links to the references the author used to write the program.
Main.c, Important due references on how he developed the program, this should get the OP on track.

There are a few more files, hardware.h and graph.c/graph.h, which can be extracted later. The three posts here include one overall concept of how an audio spectrum analyzer can be built. This isn't the ONLY way to do it, but it is the only code I found floating on the net with the GNU license.

THIS CODE WILL NOT COMPILE/WORK ON A 32 BIT PIC WITHOUT A LOT OF MODIFICATION! This is posted to help the OP understand the concepts and what needs to be done.


main.c
Rich (BB code):
/************************************************************************
    main.c

    FFT Audio Analysis
    Copyright (C) 2011 Simon Inns

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Email: simon.inns@gmail.com

************************************************************************/

#ifndef MAIN_C
#define MAIN_C

// Global includes
#include <htc.h>
#include <stdio.h>

// Local includes
#include "hardware.h"
#include "fft.h"
#include "graph.h"

// PIC18F4550/PIC18F2550 fuse configuration:
// Config word 1 (Oscillator configuration)
// 20Mhz crystal input scaled to 48Mhz and configured for USB operation
__CONFIG(1, USBPLL & IESODIS & FCMDIS & HSPLL & CPUDIV1 & PLLDIV5);
// Config word 2
__CONFIG(2, VREGEN & PWRTDIS & BORDIS & BORV20 & WDTDIS & WDTPS32K);
// Config word 3
__CONFIG(3, PBDIGITAL & LPT1DIS & MCLREN);
// Config word 4
__CONFIG(4, XINSTDIS & STVREN & LVPDIS & ICPORTDIS & DEBUGDIS);
// Config word 5, 6 and 7 (protection configuration)
__CONFIG(5, UNPROTECT);
__CONFIG(6, UNPROTECT);
__CONFIG(7, UNPROTECT);

// Globals
short imaginaryNumbers[64];
short realNumbers[64];

void main(void)
{
    // PIC port set up --------------------------------------------------------

    // Configure on-board ADC
    // Vss and Vdd as voltage references
    ADCON1 = 0b00001110;

    // Configure the ADC acquisition time according to the datasheet
    ADCON2 = 0b10110110; // Note: output is right justified

    // Configure ports as inputs (1) or outputs(0)
    //        76543210
    TRISA = 0b00000001;
    TRISB = 0b00000000;
    TRISC = 0b00000011;
    TRISD = 0b00000000;
    TRISE = 0b00000000;

    // Clear all ports
    //        76543210
    PORTA = 0b00000000;
    PORTB = 0b00000000;
    PORTC = 0b00000000;
    PORTD = 0b00000000;
    PORTE = 0b00000000;
    
    RE0 = 0;
    RE1 = 0;
    RE2 = 0;
    
    // Initialise the gLCD
    gLcdInit();
    gLcdClear();

    
    while(1)
    {
        // Perform the FFT

        // Get 64 samples at 50uS intervals
        // 50uS means our sampling rate is 20KHz which gives us
        // Nyquist limit of 10Khz
        short i = 0;
        unsigned short result;
        for (i = 0; i < 64; i++)
        {
            // Perform the ADC conversion
            // Select the desired ADC and start the conversion
            ADCON0 = 0b00000011;     // Start the ADC conversion on AN0
        
            // Wait for the ADC conversion to complete
            TESTPIN_W4 = 1; // Don't remove this... it will affect the sample timing
            while(GODONE);
            TESTPIN_W4 = 0; // Don't remove this... it will affect the sample timing
            
            // Get the 10-bit ADC result and adjust the virtual ground of 2.5V
            // back to 0Vs to make the input wave centered correctly around 0
            // (i.e. -512 to +512)
            realNumbers = ((short)(ADRESH << 8) + (short)ADRESL) - 512;
            
            // Set the imaginary number to zero
            imaginaryNumbers = 0;
            
            // This delay is calibrated using an oscilloscope according to the 
            // output on RA1 to ensure that the sampling periods are correct
            // given the overhead of the rest of the code and the ADC sampling
            // time.
            //
            // If you change anything in this loop or use the professional 
            // (optimised) version of Hi-Tech PICC18, you will need to re-
            // calibrate this to achieve an accurate sampling rate.
            __delay_us(7);
        }

        // Perform the (forward) FFT calculation

        // Note: the FFT result length is half of the input data length
        // so if we put 64 samples in we get 32 buckets out.  The first bucket
        // cannot be used so in reality our result is 31 buckets.
        //
        // The maximum frequency we can measure is half of the sampling rate
        // so if we sample at 20Khz our maximum is 10Khz (this is called the 
        // Nyquist frequency).  So if we have 32 buckets divided over 10Khz,
        // each bucket represents 312.5Khz of range, so our lowest bucket is
        // (bucket 1) 312.5Hz - 625Hz and so on up to our 32nd bucket which
        // is 9687.5Hz - 10,000Hz
        
        //  1 : 312.5 - 625
        //  2 : 625 - 937.5
        //  3 : 937.5 - 1250
        //  4 : 1250 - 1562.5
        //  5 : 1562.5 - 1875
        //  6 : 1875 - 2187.5
        //  7 : 2187.5 - 2500
        //  8 : 2500 - 2812.5
        //  9 : 2812.5 - 3125
        // 10 : 3125 - 3437.5
        // 11 : 3437.5 - 3750
        // 12 : 3750 - 4062.5
        // 13 : 4062.5 - 4375
        // 14 : 4375 - 4687.5
        // 15 : 4687.5 - 5000
        // 16 : 5000 - 5312.5
        // 17 : 5312.5 - 5625
        // 18 : 5625 - 5937.5
        // 19 : 5937.5 - 6250
        // 20 : 6250 - 6562.5
        // 21 : 6562.5 - 6875
        // 22 : 6875 - 7187.5
        // 23 : 7187.5 - 7500
        // 24 : 7500 - 7812.5
        // 25 : 7812.5 - 8125
        // 26 : 8125 - 8437.5
        // 27 : 8437.5 - 8750
        // 28 : 8750 - 9062.5
        // 29 : 9062.5 - 9375
        // 30 : 9375 - 9687.5
        // 31 : 9687.5 - 10000
        
        // Note: the '6' is the size of the input data (2 to the power of 6 = 64)
        TESTPIN_W5 = 1;
        fix_fft(realNumbers, imaginaryNumbers, 6);
        
        // Take the absolute value of the FFT results
        
        // Note: The FFT routine returns 'complex' numbers which consist of
        // both a real and imaginary part.  To find the 'absolute' value
        // of the returned data we have to calculate the complex number's
        // distance from zero which requires a little pythagoras and therefore
        // a square-root calculation too.  Since the PIC has multiplication
        // hardware, only the square-root needs to be optimised.          
        long place, root;
        for (int k=0; k < 32; k++)
        {
            realNumbers[k] = (realNumbers[k] * realNumbers[k] + 
                   imaginaryNumbers[k] * imaginaryNumbers[k]);
                   
            // Now we find the square root of realNumbers[k] using a very
            // fast (but compiler dependent) integer approximation:
            // (adapted from: http://www.codecodex.com/wiki/Calculate_an_integer_square_root)
            place = 0x40000000;
            root = 0;
            
            if (realNumbers[k] >= 0) // Ensure we don't have a negative number
            {
                while (place > realNumbers[k]) place = place >> 2; 
                
                while (place)  
                {  
                    if (realNumbers[k] >= root + place)  
                    {  
                        realNumbers[k] -= root + place;  
                        root += place * 2;  
                    }  
                    root = root >> 1;  
                    place = place >> 2;  
                }
            }
            realNumbers[k] = root;
        }
        TESTPIN_W5 = 0;
        
        // Now we have 32 buckets of audio frequency data represented as
        // linear intensity in realNumbers[]
        //
        // Since the maximum input value (in theory) to the SQRT function is
        // 32767, the peak output at this stage is SQRT(32767) = 181.
        
        // Draw a bar graph of the FFT output data
        TESTPIN_W6 = 1;
        drawFftGraph(realNumbers);
        TESTPIN_W6 = 0;
    }
}

#endif
 

Thread Starter

stefan646

Joined Dec 16, 2011
28
Thatoneguy with all my respect i said before to go to the programing part I must finish the hardware part so I can make experiments and understand better the code. Thank you for the code, I am sure that will help me, but for now I have 2 main dilemmas:

1) what does and how actually works the buffer with op amp

2) my question on post 15: "Another very important thing: My final matrix will be 26X64 LEDs.
My board has 83 I/O ports. 1 port i will use for the analog to digital input, 1-3 for the push-button, 2 ports for an eventualy TV Out(i see that Arduino has a library of that), so i will ramain only with aprox. 75 I/O ports for controlling the matrix. So my question is: what tip of IC i should use for expanding (and how many) : multiplexing, shift register , etc. The best chose will be the one with the simplest code to implement no the one with the most simplicity to build or the chipest."
 

thatoneguy

Joined Feb 19, 2009
6,359
If you haven't worked with hardware at this level before, you should consider purchasing a spectrum analyzer kit instead.

Have you built simple to intermediate circuits in the past? Etched your own circuit boards? If not, I'd STRONGLY suggest a kit, as you'd waste a lot of money not understanding many building steps.

Op amp filters are discussed in many areas on this forum if you do a search. I also have a reference in my blog to good op amp sources.

For the matrix, I'd suggest the MAX6956ANI 28 port LED Driver, it is available in DIP Packaging, and you communicate using your controller's I2C interface, so the entire matrix could conceivably be controlled by 4 of those on a single I2C bus, using 2 pins on your uC.
 

Thread Starter

stefan646

Joined Dec 16, 2011
28
-If you haven't worked with hardware at this level before

-Have you built simple to intermediate circuits in the past?
- Etched your own circuit boards?
Yes....as I said before I am a student on the Electronic Faculty too. I have studied op amps, bun I haven't studied yet(i will study them in second semester) active filters(but not this is the problem because I understand them and I know how to build one), the problem is with that buffer..I don't understand that word, I will probably know if it was spelled in romanian language :)


For the matrix, I'd suggest the MAX6956ANI 28 port LED Driver, it is available in DIP Packaging, and you communicate using your controller's I2C interface, so the entire matrix could conceivably be controlled by 4 of those on a single I2C bus, using 2 pins on your uC.
So you recommend that the IC expander will work with a data pin and a clock signal. Unfortunately in my country I haven't found MAX6956 (max in general).
What about 74HC574?
To have the simplistic code as possible and understanding better how the led matrix it is controlled i was thinking to control independently the 64 columns(the bandpass with 64I/O ports) and only on the 26 rows will use expeders. I am right?
 
Last edited:

BillO

Joined Nov 24, 2008
999
The buffer in this case is just to adjust level between the filter and MCU and possibly, to isolate any loading concerns.
 

thatoneguy

Joined Feb 19, 2009
6,359
2) my question on post 15: "Another very important thing: My final matrix will be 26X64 LEDs.
My board has 83 I/O ports. 1 port i will use for the analog to digital input, 1-3 for the push-button, 2 ports for an eventualy TV Out(i see that Arduino has a library of that), so i will ramain only with aprox. 75 I/O ports for controlling the matrix. So my question is: what tip of IC i should use for expanding (and how many) : multiplexing, shift register , etc. The best chose will be the one with the simplest code to implement no the one with the most simplicity to build or the chipest."
I'd suggest using shift registers for one axis, probably the long axis, then use I/O ports for the short axis, each port will have to drive a transistor to provide current for all the LEDs in the long axis, and each serial driver on the short axis only needs to sink the current of one LED at a time, which eliminates the need for a 2nd transistor to sink (If using a shift register and not the Maxim port expander/driver).

This will use 18 I/O to control the entire matrix, 16 I/O, 1 for each "level/volume" horizontal bar, and 2 I/O to shift in 32 bits of frequencies, only one LED will be lit up at a time, for the first frequency, have the first bit in the shift register, and then sequentially light up each LED in that frequency column up to max level from FFT. Shift to next bit, repeat lighting up each LED. This will be happening at 100kHz+, so it will appear that the LEDs are all continually on.

To try to light up more than one LED at a time opens a can of worms, as the brightness will vary with how many LEDs would be on in each row/column, even if you could light up more than two. Only 2 if using a 5V supply, or 1, if using 3.3V supply (I hope those are green LEDs and not Blue). If using the '595 shift registers. If using the Maxim drivers, the entire column could be lit if you had enough supply voltage.

Does that make sense? After the FFT, you will go through the FFT result matrix as x,y plot points (freq, amplitude), then simply shift those same values out to the matrix, one x,y at a time. Though you may want to "fill" the virtual "bar" under the max frequency, that could be a separate mode. I'm thinking you should get a dot mode working first, where only the peak LED of each column is lit at first.

Once that is going smooth and you have the display routine running at over 100kHz, add functions for filling the area under the peak, as well as the decay rate (how long it takes for a band to go down after a peak), either instant, or delayed with a peak LED dot after a bit of space.

Does this make sense?
 

Thread Starter

stefan646

Joined Dec 16, 2011
28
I'd suggest using shift registers for one axis, probably the long axis, then use I/O ports for the short axis, each port will have to drive a transistor to provide current for all the LEDs in the long axis, and each serial driver on the short axis only needs to sink the current of one LED at a time, which eliminates the need for a 2nd transistor to sink (If using a shift register and not the Maxim port expander/driver).

This will use 18 I/O to control the entire matrix, 16 I/O, 1 for each "level/volume" horizontal bar, and 2 I/O to shift in 32 bits of frequencies, only one LED will be lit up at a time, for the first frequency, have the first bit in the shift register, and then sequentially light up each LED in that frequency column up to max level from FFT. Shift to next bit, repeat lighting up each LED. This will be happening at 100kHz+, so it will appear that the LEDs are all continually on.

To try to light up more than one LED at a time opens a can of worms, as the brightness will vary with how many LEDs would be on in each row/column, even if you could light up more than two. Only 2 if using a 5V supply, or 1, if using 3.3V supply (I hope those are green LEDs and not Blue). If using the '595 shift registers. If using the Maxim drivers, the entire column could be lit if you had enough supply voltage.

Does that make sense? After the FFT, you will go through the FFT result matrix as x,y plot points (freq, amplitude), then simply shift those same values out to the matrix, one x,y at a time. Though you may want to "fill" the virtual "bar" under the max frequency, that could be a separate mode. I'm thinking you should get a dot mode working first, where only the peak LED of each column is lit at first.

Once that is going smooth and you have the display routine running at over 100kHz, add functions for filling the area under the peak, as well as the decay rate (how long it takes for a band to go down after a peak), either instant, or delayed with a peak LED dot after a bit of space.

Does this make sense?
It is a 3,3 V supply and there are blue LEDs. Why blue is not good? :(

After reading this i realize that the MAX IC is really a good deal so I will order this IC from the internet. My goal is to use the board qualities at the maximum, so that involve using as many I/O port I can. My idea is like in the picture. It is a good idea?

On MAX website i found more IC models..what is the difference between MAX 6956 AAI, AAI+,AAI+T,AAX,AAX+,AAX+t, etc. ?
 

Attachments

Last edited:

thatoneguy

Joined Feb 19, 2009
6,359
It is a 3,3 V supply and there are blue LEDs. Why blue is not good? :(

After reading this i realize that the MAX IC is really a good deal so I will order this IC from the internet. My goal is to use the board qualities at the maximum, so that involve using as many I/O port I can. My idea is like in the picture. It is a good idea?

On MAX website i found more IC models..what is the difference between MAX 6956 AAI, AAI+,AAI+T,AAX,AAX+,AAX+t, etc. ?
The letters denote the package (DIP, SOIC, etc) and temperature range it was designed for, info is on page 1 of the datasheet.

Blue LEDs sometimes need 3.4V to turn on, you might want to test several of yours from different bags to see how brightly they turn on at 3.3v (use a 100 Ohm resistor to limit current if it is enough voltage).
 

Thread Starter

stefan646

Joined Dec 16, 2011
28
On their package says: 3V-3.2V maxim...so i am thinking it is all right :D
I tested them at 3 V and their are beautiful :D

So what about my idea on the picture?
 

thatoneguy

Joined Feb 19, 2009
6,359
I'd use the port expanders for the long axis, it's a lot easier to strobe a column of LEDs if they are in the same column, and the data applies to that column (frequency, value).

The other downside is you'll need a transistor on every PIC pin driving LEDs, while with the Maxim, it's built in.

Think about going through the x/y matrix to any one display frequency column. Using the ports for the frequency axis, you'd need to jump around the x/y coordinates to find the LED to light, whereas if you were in the first frequency column, you could quickly strobe all of them in succession without needing to think about it, then go to the next frequency.

We "know" all of the LEDs in a column below the level will be lit, so strobing those LEDs all at the same (well, very quickly one by one) time simply makes more sense than scanning the matrix from left to right and top down (inverting x/y axis)

Also, you want to keep as many uC pins free as you can, so you can add other frills, that board has the power for it, so you could export it to winamp, or even import winamp displays to play on your display over USB. Using all of the ports for digital I/O cuts off a ton of options you may want to add later, even though you don't think you want them now.
 
Last edited:

Thread Starter

stefan646

Joined Dec 16, 2011
28
I'd use the port expanders for the long axis, it's a lot easier to strobe a column of LEDs if they are in the same column, and the data applies to that column (frequency, value).

The other downside is you'll need a transistor on every PIC pin driving LEDs, while with the Maxim, it's built in.

Think about going through the x/y matrix to any one display frequency column. Using the ports for the frequency axis, you'd need to jump around the x/y coordinates to find the LED to light, whereas if you were in the first frequency column, you could quickly strobe all of them in succession without needing to think about it, then go to the next frequency.

We "know" all of the LEDs in a column below the level will be lit, so strobing those LEDs all at the same (well, very quickly one by one) time simply makes more sense than scanning the matrix from left to right and top down (inverting x/y axis)

Also, you want to keep as many uC pins free as you can, so you can add other frills, that board has the power for it, so you could export it to winamp, or even import winamp displays to play on your display over USB. Using all of the ports for digital I/O cuts off a ton of options you may want to add later, even though you don't think you want them now.
I get it :D
So it must look like this?
 

Attachments

thatoneguy

Joined Feb 19, 2009
6,359
I get it :D
So it must look like this?
Yes, something like that. You'll be clocking the LED drivers fast though, when you get to LED displays that are large, it's hard to think that only one is on at a time, but it's how it works, you just need to do it fast enough.
 

thatoneguy

Joined Feb 19, 2009
6,359
You could use a standard 74HC595 or similar shift register. Maxim always comes up with the really nifty stuff, it seems that way for me, anyway.
 
Top