1/*
2  wiring_analog.c - analog input and output
3  Part of Arduino - http://www.arduino.cc/
4
5  Copyright (c) 2005-2006 David A. Mellis
6
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public
9  License as published by the Free Software Foundation; either
10  version 2.1 of the License, or (at your option) any later version.
11
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  Lesser General Public License for more details.
16
17  You should have received a copy of the GNU Lesser General
18  Public License along with this library; if not, write to the
19  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20  Boston, MA  02111-1307  USA
21
22  Modified 28 September 2010 by Mark Sproul
23
24  $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
25*/
26
27#include "wiring_private.h"
28#include "pins_arduino.h"
29
30uint8_t analog_reference = DEFAULT;
31
32void analogReference(uint8_t mode)
33{
34	// can't actually set the register here because the default setting
35	// will connect AVCC and the AREF pin, which would cause a short if
36	// there's something connected to AREF.
37	analog_reference = mode;
38}
39
40int analogRead(uint8_t pin)
41{
42	uint8_t low, high;
43
44#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
45	if (pin >= 54) pin -= 54; // allow for channel or pin numbers
46#else
47	if (pin >= 14) pin -= 14; // allow for channel or pin numbers
48#endif
49
50#if defined(ADCSRB) && defined(MUX5)
51	// the MUX5 bit of ADCSRB selects whether we're reading from channels
52	// 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
53	ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
54#endif
55
56	// set the analog reference (high two bits of ADMUX) and select the
57	// channel (low 4 bits).  this also sets ADLAR (left-adjust result)
58	// to 0 (the default).
59#if defined(ADMUX)
60	ADMUX = (analog_reference << 6) | (pin & 0x07);
61#endif
62
63	// without a delay, we seem to read from the wrong channel
64	//delay(1);
65
66#if defined(ADCSRA) && defined(ADCL)
67	// start the conversion
68	sbi(ADCSRA, ADSC);
69
70	// ADSC is cleared when the conversion finishes
71	while (bit_is_set(ADCSRA, ADSC));
72
73	// we have to read ADCL first; doing so locks both ADCL
74	// and ADCH until ADCH is read.  reading ADCL second would
75	// cause the results of each conversion to be discarded,
76	// as ADCL and ADCH would be locked when it completed.
77	low  = ADCL;
78	high = ADCH;
79#else
80	// we dont have an ADC, return 0
81	low  = 0;
82	high = 0;
83#endif
84
85	// combine the two bytes
86	return (high << 8) | low;
87}
88
89// Right now, PWM output only works on the pins with
90// hardware support.  These are defined in the appropriate
91// pins_*.c file.  For the rest of the pins, we default
92// to digital output.
93void analogWrite(uint8_t pin, int val)
94{
95	// We need to make sure the PWM output is enabled for those pins
96	// that support it, as we turn it off when digitally reading or
97	// writing with them.  Also, make sure the pin is in output mode
98	// for consistenty with Wiring, which doesn't require a pinMode
99	// call for the analog output pins.
100	pinMode(pin, OUTPUT);
101	if (val == 0)
102	{
103		digitalWrite(pin, LOW);
104	}
105	else if (val == 255)
106	{
107		digitalWrite(pin, HIGH);
108	}
109	else
110	{
111		switch(digitalPinToTimer(pin))
112		{
113			// XXX fix needed for atmega8
114			#if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__)
115			case TIMER0A:
116				// connect pwm to pin on timer 0
117				sbi(TCCR0, COM00);
118				OCR0 = val; // set pwm duty
119				break;
120			#endif
121
122			#if defined(TCCR0A) && defined(COM0A1)
123			case TIMER0A:
124				// connect pwm to pin on timer 0, channel A
125				sbi(TCCR0A, COM0A1);
126				OCR0A = val; // set pwm duty
127				break;
128			#endif
129
130			#if defined(TCCR0A) && defined(COM0B1)
131			case TIMER0B:
132				// connect pwm to pin on timer 0, channel B
133				sbi(TCCR0A, COM0B1);
134				OCR0B = val; // set pwm duty
135				break;
136			#endif
137
138			#if defined(TCCR1A) && defined(COM1A1)
139			case TIMER1A:
140				// connect pwm to pin on timer 1, channel A
141				sbi(TCCR1A, COM1A1);
142				OCR1A = val; // set pwm duty
143				break;
144			#endif
145
146			#if defined(TCCR1A) && defined(COM1B1)
147			case TIMER1B:
148				// connect pwm to pin on timer 1, channel B
149				sbi(TCCR1A, COM1B1);
150				OCR1B = val; // set pwm duty
151				break;
152			#endif
153
154			#if defined(TCCR2) && defined(COM21)
155			case TIMER2:
156				// connect pwm to pin on timer 2
157				sbi(TCCR2, COM21);
158				OCR2 = val; // set pwm duty
159				break;
160			#endif
161
162			#if defined(TCCR2A) && defined(COM2A1)
163			case TIMER2A:
164				// connect pwm to pin on timer 2, channel A
165				sbi(TCCR2A, COM2A1);
166				OCR2A = val; // set pwm duty
167				break;
168			#endif
169
170			#if defined(TCCR2A) && defined(COM2B1)
171			case TIMER2B:
172				// connect pwm to pin on timer 2, channel B
173				sbi(TCCR2A, COM2B1);
174				OCR2B = val; // set pwm duty
175				break;
176			#endif
177
178			#if defined(TCCR3A) && defined(COM3A1)
179			case TIMER3A:
180				// connect pwm to pin on timer 3, channel A
181				sbi(TCCR3A, COM3A1);
182				OCR3A = val; // set pwm duty
183				break;
184			#endif
185
186			#if defined(TCCR3A) && defined(COM3B1)
187			case TIMER3B:
188				// connect pwm to pin on timer 3, channel B
189				sbi(TCCR3A, COM3B1);
190				OCR3B = val; // set pwm duty
191				break;
192			#endif
193
194			#if defined(TCCR3A) && defined(COM3C1)
195			case TIMER3C:
196				// connect pwm to pin on timer 3, channel C
197				sbi(TCCR3A, COM3C1);
198				OCR3C = val; // set pwm duty
199				break;
200			#endif
201
202			#if defined(TCCR4A) && defined(COM4A1)
203			case TIMER4A:
204				// connect pwm to pin on timer 4, channel A
205				sbi(TCCR4A, COM4A1);
206				OCR4A = val; // set pwm duty
207				break;
208			#endif
209
210			#if defined(TCCR4A) && defined(COM4B1)
211			case TIMER4B:
212				// connect pwm to pin on timer 4, channel B
213				sbi(TCCR4A, COM4B1);
214				OCR4B = val; // set pwm duty
215				break;
216			#endif
217
218			#if defined(TCCR4A) && defined(COM4C1)
219			case TIMER4C:
220				// connect pwm to pin on timer 4, channel C
221				sbi(TCCR4A, COM4C1);
222				OCR4C = val; // set pwm duty
223				break;
224			#endif
225
226			#if defined(TCCR5A) && defined(COM5A1)
227			case TIMER5A:
228				// connect pwm to pin on timer 5, channel A
229				sbi(TCCR5A, COM5A1);
230				OCR5A = val; // set pwm duty
231				break;
232			#endif
233
234			#if defined(TCCR5A) && defined(COM5B1)
235			case TIMER5B:
236				// connect pwm to pin on timer 5, channel B
237				sbi(TCCR5A, COM5B1);
238				OCR5B = val; // set pwm duty
239				break;
240			#endif
241
242			#if defined(TCCR5A) && defined(COM5C1)
243			case TIMER5C:
244				// connect pwm to pin on timer 5, channel C
245				sbi(TCCR5A, COM5C1);
246				OCR5C = val; // set pwm duty
247				break;
248			#endif
249
250			case NOT_ON_TIMER:
251			default:
252				if (val < 128) {
253					digitalWrite(pin, LOW);
254				} else {
255					digitalWrite(pin, HIGH);
256				}
257		}
258	}
259}
260