/*
 * Copyright(C) Paul und Scherer (mct.de/mct.net)
 *
 * This example demonstrates how to...
 *
 *  ... use an ADC channel to monitor the DAC output.
 *
 *  ... reduce signal noise using low pass filtering.
 */

#include <stdio.h>
#include <conio.h>
#include <target.h>

/*
 * Low pass (numerical simulation of an RC circuit)
 *
 * The behaviour of an RC circuit can be described with the formula
 *
 *  (new)out := (1-K)*out+K*in, with 0<= K <=1, initial out =0
 *
 * In other words, the output is composed of a part of the previous
 * output and a part of the current input. For K =0 the output will
 * never change, and for K =1 it follows the input immediately. The
 * choice for K is a trade-off: signal stability vs. response time.
 *
 * The above formula is rewritten as: (new)out := out-K*out+K*in or
 *
 *  out += K(in-out)
 *
 * To avoid using floats, this is transformed to integer arithmetic
 * by replacing K with 1/F and multiplying both sides with factor F
 *
 *  fout += (in-fout/F), where fout = F*out, F >=1
 *
 * Return out.
 */
#define F	100
static int
lp(int in)
{
	static long fout;			// initial fout (=F*out) =0

	return (fout += in-fout/F)/F;		// return   out (=fout/F)
}

/*
 * Connect the DAC output (=Aout =P0.25) to AD0.0 (=P0.27). The DAC
 * output can be changed by entering values between 0 and 1023. The
 * output is sampled by AD0.0, filtered through a low pass and then
 * displayed. DAC and ADC values should not differ significantly.
 */
int
main(void)
{
	Intern_ad0cr	= 0x210f01;		// enable AD0.0, BURST on
	Intern_pinsel1 |= 0x480000;		//        DAC
						//    and AD0.0 pins
	while (1) {
		char line[5];			// input buffer
		unsigned dac;			// DAC data
		long	 adc;			// ADC data

		while ((adc = Intern_ad0dr) >= 0) ;	// wait for DONE

		printf("DAC ->ADC: %d\n", lp((adc>>6)&0x3ff));

		if (!kbhit()) continue;		// new DAC data?
		do {
			fputs("\nNew DAC data (0.. 1023): ", stdout);
			fgets(line, sizeof(line), stdin);
		} while (sscanf(line, "%u", &dac) != 1 || dac > 1023);
		putchar('\n');
		Intern_dacr = (unsigned short)(dac<<6);
	}
}
