//*****************************************************
// A/D convert -> 1st Order IIR Filter -> PWM out wave
// 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/04/25
//*****************************************************

#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;

int adData;
int pwmData;
fractional filterOutData;
fractional filterInData;
fractional iirData[2]; // iirData[0]には入力がそのまま入り、iirData[1]は出力の遅延器として働く
fractional iirCoeff[2]; // iirCoeff[0]は入力側の係数、iirCoeff[1]は出力側の係数

void CoeffInit() { // 移動平均フィルタ（10タップ）の係数を代入
// +1.0 -> 32767(0x7FFF), -1.0 -> -32768(0x8000)
// したがって +0.1 -> 3276, +0.9 -> 29490 となる。
	iirCoeff[0] = 3276; // +0.1
	iirCoeff[1] = 29490; // +0.9

// 高域の減衰多め
//	iirCoeff[0] = 983; // +0.03
//	iirCoeff[1] = 31784; // +0.97

// 高域の減衰少なめ
//	iirCoeff[0] = 16384; // +0.5
//	iirCoeff[1] = 16384; // +0.5
}

// Timer subroutine
void __attribute__((__interrupt__, __shadow__, no_auto_psv)) _AltT3Interrupt(void)
{
	// --- A/D is 12bits, filtering is 12bits, then truncate 2bits, PWM is 10bits
	while(!IFS0bits.ADIF);	// wait A/D

	adData = ReadADC12(0);	// A-Dからデータを受け取る。12ビット、符号なし

	filterInData = (adData << 2) - 8192; // 14ビット、符号付きにする

	iirData[0] = filterInData; // iirData[0]には入力データが入る

	// IIRフィルタの出力を計算
	filterOutData = VectorDotProduct(2, iirData, iirCoeff); // データと係数積和演算（DSPライブラリ使用）

	iirData[1] = filterOutData; // iirData[1]には出力データが入る

	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 ADC
	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;

	CoeffInit(); // 1次IIRフィルタの係数を代入

	// main loop
	while(1)
	{
		// A/D result store in ResultData
	}
}
