//***************************************************
// A/D converter -> 8th order LPF (IIR type) -> PWM output
// 7.37MHz Internal RC oscillator, 16x PLL enabled
// Fcy=7.37MHzx16/4=29.48MHz, Tcy=33.92ns
// Toshio Iwata at DIGITALFILTER.COM all rights reserved
// Last modified on 2008/07/07
//***************************************************

#include <p30f2012.h>
#include <adc12.h>
#include <timer.h>
#include <outcompare.h>
#include <dsp.h>

// configuration
_FWDT(WDT_OFF);
_FGS(CODE_PROT_OFF);
_FOSC(CSW_FSCM_OFF & FRC_PLL16);
_FBORPOR(PBOR_OFF & PWRT_64 & MCLR_EN);

// A/D control register
unsigned int _ADCON1;
unsigned int _ADCON2;
unsigned int _ADCON3;
unsigned int _ADCHS;
unsigned int _ADPCFG;
unsigned int _ADCSSL;

// PWM control register
unsigned int _PTCON;
unsigned int _PWMCON1;
unsigned int _PWMCON2;

// data
int adData;
int pwmData;
fractional filterOutData;
fractional filterInData;

// IIR Filter
#define iirNumSections		4
const fractional iirCoeff[] __attribute__ ((space(auto_psv))) = {
//Generated by DSPLinks
//http://digitalfilter.com/products/dsplinks/jpdsplinks.html
//U_3
//Butterworth LPF
//Sampling Frequency =   28800.0
//cutoff1 =    1500.0
//Order = 8th
//Quantized by 15 [bits]
//**** 1st buquad ****
          409,
          818,
       29196,
         409,
       -14449,
//**** 2nd buquad ****
         369,
         738,
      26325,
         369,
       -11417,
//**** 3rd buquad ****
         343,
         686,
      24482,
         343,
        -9471,
//**** 4rd buquad ****
         330,
         661,
      23589,
         330,
        -8527
};

//fractional iirDelay1[] __attribute__ ((section (".ydata, data, ymemory"), aligned (8)));      
//fractional iirDelay2[] __attribute__ ((section (".ydata, data, ymemory"), aligned (8)));      
fractional __attribute__((space(ymemory), aligned (8))) iirDelay1[4]; // for MPLAB 8.10
fractional __attribute__((space(ymemory), aligned (8))) iirDelay2[4]; // for MPLAB 8.10

IIRTransposedStruct iirFilter;

// Timer subroutine
void __attribute__((__interrupt__, __shadow__)) _AltT3Interrupt(void) {
	// --- A/D converter -> 8th order LPF (IIR type) -> PWM output
	while(!IFS0bits.ADIF);	// wait A/D

	adData = ReadADC12(0);	// A-Dからデータを受け取る。12ビット、符号なし
	filterInData = (adData << 2) - 8192; // 14ビット、符号付きにする

	// IIRフィルタの出力を1個計算する（DSP関数）
	IIRTransposed( 1, &filterOutData, &filterInData, &iirFilter );

	pwmData = (filterOutData >> 4) + 512; // 10ビット、符号なしにする

	if(pwmData > 1024-1) pwmData = 1024-1; // オーバフローリミッタ
	if(pwmData < 0) pwmData = 0; // アンダーフローリミッタ

	if(PORTBbits.RB0 == 0) { // プッシュスイッチ（SW1)が押されたとき
		pwmData = adData >> 2; // スルーで出力（10ビット）
	}
	SetDCOC2PWM(pwmData); // PWMに渡す

	IFS0bits.ADIF = 0;	// clear A/D interuppt flag
	IFS0bits.T3IF = 0;	// clear T3 interuppt flag
}

// Main routine
int main(void)
{

	// port init
	TRISB=0x01FF;
	// Use Alternate Interrupt Vector Table
	INTCON2bits.ALTIVT=1;
	// Confirm to turn off ADC
	ADCON1bits.ADON=0;
	// ADC init
	_ADCHS=	ADC_CH0_POS_SAMPLEA_AN3 &
			ADC_CH0_NEG_SAMPLEA_NVREF;		// A-D channel-3 select
	SetChanADC12(_ADCHS);
	_ADCON1=ADC_MODULE_ON &
			ADC_IDLE_CONTINUE &
			ADC_FORMAT_INTG &
			ADC_CLK_TMR &
			ADC_AUTO_SAMPLING_ON &
			ADC_SAMP_OFF;
	_ADCON2=ADC_VREF_AVDD_AVSS &
			ADC_SCAN_OFF &
			ADC_SAMPLES_PER_INT_1 &
			ADC_ALT_BUF_OFF &
			ADC_ALT_INPUT_OFF;
	// Tad={Tcy(ADCS+1)}/2>334ns, Then ADCS>18.7, Tad=10*Tcy
	_ADCON3=ADC_SAMPLE_TIME_1 &
			ADC_CONV_CLK_SYSTEM &
			ADC_CONV_CLK_10Tcy;
	_ADPCFG=ENABLE_AN3_ANA;	// A-D channel-3 analog input
	_ADCSSL=SCAN_NONE;
	OpenADC12(_ADCON1, _ADCON2, _ADCON3, _ADPCFG, _ADCSSL);

	// Timer3 setting 
	OpenTimer3(T3_ON & T3_GATE_OFF & T3_PS_1_1 & T3_SOURCE_INT, 1024-1);	// 28.8kHz sampling by Iwata
	ConfigIntTimer3(T3_INT_PRIOR_5 & T3_INT_ON);

	// Timer2 setting 
	OpenTimer2(T2_ON & T2_GATE_OFF & T2_PS_1_1 & T2_SOURCE_INT, 1024-1);	// 28.8kHz carrier PWM
	OpenOC2(OC_IDLE_CON & OC_TIMER2_SRC &
		OC_PWM_FAULT_PIN_DISABLE, 0, 0);

	// enable interrupt
	DISICNT = 0x0000;

	iirFilter.numSectionsLess1		= iirNumSections - 1;
	iirFilter.coeffsBase			= (fractional *)iirCoeff;
	iirFilter.coeffsPage			= __builtin_psvpage( iirCoeff );
	iirFilter.delayBase1			= iirDelay1;
	iirFilter.delayBase2			= iirDelay2;
	iirFilter.finalShift			= 0;
	IIRTransposedInit( &iirFilter );

	// main loop
	while(1)
	{
		// A/D result store in ResultData
	}
}
