
//ADC to PWM

#include <Mega32.h>
#include <stdio.h> // 

//I like these definitions
#define begin {
#define end   } 
#define int2fix(a)   (((int)(a))<<8)            //Convert char to fix. a is a char
#define float2fix(a) ((int)((a)*256.0)) 
#define fix2int(a)   ((signed char)((a)>>8))    //Convert fix to char. a is an int
#define countNum  4000 // slow down sample rate

//IIR stuff
 #pragma regalloc-
 int alpha, yn_1  ;
 #pragma regalloc+
 
 char newReady ; //ISR communication flag
 unsigned int count ; //state variable to slow down sampling
 
//========================================================   
int OnePoleLow(int xx)
// xx is the current input signal sample
// returns the current filtered output sample
begin
    #asm
    .macro mult_acc         ;r31:r30:r24 += r23:r22 * r21:r20
        muls r23, r21		; (signed)ah * (signed)bh
    	add	r31, r0
    	mul	r22, r20		; al * bl
    	add	r24, r0
    	adc	r30, r1
    	adc	r31, r27
    	mulsu r23, r20		; (signed)ah * bl
    	add	r30, r0
    	adc	r31, r1
    	mulsu	r21, r22	; (signed)bh * al
    	add	r30, r0
    	adc	r31, r1
    .endm 
    
    push r20    ;save parameter regs
    push r21
    
	clr r27             ;permanent zero
    clr r24             ;clear 24 bit result reg; msb to lsb => r31:r30:r24
    
    ld   R30, Y         ;load input parameter xx from stack
	ldd  R31, Y+1       ; and put in result location
	
    lds  R20, _yn_1     ;load y(n-1) from  RAM
	lds  R21, _yn_1+1
	sub  r20, r30       ;form y(n-1) - xx
	sbc  r21, r31       
	lds  R22, _alpha    ;load alpha from RAM
	lds  R23, _alpha+1 
    mult_acc            ; alpha*(yn_1 - xx)) + xx
    
	sts  _yn_1, r30     ;store new output as y(n-1) to  RAM
	sts  _yn_1+1, r31 
	
    pop r21             ;restore parameter regs
	pop r20
	
	#endasm 
	
end

//================================================================= 
interrupt [TIM0_OVF] void sgen(void)
begin
    count--;
    if (count==0)
    begin
        count = countNum ; 
        //read ADC, lowpass, send to PWM
    	OCR0 = fix2int(OnePoleLow(int2fix(ADCH))) ;
    	//start another conversion
     	ADCSR.6=1;  
     	newReady = 1; 
    end	
end 

//=================================================================
void main(void)
begin 
   //PORTB has PWM out
   DDRB=0xff; 
   
   //PORTA is analog input
   DDRA = 0b0 ; //all analog inputs with pullup off.
   PORTA = 0b0;
      
   //turn on pwm with period= 256*8 cycles  = 2048 cycles 
    // or 7812 samples/sec //fast PWM mode,
    TCNT0 = 0; 
    OCR0 = 128; 
    TCCR0 = 0b01101010 ;   
   //turn on timer 0 overflow ISR
   TIMSK = 0b00000001 ;
   
   //init the A to D converter 
   //channel zero/ left adj /EXTERNAL Aref
   //!!!CONNECT Aref jumper!!!!
   ADMUX = 0b00100000;   
   //enable ADC and set prescaler to 1/128*16MHz=125,000
   //and clear interupt enable
   //and start a conversion
   ADCSR = 0b11000111; 
   
   //init the UART
   UCSRB = 0x18;
   UBRRL = 103;
   printf("starting...\n\r");
   
   #asm
   sei
   #endasm
   
   //set IIR filter
   alpha = float2fix(0.875) ;
   //set sample rate
   count = countNum ;
   
   while(1) 
   begin
     if (newReady==1)
     begin
        newReady=0;  
        printf("%f\n\r", (float)OCR0/256.0*5.0) ; 
     end
   end // end while    
   
end  //end main
      

