//*****************************************************
// A/D convert -> Delay&Add -> 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/01/04
//*****************************************************

#include <p30f2012.h>
#include <adc12.h>
#include <timer.h>
#include <outcompare.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
unsigned int ResultData;

int DelayLine[10];
int outdata;
int indata;

void PushDelay(int din) { // 遅延器のプッシュ
	int tmpDelayLine[10];	// ローカル配列の宣言
	VectorCopy(10-1, tmpDelayLine+1, DelayLine); // 配列を一個ずらしてコピー（DSPライブラリ使用）
	tmpDelayLine[0] = din; // 新しいデータを入れる
	VectorCopy(10, DelayLine, tmpDelayLine); // グローバル配列にコピー（DSPライブラリ使用）
}

int CalOutWave() { // 遅延前のデータと遅延後のデータを加算
	int tmp;
	tmp = DelayLine[0] + DelayLine[8];
	return tmp;
}

// 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
	ResultData = ReadADC12(0);	// 12bit resolution (28.8kHz sampling)

	indata = ResultData - 2048;			// 符号付きにする
	PushDelay(indata);				// 遅延器のプッシュ
	outdata = CalOutWave();			// 遅延前のデータと遅延後のデータを加算
	outdata += 2048;				// 符号なしにする
	if(outdata > 4095) outdata = 4095;		// オーバフローリミッタ
	if(outdata < 0) outdata = 0;		// アンダーフローリミッタ
	ResultData = outdata >> 2;			// 10ビットにする

	SetDCOC2PWM(ResultData);
	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, 1843-1);	// 29.48MHz/1843 = 16kHz 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, 1843-1);	// 29.48MHz/1843 = 16kHz carrier PWM
	OpenOC2(OC_IDLE_CON & OC_TIMER2_SRC &
		OC_PWM_FAULT_PIN_DISABLE, 0, 0);

	// enable interrupt
	DISICNT = 0x0000;

	// main loop
	while(1)
	{
		// A/D result store in ResultData
	}
}
