Low frequency audio level detector using PIC ADC?


Closed Thread
Results 1 to 40 of 69

Hybrid View

  1. #1
    Join Date
    Aug 2010
    Location
    Maryland, USA
    Posts
    869


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    Quote Originally Posted by HankMcSpank View Post
    thanks bert...ok, so taking PR2 = 8 yields an interrupt toggle of 22khz (I took PR2 down to 6, but the interrupt frequency on my scope stayed the same so it looks like I'll have to stick with that?!)
    This doesn't sound to good. lets see if it makes sense: PR2=8 means every time TMR2 counts to 8, an interrupt should fire and TMR2 gets reset. with PR2=66, you had ~30K. So remember the main thats approx 7 clock ticks(clock ticks = instructions, so as not to continue confusing everyone). The math remains the same, for TMR to count to 8 thats 4uSec! 1/.000004 = 250K, not 22K. So my guess is you are going too fast. what was mains frequency? start back at PR2=66 and increase it. see if the INT gets slower, until it is 20K. At PR2=200, I think you were at 15K? so just guessing, maybe a value of ~130?

    Now about that ADC time. I haven't read the errata, but did it say not to run faster then 8mHz or not to run the ADC faster? I ask because I saw something about the speed of the ADC implying there is a prescaler for that so maybe you could run at 32mHz?

    I'm thinking about putting the 'capacitor discharge' emulation into the same interrupt, so something high level like this...

    (I will use a variable called previous_sample to store highest ADC sample)

    1. does present incoming ADC sample equal (or is greater than) previous_sample.

    i)if so previous_sample = present incoming sample .....& retrun

    ii) if not, decrement previous_sample by '1' & return

    with an ADC sample of 8 bits, the maximum signal sample is 255.....the maximum pseudo discharge time will be the interrupt rate (22khz) * 255, therefore about 12ms (which is nicely tied in with the lowest frequency 'cycle' on a guitar @82Hz)....sound about right?
    I don't know much about this, I will have to think on it tonight when I get home from work.
    -Bert

    The glass is not half full or half empty, Its twice as big as needed for the job!

    http://foamcasualty.com/ - Warbird R/C scratch building with foam!

  2. #2
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    thanks bert...slight oversight in my previous (noe edited)...the toggle frequency on my scope is HALF the interrupt frequency!

    Re the pseudo cap - a peak detect cicuit (the end goal here)....it's basically a diode followed by a cap...when the incoming ac signal is higher in magnitude in voltage than that across the cap the diode allows it through...and the cap's voltage increases......when the incoming signal is lower the diode switches off....the cap holds the voltage, but for this circuit to be useful, we actually add in a resistor to discharge it at the designer's choice.....hence wanting to decrement the ADCsample variable when the incoming signal is lower.

    http://hades.mech.northwestern.edu/i...#Peak_Detector

  3. #3
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    ok, despite far too loong trying, i can't get into the interrupt, do my stuff & get out fast enough (for the sample rate I need)....so i'm officially parking the interrupt method of taking ADC samples at a high frequency.

    So back to what languer recommended to me earlier - using the special event trigger to do ADC in background hw.

    this from the data sheet (http://ww1.microchip.com/downloads/e...Doc/41419A.pdf page 216 23.2.4 SPECIAL EVENT TRIGGER )...

    "When Special Event Trigger mode is chosen(CCPxM<3:0> = 1011), the CCPx module does the following:
    • Resets Timer1
    • Starts an ADC conversion if ADC is enabled
    The CCPx module does not assert control of the CCPxpin in this mode.
    The Special Event Trigger output of the CCP occursimmediately upon a match between the TMR1H,TMR1L register pair and the CCPRxH, CCPRxL register pair. The TMR1H, TMR1L register pair is not reset until the next rising edge of the Timer1 clock. The Special
    Event Trigger output starts an A/D conversion (if the A/D module is enabled). This allows the CCPRxH, CCPRxL register pair to effectively provide a 16-bit programmable
    period register for Timer1."


    After an hour of dicking about - I've got it working but would like confirmation how to set the sampling frequency - So I'm back to maths again!

    Ok, with an 8Mhz clock, I now know that we get 2MIPs.....therefore will the Timer1 increment with each instruction clock cycle? so - 1/2,000000? ...that's every 500ns?). If so, to get a sampling frequency of say 40khz, this would mean an ADC sample needed every 25uS, therefore every (25us/500ns) 50 instruction cycles. is it just a matter then of setting CCPR4H = 0 and CCPR4H = 50 for the Timer1H & Timer1L registers to match ???
    Last edited by HankMcSpank; - 22nd February 2011 at 00:52.

  4. #4
    Join Date
    Aug 2010
    Location
    Maryland, USA
    Posts
    869


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    YES, See how easy it is
    -Bert

    The glass is not half full or half empty, Its twice as big as needed for the job!

    http://foamcasualty.com/ - Warbird R/C scratch building with foam!

  5. #5
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    Quote Originally Posted by cncmachineguy View Post
    YES, See how easy it is
    thanks for bearing with me Bert ...it seems to be working a treat - ie Im feeding an AC signal of 5V peak to peak into an analogue pin...and the PIC is extracting the signal's peak level in real time.....just like a hardware peak detector (but better as the 'charge time' is essentially instant, and the 'discharge time' linear & changeable on the fly).

    FWIW, I'm also reversing the ADC reading from the negative half of the incoming AC signal (ie readings below 128) to give a smoother overall reading (essentially full wave rectification in software)

    the special event trigger was absolutely key in getting this to work without using interrupts ....a hearty thanks to languer too :-)
    Last edited by HankMcSpank; - 22nd February 2011 at 19:52.

  6. #6
    Join Date
    Nov 2007
    Location
    Lake Villa Il.
    Posts
    40


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    Hi Hank,
    That is great that you got it to work! Is there a chance that you could post a working version in the code examples section for the rest of us? It is still a little foggy to me.......

    Thank you,
    Sneaky-geek

  7. #7
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    Quote Originally Posted by Sneaky-geek View Post
    Hi Hank,
    That is great that you got it to work! Is there a chance that you could post a working version in the code examples section for the rest of us? It is still a little foggy to me.......

    Thank you,
    Sneaky-geek
    Sure, at the risk of being ridiculed for my elementary coding (I'll always be a n00b!), here you go..

    Code:
    '16F1828 Pin Connections*********************************************
                    ' PIN# NAME  USE & CONNECTION
                    '1   Vdd     +5VDC power supply
    TrisC.3 = 1     '7   RC3     AN7 ADC iN
    TrisB.7 = 0     '10  RB7     HSEROUT pin
                    '20  Vss     Ground
    ''*****************************************************************
    @ __CONFIG _CONFIG1, _FCMEN_OFF & _FOSC_INTOSC & _WDTE_OFF & _MCLRE_OFF & _CP_OFF & _IESO_OFF & _BOREN_OFF & _PWRTE_OFF & _LVP_OFF
    @ __CONFIG _CONFIG2, _LVP_OFF
    
    Osccon = %01110010      'Osc 8Mhz
    
    DEFINE  OSC 8
    DEFINE  NO_CLRWDT 1   ' PBP doesn't clear WDT automatically
    
    ' HW Serial port setup - 115200 @ 8Mhz***********************************
    DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
    DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
    DEFINE HSER_CLROERR 1 ' Clear overflow automatically
    DEFINE HSER_SPBRG 16  ' 115200 Baud @ 8MHz, 2.12%
    SPBRGH = 0
    BAUDCON.3 = 1         ' Enable 16 bit baudrate generator
    '********************************************************************
    
    CM1CON0 = 0   ' COMPARATORS OFF
    CM2CON0 = 0   ' COMPARATORS OFF
    
    ADCON0 = %00011101      'SET AN7 as selected ADC input + ON
    ADCON1 = 0
    
    ANSELA     = 0          ; All Port A ports digital
    ANSELB     = 0          ; All Port B ports digital
    ANSELC     = %00001000  'Analogue pin on RC3 (AN7)
    
    CCP4CON = %0001011     'set CCP4 into special event timer mode
    
    TMR1H = 0       ' set timer1 counter registers to zero            
    TMR1L = 0
    
    CCPR4H = 0       ' preset for timer1 match (MSB register) when timer1 TMR1H & TMR1L match these two regsiters, an ADC sample occurs in hardware
    CCPR4L = 50      ' preset for timer1 match (LSB register)  lower value = higher sampling rate (40Khz here - I think!)
    
    T1CON.0 = 1         ' set timer1 on
    
    count1 var byte
    rolling_peak var BYTE
    present_sample var BYTE
    
    rolling_peak = 0
    present_sample= 0
    count1 = 0
    
    '**********ok that's all the config out the way, let's start***************************************
    
    main:
        count1 = count1 +1                       
        present_sample = ADRESH              'copy the ADC value as taken in the background (by the special event trigger) into a variable
        IF  present_sample < 128 then         'if it's less than 128, then this the waveform has entered the negative part of its cycle.
        present_sample = (127 - present_sample)   'therefore  let's make it positive! (just like a full wave rectifier)
        else 
        present_sample = present_sample -128   ' if it' not in the negative cycle (as checked above), then we're in the positrive part of the cycle, so let's rebase everyting down to 0
        endif
    
        IF present_sample >= rolling_peak THEN 'if the present sample is equal or bigger than the last sample - keep it
        rolling_peak = present_sample
        else                            'if the present sample is not equal or bigger than the last, start decrementing (discharging)
        if count1 =  10 then             ' this count will set the decrement ('discharge') rate (lower is faster)
        rolling_peak = rolling_peak -1   
        count1 = 0
        endif
        endif
        HSEROUT [dec rolling_peak, 13, 10]   'lets make sure everything looks ok on screen
        goto main
    The above sets a 16f1828 up to take ADC samples using the special event trigger ...if using the exact code above, your AC input signal goes in on pin 7 (max 'peak to peak' amplitude being your VCC level - best to amplify your signal for presenting into the pin so that 'max peak to peak' of your incoming signal is as near your VCC voltage as possible - you'll achieve max resolution then) ....your AC signal should be sitting an a DC level of half your PIC's VCC (ie positive cycle go from ADC values of 128->255. negative cycles go from 127->0 - the zero crossing point is an ADC value of about 128)

    I should emphasise that I've not used it in anger yet....there may well be some bugs to flush out - & I'm sure it can be improved (feel free anyone to outline how I can make it slicker anyone!), but it works approx ±1 jitter @7 bits...seems to be reasonably ok upto 20khz...which suggests my sampling frequency in the code is higher than I think it is (btw you lose 1 bit of ADC resolution by flipping the negative cycle up into positive territory...this is a sacrifice worth making as you'll get less 'psuedo ripple' when otherwise the value of the ensuing decrements during the negative cycles would kick in - you can always use 10 bits for your ADC, if so, then you'll lose you one bit, therefore a max 512 values up for grabs) ...

    5V peak to peak @300hz....



    Here's approx 2.5V peak to peak @20khz (a tad more jitter), it should read 64, but I reckon the discrepancy can be accounted for with the DC not being exactly 2.5V that the AC signal sits on (&/or my Chinese USB scope might not be that accurate!)



    One last point - despite the thread title, this detects 'peak' not RMS (& peak is what I need in the end...if you need RMS multiply the result by .707 ....or rather use a workaround for the lack of floating point)
    Last edited by HankMcSpank; - 23rd February 2011 at 01:23.

Members who have read this thread : 0

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts