-
Notifications
You must be signed in to change notification settings - Fork 6
/
adc.c
123 lines (104 loc) · 2.89 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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// microbian/adc.c
// Copyright (c) 2021 J. M. Spivey
#include "microbian.h"
#include "hardware.h"
static int ADC;
static void adc_task(int dummy) {
int client, chan;
short result;
message m;
#ifdef UBIT_V1
// Initialise the ADC: 10 bit resolution,
// compare 1/3 of the input with 1/3 of Vdd
ADC_CONFIG = FIELD(ADC_CONFIG_RES, ADC_RES_10bit)
| FIELD(ADC_CONFIG_INPSEL, ADC_INPSEL_AIn_1_3)
| FIELD(ADC_CONFIG_REFSEL, ADC_REFSEL_Vdd_1_3);
ADC_INTEN = BIT(ADC_INT_END);
#endif
#ifdef UBIT_V2
// Initialise the SAADC: 10 bit resolution,
// compare 1/4 if the input with 1/4 of Vdd with
// acquisition window of 10 microsec. (Yes, micro not pico.)
ADC_CHAN[0].CONFIG = FIELD(ADC_CONFIG_GAIN, ADC_GAIN_1_4)
| FIELD(ADC_CONFIG_REFSEL, ADC_REFSEL_VDD_1_4)
| FIELD(ADC_CONFIG_TACQ, ADC_TACQ_10us);
ADC_RESOLUTION = ADC_RESOLUTION_10bit;
ADC_INTEN = BIT(ADC_INT_END) | BIT(ADC_INT_CALDONE);
#endif
connect(ADC_IRQ);
enable_irq(ADC_IRQ);
#ifdef UBIT_V2
// Run a calibration cycle to set zero point
ADC_ENABLE = 1;
ADC_CALIBRATE = 1;
receive(INTERRUPT, NULL);
assert(ADC_CALDONE);
ADC_CALDONE = 0;
clear_pending(ADC_IRQ);
enable_irq(ADC_IRQ);
ADC_ENABLE = 0;
#endif
while (1) {
receive(ANY, &m);
assert(m.type == REQUEST);
client = m.sender;
chan = m.int1;
#ifdef UBIT_V1
SET_FIELD(ADC_CONFIG, ADC_CONFIG_PSEL, BIT(chan));
ADC_ENABLE = 1;
ADC_START = 1;
receive(INTERRUPT, NULL);
assert(ADC_END);
result = ADC_RESULT;
ADC_END = 0;
ADC_ENABLE = 0;
#endif
#ifdef UBIT_V2
ADC_CHAN[0].PSELP = chan+1;
ADC_ENABLE = 1;
ADC_RESULT.PTR = &result;
ADC_RESULT.MAXCNT = 1;
ADC_START = 1;
ADC_SAMPLE = 1;
receive(INTERRUPT, NULL);
assert(ADC_END);
assert(ADC_RESULT.AMOUNT == 1);
ADC_END = 0;
ADC_ENABLE = 0;
// Result can still be slightly negative even after calibration
if (result < 0) result = 0;
#endif
clear_pending(ADC_IRQ);
enable_irq(ADC_IRQ);
send_int(client, REPLY, result);
}
}
/* chantab -- translate pin numbers to ADC channels */
static const int chantab[] = {
#ifdef UBIT_V1
PAD0, 4, PAD1, 3, PAD2, 2, PAD3, 5, PAD4, 6, PAD10, 7,
#endif
#ifdef UBIT_V2
PAD0, 0, PAD1, 1, PAD2, 2, PAD3, 7, PAD4, 4, PAD10, 6,
#endif
0
};
int adc_reading(int pin) {
int i, chan = -1;
message m;
for (i = 0; chantab[i] != 0; i += 2) {
if (chantab[i] == pin) {
chan = chantab[i+1];
break;
}
}
if (chan < 0)
panic("Can't use pin %d for ADC", pin);
m.type = REQUEST;
m.int1 = chan;
sendrec(ADC, &m);
return m.int1;
}
void adc_init(void) {
ADC = start("ADC", adc_task, 0, 256);
}