Skip to content

Commit 2d5e673

Browse files
committed
import analog stuff
1 parent d94a195 commit 2d5e673

File tree

2 files changed

+101
-236
lines changed

2 files changed

+101
-236
lines changed

cores/arduino/wiring_analog.c

+100-210
Original file line numberDiff line numberDiff line change
@@ -24,76 +24,86 @@
2424

2525
#include "wiring_private.h"
2626
#include "pins_arduino.h"
27+
#include "Arduino.h"
2728

2829
uint8_t analog_reference = DEFAULT;
2930

3031
void analogReference(uint8_t mode)
3132
{
32-
// can't actually set the register here because the default setting
33-
// will connect AVCC and the AREF pin, which would cause a short if
34-
// there's something connected to AREF.
35-
analog_reference = mode;
33+
/* Clear relevant settings */
34+
ADC0.CTRLC &= ~(ADC_REFSEL_gm);
35+
VREF.CTRLA &= ~(VREF_ADC0REFSEL_gm);
36+
37+
/* If reference NOT using internal reference from VREF */
38+
if((mode == EXTERNAL) || (mode == VDD)) {
39+
40+
/* Set reference in ADC peripheral */
41+
ADC0.CTRLC |= mode;
42+
43+
/* If reference using internal reference from VREF */
44+
} else if (
45+
(mode == INTERNAL0V55)
46+
|| (mode == INTERNAL1V1)
47+
|| (mode == INTERNAL2V5)
48+
|| (mode == INTERNAL4V3)
49+
|| (mode == INTERNAL1V5)) {
50+
51+
/* Set ADC reference to INTERNAL */
52+
ADC0.CTRLC |= INTERNAL;
53+
54+
/* Configure VREF ADC0 reference */
55+
VREF.CTRLA |= (mode << VREF_ADC0REFSEL_gp);
56+
57+
/* Non-standard values / default */
58+
} else {
59+
60+
/* Non valid value will set default */
61+
/* Set ADC reference to INTERNAL */
62+
ADC0.CTRLC |= INTERNAL;
63+
64+
/* Configure VREF ADC0 reference */
65+
VREF.CTRLA |= (INTERNAL0V55 << VREF_ADC0REFSEL_gp);
66+
}
3667
}
3768

3869
int analogRead(uint8_t pin)
3970
{
71+
if(pin > NUM_ANALOG_INPUTS) return NOT_A_PIN;
72+
4073
uint8_t low, high;
4174

4275
#if defined(analogPinToChannel)
43-
#if defined(__AVR_ATmega32U4__)
44-
if (pin >= 18) pin -= 18; // allow for channel or pin numbers
45-
#endif
46-
pin = analogPinToChannel(pin);
47-
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
48-
if (pin >= 54) pin -= 54; // allow for channel or pin numbers
49-
#elif defined(__AVR_ATmega32U4__)
50-
if (pin >= 18) pin -= 18; // allow for channel or pin numbers
51-
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
52-
if (pin >= 24) pin -= 24; // allow for channel or pin numbers
53-
#else
54-
if (pin >= 14) pin -= 14; // allow for channel or pin numbers
76+
/* If analog pin number != adc0 channel */
5577
#endif
5678

57-
#if defined(ADCSRB) && defined(MUX5)
58-
// the MUX5 bit of ADCSRB selects whether we're reading from channels
59-
// 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
60-
ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
61-
#endif
62-
63-
// set the analog reference (high two bits of ADMUX) and select the
64-
// channel (low 4 bits). this also sets ADLAR (left-adjust result)
65-
// to 0 (the default).
66-
#if defined(ADMUX)
67-
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
68-
ADMUX = (analog_reference << 4) | (pin & 0x07);
69-
#else
70-
ADMUX = (analog_reference << 6) | (pin & 0x07);
71-
#endif
72-
#endif
79+
#if defined(ADC0)
80+
/* Reference should be already set up */
81+
/* Select channel */
82+
ADC0.MUXPOS = (pin << ADC_MUXPOS_gp);
83+
84+
/* Start conversion */
85+
ADC0.COMMAND = ADC_STCONV_bm;
86+
87+
/* Wait for result ready */
88+
while(!(ADC0.INTFLAGS & ADC_RESRDY_bm));
89+
90+
/* Save state */
91+
uint8_t status = SREG;
92+
cli();
93+
94+
/* Read result */
95+
low = ADC0.RESL;
96+
high = ADC0.RESH;
97+
98+
/* Restore state */
99+
SREG = status;
73100

74-
// without a delay, we seem to read from the wrong channel
75-
//delay(1);
76-
77-
#if defined(ADCSRA) && defined(ADCL)
78-
// start the conversion
79-
sbi(ADCSRA, ADSC);
80-
81-
// ADSC is cleared when the conversion finishes
82-
while (bit_is_set(ADCSRA, ADSC));
83-
84-
// we have to read ADCL first; doing so locks both ADCL
85-
// and ADCH until ADCH is read. reading ADCL second would
86-
// cause the results of each conversion to be discarded,
87-
// as ADCL and ADCH would be locked when it completed.
88-
low = ADCL;
89-
high = ADCH;
90-
#else
91-
// we dont have an ADC, return 0
92-
low = 0;
101+
#else /* No ADC, return 0 */
102+
low = 0;
93103
high = 0;
94104
#endif
95105

96-
// combine the two bytes
106+
/* Combine two bytes */
97107
return (high << 8) | low;
98108
}
99109

@@ -103,183 +113,63 @@ int analogRead(uint8_t pin)
103113
// to digital output.
104114
void analogWrite(uint8_t pin, int val)
105115
{
116+
117+
uint8_t bit_pos = digitalPinToBitPosition(pin);
118+
if(bit_pos == NOT_A_PIN) return;
119+
106120
// We need to make sure the PWM output is enabled for those pins
107121
// that support it, as we turn it off when digitally reading or
108122
// writing with them. Also, make sure the pin is in output mode
109-
// for consistenty with Wiring, which doesn't require a pinMode
123+
// for consistently with Wiring, which doesn't require a pinMode
110124
// call for the analog output pins.
111125
pinMode(pin, OUTPUT);
112-
if (val == 0)
113-
{
114-
digitalWrite(pin, LOW);
115-
}
116-
else if (val == 255)
117-
{
118-
digitalWrite(pin, HIGH);
119-
}
120-
else
121-
{
122-
switch(digitalPinToTimer(pin))
123-
{
124-
// XXX fix needed for atmega8
125-
#if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__)
126-
case TIMER0A:
127-
// connect pwm to pin on timer 0
128-
sbi(TCCR0, COM00);
129-
OCR0 = val; // set pwm duty
130-
break;
131-
#endif
132126

133-
#if defined(TCCR0A) && defined(COM0A1)
134-
case TIMER0A:
135-
// connect pwm to pin on timer 0, channel A
136-
sbi(TCCR0A, COM0A1);
137-
OCR0A = val; // set pwm duty
138-
break;
139-
#endif
127+
if(val < 1){ /* if zero or negative drive digital low */
140128

141-
#if defined(TCCR0A) && defined(COM0B1)
142-
case TIMER0B:
143-
// connect pwm to pin on timer 0, channel B
144-
sbi(TCCR0A, COM0B1);
145-
OCR0B = val; // set pwm duty
146-
break;
147-
#endif
129+
digitalWrite(pin, LOW);
148130

149-
#if defined(TCCR1A) && defined(COM1A1)
150-
case TIMER1A:
151-
// connect pwm to pin on timer 1, channel A
152-
sbi(TCCR1A, COM1A1);
153-
OCR1A = val; // set pwm duty
154-
break;
155-
#endif
131+
} else if(val == 255){ /* if max drive digital high */
156132

157-
#if defined(TCCR1A) && defined(COM1B1)
158-
case TIMER1B:
159-
// connect pwm to pin on timer 1, channel B
160-
sbi(TCCR1A, COM1B1);
161-
OCR1B = val; // set pwm duty
162-
break;
163-
#endif
133+
digitalWrite(pin, HIGH);
164134

165-
#if defined(TCCR1A) && defined(COM1C1)
166-
case TIMER1C:
167-
// connect pwm to pin on timer 1, channel B
168-
sbi(TCCR1A, COM1C1);
169-
OCR1C = val; // set pwm duty
170-
break;
171-
#endif
135+
} else { /* handle pwm to generate analog value */
172136

173-
#if defined(TCCR2) && defined(COM21)
174-
case TIMER2:
175-
// connect pwm to pin on timer 2
176-
sbi(TCCR2, COM21);
177-
OCR2 = val; // set pwm duty
178-
break;
179-
#endif
137+
/* Get timer */
138+
uint8_t digital_pin_timer = digitalPinToTimer(pin);
180139

181-
#if defined(TCCR2A) && defined(COM2A1)
182-
case TIMER2A:
183-
// connect pwm to pin on timer 2, channel A
184-
sbi(TCCR2A, COM2A1);
185-
OCR2A = val; // set pwm duty
186-
break;
187-
#endif
140+
/* Find out Port and Pin to correctly handle port mux, and timer. */
141+
switch (digital_pin_timer)
142+
{
143+
case TIMERA0:
144+
/* Calculate correct compare buffer register */
145+
uint16_t* timer_cmp_out = ((uint16_t*) (&TCA0.SINGLE.CMP0BUF)) + bit_pos;
188146

189-
#if defined(TCCR2A) && defined(COM2B1)
190-
case TIMER2B:
191-
// connect pwm to pin on timer 2, channel B
192-
sbi(TCCR2A, COM2B1);
193-
OCR2B = val; // set pwm duty
194-
break;
195-
#endif
147+
/* Configure duty cycle for correct compare channel */
148+
(*timer_cmp_out) = (val);
196149

197-
#if defined(TCCR3A) && defined(COM3A1)
198-
case TIMER3A:
199-
// connect pwm to pin on timer 3, channel A
200-
sbi(TCCR3A, COM3A1);
201-
OCR3A = val; // set pwm duty
202-
break;
203-
#endif
150+
/* Enable output on pin */
151+
TCA0.SINGLE.CTRLB |= (1 << (TCA_SINGLE_CMP0EN_bp + bit_pos));
204152

205-
#if defined(TCCR3A) && defined(COM3B1)
206-
case TIMER3B:
207-
// connect pwm to pin on timer 3, channel B
208-
sbi(TCCR3A, COM3B1);
209-
OCR3B = val; // set pwm duty
210153
break;
211-
#endif
154+
case TIMERB0:
155+
case TIMERB1:
156+
case TIMERB2:
157+
case TIMERB3:
212158

213-
#if defined(TCCR3A) && defined(COM3C1)
214-
case TIMER3C:
215-
// connect pwm to pin on timer 3, channel C
216-
sbi(TCCR3A, COM3C1);
217-
OCR3C = val; // set pwm duty
218-
break;
219-
#endif
220-
221-
#if defined(TCCR4A)
222-
case TIMER4A:
223-
//connect pwm to pin on timer 4, channel A
224-
sbi(TCCR4A, COM4A1);
225-
#if defined(COM4A0) // only used on 32U4
226-
cbi(TCCR4A, COM4A0);
227-
#endif
228-
OCR4A = val; // set pwm duty
229-
break;
230-
#endif
231-
232-
#if defined(TCCR4A) && defined(COM4B1)
233-
case TIMER4B:
234-
// connect pwm to pin on timer 4, channel B
235-
sbi(TCCR4A, COM4B1);
236-
OCR4B = val; // set pwm duty
237-
break;
238-
#endif
159+
/* Get pointer to timer, TIMERB0 order definition in Arduino.h*/
160+
//assert (((TIMERB0 - TIMERB3) == 2));
161+
TCB_t *timer_B = ((TCB_t *)&TCB0 + (digital_pin_timer - TIMERB0));
239162

240-
#if defined(TCCR4A) && defined(COM4C1)
241-
case TIMER4C:
242-
// connect pwm to pin on timer 4, channel C
243-
sbi(TCCR4A, COM4C1);
244-
OCR4C = val; // set pwm duty
245-
break;
246-
#endif
247-
248-
#if defined(TCCR4C) && defined(COM4D1)
249-
case TIMER4D:
250-
// connect pwm to pin on timer 4, channel D
251-
sbi(TCCR4C, COM4D1);
252-
#if defined(COM4D0) // only used on 32U4
253-
cbi(TCCR4C, COM4D0);
254-
#endif
255-
OCR4D = val; // set pwm duty
256-
break;
257-
#endif
258-
259-
260-
#if defined(TCCR5A) && defined(COM5A1)
261-
case TIMER5A:
262-
// connect pwm to pin on timer 5, channel A
263-
sbi(TCCR5A, COM5A1);
264-
OCR5A = val; // set pwm duty
265-
break;
266-
#endif
163+
/* set duty cycle */
164+
timer_B->CCMPH = val;
267165

268-
#if defined(TCCR5A) && defined(COM5B1)
269-
case TIMER5B:
270-
// connect pwm to pin on timer 5, channel B
271-
sbi(TCCR5A, COM5B1);
272-
OCR5B = val; // set pwm duty
273-
break;
274-
#endif
166+
/* Enable Timer Output */
167+
timer_B->CTRLB |= (TCB_CCMPEN_bm);
275168

276-
#if defined(TCCR5A) && defined(COM5C1)
277-
case TIMER5C:
278-
// connect pwm to pin on timer 5, channel C
279-
sbi(TCCR5A, COM5C1);
280-
OCR5C = val; // set pwm duty
281169
break;
282-
#endif
170+
171+
/* If non timer pin, or unknown timer definition. */
172+
/* do a digital write */
283173

284174
case NOT_ON_TIMER:
285175
default:
@@ -288,7 +178,7 @@ void analogWrite(uint8_t pin, int val)
288178
} else {
289179
digitalWrite(pin, HIGH);
290180
}
181+
break;
291182
}
292183
}
293-
}
294-
184+
}

0 commit comments

Comments
 (0)