// Digital Potentiometer driver, for MCP41010
// Code for ATtiny13
// by Ian Hooper (C) 2011

// Fuses: leave as standard (~1mhz internal clock)

#include <avr/io.h>
#include <util/delay.h>
#include <avr/wdt.h>

#define CS	(1<<PB2);
#define SCK	(1<<PB1);
#define SI	(1<<PB0);

#define ADC_VREF_TYPE 0x00 //0x40 // this woulda turned on Vref = 1.1V
unsigned short read_adc(unsigned char adc_input)
{
	ADMUX = adc_input | (ADC_VREF_TYPE & 0xff);
	_delay_us(10); // Delay needed for the stabilization of the ADC input voltage
	ADCSRA |= 0x40; // Start the AD conversion
	while ((ADCSRA & 0x10) == 0); // Wait for the AD conversion to complete
	ADCSRA |= 0x10;
	return ADCW;
}


short main(void)
{
	wdt_enable(WDTO_15MS);
	DDRB = 0b00000111; // PB0, PB1 and PB2 all outputs
	ADCSRA=0x84; // ADC initialization

	PORTB |= CS; // Start with CS on
	PORTB &= ~SCK; // and clock off

	while (1)
	{
		wdt_reset(); // Heartbeat for watchdog timer
		
		// Focus HEPAs are 0-3.5V full scale, so about 0-640 counts would be good range
		unsigned short output = read_adc(2);
		if (output > 700) output = 700; // i.e only use 0-3V of scale or so.. optimally 640 but adding 60 for approx zero offset below
		
		//0-640 is full scale but we see 650 ohms at 0 thrott which is 13% of 5000, 13% of 640 is 83, ergo we need to subtract 83 off the above
		if (output > 80)
			output -= 80;
		else
			output = 0;

		output = output*2/10; // scale down to 0-127
		output += 0b00010001 << 8; // Command byte: Write data to Pot0

		// Start write
		PORTB |= SCK; // clock goes high
		_delay_us(20);
		PORTB &= ~CS; // cs goes low to start write
		_delay_us(20);
		unsigned short mask = 0b1000000000000000; // MSB
		for (int n=0; n<16; n++) // 16 bits, 2 bytes: command byte plus data byte
		{
			PORTB &= ~SCK; // clock goes low
			_delay_us(20);
			
			// Prepare pin
			if ((output & mask) > 0) // Bit is on
				PORTB |= SI // SI on
			else
				PORTB &= ~SI;
			
			_delay_us(20);

			PORTB |= SCK; // clock goes high
			_delay_us(20); // stays high for a bit while bit is read by DPOT
			
			mask = mask>>1; // next bit down
		}
		PORTB |= CS; // CS high again to end write

		_delay_ms(1); // why not
	}
}


