;========================================================================================== ; 12F683 AGC System ; ; (c) Cumbria Designs ; ; CONDITIONS OF USE ; This software is provided free of charge for non commercial use. The software is provided ; without warranty or licence and no liability is accepted by the author or Cumbria Designs ; for any loss, injury, mishap, inconvenience or misdemeanor arising from the use of the ; software in whole or part. In using this software and the code compiled from it, you agree ; to these terms. ; ; We ask that in return for downloading and/or using this software or any part therof, in any way, ; that you make a donation to a deserving charity of your choice. How much is up to you. ; ; Ron Taylor, Cumbria Designs ; ; ; This program implements an audio AGC system in a 8 pin PIC. The AGC voltage is produced as a PWM ; waveform which after low pass filtering, becomes a 0V to 5V DC level for driving the AGC line. ; ;========================================================================================== ; ; Revision History ; ; July 2010 Version 1.0 ; Simple version for proof of concept, fast decay rate and fixed output inversion ; ; 2 Fast/Slow and positive negative AGC controls added. Attack rate gradient set by signal ; amplitude. ; 3 Re-work of attack routine to reduce overshoot. Simple increment process now used. ; ; 4 Fixed count introduced into decay branch. This extends the decay times to provide ; a more useful slow decay range. ; ;========================================================================================== ; ; Pin Out ; ; Device ; 1 GND ; 2 GP5 ; 3 GP4 Audio Input ; 4 GP3 ; 5 GP2 PWM AGC Voltage Output ; 6 GP1 ; 7 GP0 Fast/Slow AGC Recovery ; 8 +5V ; ; ;========================================================================================== list p=12F683 ; list directive to define processor #include ; processor specific variable definitions errorlevel -302 ;========================================================================== ; ; Configuration Bits ; ;========================================================================== _FCMEN_ON EQU H'3FFF' _FCMEN_OFF EQU H'37FF' _IESO_ON EQU H'3FFF' _IESO_OFF EQU H'3BFF' _BOD_ON EQU H'3FFF' _BOD_NSLEEP EQU H'3EFF' _BOD_SBODEN EQU H'3DFF' _BOD_OFF EQU H'3CFF' _CPD_ON EQU H'3F7F' _CPD_OFF EQU H'3FFF' _CP_ON EQU H'3FBF' _CP_OFF EQU H'3FFF' _MCLRE_ON EQU H'3FFF' _MCLRE_OFF EQU H'3FDF' _PWRTE_OFF EQU H'3FFF' _PWRTE_ON EQU H'3FEF' _WDT_ON EQU H'3FFF' _WDT_OFF EQU H'3FF7' _LP_OSC EQU H'3FF8' _XT_OSC EQU H'3FF9' _HS_OSC EQU H'3FFA' _EC_OSC EQU H'3FFB' _INTRC_OSC_NOCLKOUT EQU H'3FFC' _INTOSCIO EQU H'3FFC' _INTRC_OSC_CLKOUT EQU H'3FFD' _INTOSC EQU H'3FFD' _EXTRC_OSC_NOCLKOUT EQU H'3FFE' _EXTRCIO EQU H'3FFE' _EXTRC_OSC_CLKOUT EQU H'3FFF' _EXTRC EQU H'3FFF' __config(_INTOSCIO & _WDT_OFF & _BOD_OFF & _MCLRE_OFF) ;========================================================================================== ; ; File Register Definitions ; ;========================================================================================== CBLOCK 0x20 ; Start of Program Variables Memory AGC_word ; Digital "AGC Voltage" AGC_volt ; AGC word with DC bias PWM_word ; PWM Duty Cycle control_flags ; Flag word for controlling AGC operation control_last ; Historic control states decay_slope ; Fixed value that sets fastest decay rate, fast/slow are multiples of this decay_rate ; Store for selected AGC decay speed count value decay_gradient ; Decay rate counter attack_rate ; Store for AGC attack rate (passes/increment) attack_gradient ; Attack rate counter AF_threshold ; Peak audio in 5mV steps above which AGC action invoked sample ; Current difference between ADC sample and threshold last_sample ; Last difference between ADC sample and threshold temp ; Used in determining AGC step size ENDC CBLOCK 0X70 ; Context Save Area temp_w temp_status ENDC ; Control Input Pin Addresses ; #DEFINE POLARITY GPIO,1 ; Set AGC Direction, high = negative going, low = positive going #DEFINE SPEED GPIO,0 ; Set AGC recovery speed, high = fast AGC, low = slow AGC ; Hardcoded Values Adjust to suit your application and preferences ; ; THRESHOLD A/D peak input voltage above which AGC attack is applied. The value represents ; increments of approximately 5mV (5/1023V) ; ; DECAY_STEP Fixed period between decay rate decrements. This "stretches" the decay range ; set by the Fast/Slow rates to provide a useful control range. A value of 10 is ; used such that on every 10th ISR pass the decay gradient counter is decremented. ; ; DECAY FAST/SLOW AGC Decay Rates, time/volt = 128uSec*k*N*256/V where V is the AGC voltage range ; and k is the Decay Step, for V=10 and k=10 Decay Rate = N*33mSec/Volt. ; ; ATTACK AGC Attack Rate, time/volt = 128uSec*N*255/V where V is the AGC voltage range ; for V=10 and N=0x10 Decay Rate = 52mSec/Volt ; ; DC BIAS No signal AGC standing bias. Set this to suit the gain reduction threshold ; voltage of your IF amplifier. Value sets the minimum PWM duty cycle as ; 255*Vbias/G*5. Where Vbias is the required standing voltage and G is the ; voltage gain of the AGC amplifier. For example, x2 AGC amplififer and Vbias of ; 4V, DC BIAS = 255*4/2*5 = 1020/10 = 102 (0x66 hex). Note with AGC inversion ; applied this will be 10-4 = 6V. ; ; AGC_MAX Maximum full signal limit of AGC Voltage. This helps to reduce overshoot. As with ; DC BIAS this is a PWM duty cycle function calculated as AGC MAX= 255*Vmax/G*5 ; where Vmax is the maximum AGC voltage in volts and G is the AGC amplifier voltage ; gain. For example, x2 AGC amplifier and Vmax of 8V, ; AGC MAX = 255*8/2*5 = 2040/10 = 204 (0xCC hex). Note with AGC inversion ; applied this will be 10-8 = 2V. ; #DEFINE THRESHOLD 0x0A ; Detection Threshold in 5mV steps #DEFINE ATTACK 0X01 ; Attack rate, 1= increment every pass, 2 = every second pass etc #DEFINE DECAY_FAST 0x09 ; Fast AGC Decay, ISR passes*DECAY_SLOPE/decay decrement #DEFINE DECAY_SLOW 0x33 ; Slow AGC Decay, ISR passes*DECAY_SLOPE/decay decrement #DEFINE DECAY_STEP 0x0A ; Fixed duration for each decrement of the decay rate. #DEFINE DC_BIAS 0x66 ; No signal AGC bias #DEFINE AGC_MAX 0xCC ; Limit of AGC to prevent overshoot ; ;========================================================================================== ; ; MACRO AREA ; ;========================================================================================== Bank0 MACRO bcf STATUS,RP0 ENDM Bank1 MACRO bsf STATUS,RP0 ENDM ; Routines for saving and restoring working register data during ISR ; All associated temp registers must be defined in common user RAM 0x70 - 0x7F PUSH MACRO ; Save working register contents on entry to ISR movwf temp_w ; Save w swapf STATUS,w ; Save STATUS without affecting flags bcf STATUS,RP0 ; Point to Bank 0 movwf temp_status ENDM POP MACRO ; Restore working register contents on exit from ISR swapf temp_status,w ; Restore STATUS without affecting flags movwf STATUS swapf temp_w,f ; Restore w without affecting STATUS swapf temp_w,w ENDM ;================================================================================================ ; ; Reset Vector ; ;================================================================================================ ORG 0x0000 goto Start ;================================================================================================ ; ; Interrupt Service Routine ; ; The ISR is the heart of the program. All AGC functions are controlled from here. ; ; 1. Sample the audio input. ; 2. Determine amplitude (difference from centre rail). ; 3. Compare to previous sample to determine peak value. ; 4. Increment AGC word by attack step or decrement by decay step. ; 5. Apply AGC word to PWM module to produce new duty cycle. ; ; ; Timings for 8MHz Internal Clock ; ; The ISR is triggered by TMR0 overflow flag and is used to scan the controls for change. The rate ; is not critical but a relatively high speed is desirable for fast attack rate. ; ; Internal clock = 8/4 = 2MHz, t=0.5uSec ; ; TMR0 = 256 ISR rate= 0.5E-6*256 = 128uSec ; ;================================================================================================ ORG 0x0004 ; ISR PUSH bcf INTCON, T0IF ; Clear interrupt flag movlw 0x7F ; Re-load start count for 64uSec ISR rate movwf TMR0 ; ; In this application the active A/D range is 256 to 767, i.e. 255 either side of the centre zero ; bias point. The 10 bit right justified result gives a resolution of about 5mV per A/D step giving ; an input voltage range of +/- 1.275V either side of centre (2.5Vpp). A diode limiter in the AF ; pre-amp prevents the applied AF signal from exceeding this range. The result is takne from ADRESL ; which at 8 bits describes the amplitude. the polarity is determined from the higher order ADRESH ; result which will be 01 for the negative range and 10 for the positive range. Sample bsf ADCON0,1 ; Start A to D conversion btfsc ADCON0,1 ; Has it completed goto $-1 ; No, check again ; The A/D result is right justified. The 8 bit amplitude in in ADRESL and the polarity ; bit is in ADRESH. The negative going result needs to be inverted to produce a positive ; value amplitude. The A/D input is held centre rail by a resistive divider, therefore ; ADRESH bit 1 determines whether the result is greater or less than 2.5V. ; ; bits ; 0..7 ADRESL A/F amplitude ; 8 ADRESH,0 Higher order quadrant bits ; 9 ADRESH,1 (see below) ; ; ADRESH ; bit 1 0 ; 0 0 Exceeded negative boundary ; 0 1 Negative ; 1 0 Positive ; 1 1 Exceeded positive bounary ; ; ; Boundary Tests ; ; Diode limiting should keep us with the positive and negative bands but just ; in case, limit checks will apply attack. For development use only, not ; required under normal operation with diode input limiting. ; movf ADRESH,f ; Test for zero ; btfsc STATUS,Z ; goto Attack ; Exceeded A/D range lower limit (00) ; movlw 0x11 ; xorwf ADRESH,w ; btfsc STATUS,Z ; goto Attack ; Exceeded A/D range upper limit (11) ;Result in range btfss ADRESH,1 ; Are we positive or negative? goto negative_half_cycle ; positive_half_cycle ; For the +ve half cycle the amplitude is given by the Bank1 ; ADRESL value movf ADRESL,w Bank0 goto Threshold_detection negative_half_cycle ; For the -ve half cycle the amplitude is given by the Bank1 ; complement of the ADRESL value comf ADRESL,w;f ; Invert, increment and save result to w ; incf ADRESL,w ; (not reuqired) Bank0 Threshold_detection sublw THRESHOLD ; Is new sample value greater than the threshold value? btfsc STATUS,C ; If negative C=0, sample>threshold goto Decay ; samplethreshold, apply attack movwf sample ; Save amplitude above threshold decfsz attack_gradient,f ; Decrement the attack rate counter on every pass goto ISR_exit ; Gradient counter not at zero, liesurely exit movlw ATTACK ; Re-load attack counter movwf attack_gradient movf last_sample,w ; subwf sample,w ; Is new sample greater than last? btfss STATUS,C ; Is result positive? (C=1) goto ISR_exit ; No, update last_sample and exit btfsc STATUS,Z ; Was result zero? (sample=last_sample) goto ISR_exit ; Yes, exit incf AGC_word,f ; Ramp up the AGC voltage movlw AGC_MAX ; Test to see if AGC is at maximum subwf AGC_word,w ; btfsc STATUS,C goto AGC_max ; Yes, we are at maximum goto ISR_exit ; No, update sample and exit Decay ; Sample and CCP1CON<5,4> END