-
Notifications
You must be signed in to change notification settings - Fork 2
/
adc.c
96 lines (69 loc) · 2.14 KB
/
adc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// ADC handling
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "max261.h"
#include "lookuptable.h"
// setup interrupt timer
void run_adc_timer() {
OCR1AH = 0x13; // 20000000/5000 -> 4KHz timer
OCR1AL = 0x88; // this means every CV / Pot will be read & updated at 1 KHz.
// clear on OCR1A hit, prescaler=1.
TCCR1B |= (1<<WGM12) | (1<<CS10) ;
// enable OCR1A interrupt
TIMSK1 |= (1<<OCIE1A);
}
// setup ADC & trigger first conversion
void setup_adc() {
// enable ADC, prescaler = /64 -> 312.5 KHz ADC clock.
ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) ;
// disable digital IOs on used ADC pins
DIDR0 = 0x0f ;
// v.ref = AREF, left adjust, channel selected=0.
ADMUX |= (1<<ADLAR) | (1<<REFS0) ;
// go conversions!
ADCSRA |= (1<<ADSC) ;
}
// ADC interrupt handler & next-conversion-trigger
ISR(TIMER1_COMPA_vect) {
// ISR indicator
// PORTB |= 0b00000001;
static uint8_t adc_chan = 0 ; // currently selected ADC channel
static uint8_t adc_last_value[4];
uint8_t adc_mask = 0b00000011 ; // mask of bits used for ADC channel selection
// read ADC register(s)
uint8_t adc_in = ADCH ;
uint8_t adc_in_neg = 255-adc_in ;
if ( adc_in != adc_last_value[adc_chan] ) { // only update if input has changed
// PORTB |= 0b00000001;
switch (adc_chan) {
case 0 : // filter A F
max261_write_f(adc_in >> 2, 0);
OCR0A = pgm_read_byte(÷r[adc_in_neg]);
TCCR0B = pgm_read_byte(&prescaler[adc_in_neg]);
break ;
case 1 : // filter A Q
max261_write_q((adc_in_neg >> 1), 0);
break ;
case 2 : // filter B F
max261_write_f(adc_in >> 2, 1);
OCR2A = pgm_read_byte(÷r[adc_in_neg]);
TCCR2B = pgm_read_byte(&prescaler[adc_in_neg]);
break ;
case 3 : // filter B Q
max261_write_q((adc_in_neg >> 1), 1);
break;
}
}
// save adc value for next time...
adc_last_value[adc_chan] = adc_in;
// channel number +1
adc_chan = ((adc_chan+1) & adc_mask ) ;
// update ADMUX register
ADMUX &= 0xf0; // reset channel bits
ADMUX |= adc_chan ;
// start next conversion
ADCSRA |= (1<<ADSC) ;
// turn off ISR indicator
// PORTB &= 0b11111110;
}