/*
 * 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 DAC0 output to ADC0. The DAC output can be changed, by
 * entering values between 0 and 4095. The output is sampled by ADC0,
 * filtered through a low pass and then displayed. DAC and ADC values
 * should not differ significantly.
 */
int
main(void)
{
	/*
	 * Reference voltage
	 *
	 * Setting refcon to 1 activates the internal
	 * reference and connects it to the Vref pin.
	 *
	 * Note: A 0.47uF capacitor is required (from
	 * Vref to GND) for proper operation!
	 */
	Intern_refcon = 1;

	Intern_dac0con = 0x12;			// DAC range 0 to Vref
	Intern_adccon  = 0xa4;			// ADC continuous conversion

	while (1) {
		char line[5];			// input buffer
		unsigned long dac;		// DAC data

		while (!Intern_adcsta) ;	// wait for result ready

		printf("DAC ->ADC: %d\n", lp((Intern_adcdat>>16)&0xfff));

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