24
24
25
25
#include "wiring_private.h"
26
26
#include "pins_arduino.h"
27
+ #include "Arduino.h"
27
28
28
29
uint8_t analog_reference = DEFAULT ;
29
30
30
31
void analogReference (uint8_t mode )
31
32
{
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
+ }
36
67
}
37
68
38
69
int analogRead (uint8_t pin )
39
70
{
71
+ if (pin > NUM_ANALOG_INPUTS ) return NOT_A_PIN ;
72
+
40
73
uint8_t low , high ;
41
74
42
75
#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 */
55
77
#endif
56
78
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 ;
73
100
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 ;
93
103
high = 0 ;
94
104
#endif
95
105
96
- // combine the two bytes
106
+ /* Combine two bytes */
97
107
return (high << 8 ) | low ;
98
108
}
99
109
@@ -103,183 +113,63 @@ int analogRead(uint8_t pin)
103
113
// to digital output.
104
114
void analogWrite (uint8_t pin , int val )
105
115
{
116
+
117
+ uint8_t bit_pos = digitalPinToBitPosition (pin );
118
+ if (bit_pos == NOT_A_PIN ) return ;
119
+
106
120
// We need to make sure the PWM output is enabled for those pins
107
121
// that support it, as we turn it off when digitally reading or
108
122
// 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
110
124
// call for the analog output pins.
111
125
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
132
126
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 */
140
128
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 );
148
130
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 */
156
132
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 );
164
134
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 */
172
136
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 );
180
139
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 ;
188
146
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 );
196
149
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 ));
204
152
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
210
153
break ;
211
- #endif
154
+ case TIMERB0 :
155
+ case TIMERB1 :
156
+ case TIMERB2 :
157
+ case TIMERB3 :
212
158
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 ));
239
162
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 ;
267
165
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 );
275
168
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
281
169
break ;
282
- #endif
170
+
171
+ /* If non timer pin, or unknown timer definition. */
172
+ /* do a digital write */
283
173
284
174
case NOT_ON_TIMER :
285
175
default :
@@ -288,7 +178,7 @@ void analogWrite(uint8_t pin, int val)
288
178
} else {
289
179
digitalWrite (pin , HIGH );
290
180
}
181
+ break ;
291
182
}
292
183
}
293
- }
294
-
184
+ }
0 commit comments