| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#include "EXTERN.h" |
|
2
|
|
|
|
|
|
|
#include "perl.h" |
|
3
|
|
|
|
|
|
|
#include "XSUB.h" |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
#include |
|
6
|
|
|
|
|
|
|
#include |
|
7
|
|
|
|
|
|
|
#include |
|
8
|
|
|
|
|
|
|
#include |
|
9
|
|
|
|
|
|
|
#include |
|
10
|
|
|
|
|
|
|
#include |
|
11
|
|
|
|
|
|
|
#include |
|
12
|
|
|
|
|
|
|
#include |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
// ADC full-scale positive code: 16-bit (ADS111x), and the 12-bit (ADS101x) |
|
15
|
|
|
|
|
|
|
// value after fetch() right-shifts the reading into 12 bits. |
|
16
|
|
|
|
|
|
|
#define ADS_FS_16 32767.0 |
|
17
|
|
|
|
|
|
|
#define ADS_FS_12 2048.0 |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
// Reference for percent(): the input as a percentage of the Pi's 3.3V GPIO |
|
20
|
|
|
|
|
|
|
// range, so a gain-1 reading of 3.3V is 100% (the historical scale). |
|
21
|
|
|
|
|
|
|
#define ADS_VREF 3.3 |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
// Per-conversion i2c retry cap. The Pi bus intermittently throws transient |
|
24
|
|
|
|
|
|
|
// errors (e.g. EREMOTEIO); we retry the conversion rather than abort, but bail |
|
25
|
|
|
|
|
|
|
// loudly if the bus is persistently unresponsive. |
|
26
|
|
|
|
|
|
|
#define MAX_I2C_ATTEMPTS 1000 |
|
27
|
|
|
|
|
|
|
|
|
28
|
0
|
|
|
|
|
|
int fetch(int addr, char * dev, char * wbuf1, char * wbuf2, int res, int samples){ |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
uint8_t write_buf[3]; |
|
31
|
|
|
|
|
|
|
uint8_t read_buf[2]; |
|
32
|
|
|
|
|
|
|
|
|
33
|
0
|
0
|
|
|
|
|
if (samples < 1){ |
|
34
|
0
|
|
|
|
|
|
samples = 1; |
|
35
|
|
|
|
|
|
|
} |
|
36
|
|
|
|
|
|
|
|
|
37
|
0
|
|
|
|
|
|
int i2c_file = open(dev, O_RDWR); |
|
38
|
|
|
|
|
|
|
|
|
39
|
0
|
0
|
|
|
|
|
if (i2c_file == -1){ |
|
40
|
0
|
|
|
|
|
|
perror(dev); |
|
41
|
0
|
|
|
|
|
|
exit(1); |
|
42
|
|
|
|
|
|
|
} |
|
43
|
|
|
|
|
|
|
|
|
44
|
0
|
0
|
|
|
|
|
if (ioctl(i2c_file, I2C_SLAVE, addr) < 0){ |
|
45
|
0
|
|
|
|
|
|
perror("failed to acquire bus access and/or talk to slave"); |
|
46
|
0
|
|
|
|
|
|
exit(1); |
|
47
|
|
|
|
|
|
|
} |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
// Average `samples` single-shot conversions, returning the mean. The i2c |
|
50
|
|
|
|
|
|
|
// device is opened once for the whole batch (the open/ioctl/close dominate |
|
51
|
|
|
|
|
|
|
// the per-conversion cost), so averaging N samples here is far cheaper than |
|
52
|
|
|
|
|
|
|
// taking N separate single reads. Averaging in the raw conversion domain is |
|
53
|
|
|
|
|
|
|
// exact: the volts/percent scaling that the callers apply is linear. |
|
54
|
|
|
|
|
|
|
|
|
55
|
0
|
|
|
|
|
|
long sum = 0; |
|
56
|
|
|
|
|
|
|
|
|
57
|
0
|
0
|
|
|
|
|
for (int s = 0; s < samples; s++){ |
|
58
|
|
|
|
|
|
|
|
|
59
|
0
|
|
|
|
|
|
int16_t conversion = 0; |
|
60
|
0
|
|
|
|
|
|
int got = 0; |
|
61
|
0
|
|
|
|
|
|
int attempts = 0; |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
// Acquire one conversion, retrying on a transient i2c error rather than |
|
64
|
|
|
|
|
|
|
// aborting. Averaging many conversions makes a single bus glitch likely, |
|
65
|
|
|
|
|
|
|
// and a conversion-ready poll must tolerate the odd failed read; we only |
|
66
|
|
|
|
|
|
|
// bail (loudly) if the bus stays unresponsive past MAX_I2C_ATTEMPTS. |
|
67
|
|
|
|
|
|
|
|
|
68
|
0
|
0
|
|
|
|
|
while (! got){ |
|
69
|
|
|
|
|
|
|
|
|
70
|
0
|
0
|
|
|
|
|
if (++attempts > MAX_I2C_ATTEMPTS){ |
|
71
|
0
|
|
|
|
|
|
fprintf(stderr, "fetch: i2c bus unresponsive after %d attempts\n", |
|
72
|
|
|
|
|
|
|
attempts); |
|
73
|
0
|
|
|
|
|
|
exit(1); |
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
|
|
76
|
0
|
|
|
|
|
|
write_buf[0] = 1; // set pointer to config register |
|
77
|
0
|
|
|
|
|
|
write_buf[1] = strtol(wbuf1, NULL, 0); |
|
78
|
0
|
|
|
|
|
|
write_buf[2] = strtol(wbuf2, NULL, 0); |
|
79
|
|
|
|
|
|
|
|
|
80
|
0
|
|
|
|
|
|
read_buf[0] = 0; |
|
81
|
0
|
|
|
|
|
|
read_buf[1] = 0; |
|
82
|
|
|
|
|
|
|
|
|
83
|
0
|
0
|
|
|
|
|
if (write(i2c_file, write_buf, 3) != 3){ |
|
84
|
0
|
|
|
|
|
|
continue; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
// AND with 10000000 and wait for bit 15 of the config register to |
|
88
|
|
|
|
|
|
|
// go false. This bit stores the "conversion complete" indicator. |
|
89
|
|
|
|
|
|
|
|
|
90
|
0
|
|
|
|
|
|
int ready = 1; |
|
91
|
|
|
|
|
|
|
|
|
92
|
0
|
0
|
|
|
|
|
while ((read_buf[0] & 0x80) == 0){ |
|
93
|
0
|
0
|
|
|
|
|
if (read(i2c_file, read_buf, 2) != 2){ |
|
94
|
0
|
|
|
|
|
|
ready = 0; |
|
95
|
0
|
|
|
|
|
|
break; |
|
96
|
|
|
|
|
|
|
} |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
0
|
0
|
|
|
|
|
if (! ready){ |
|
100
|
0
|
|
|
|
|
|
continue; |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
// 0: conversion register |
|
104
|
|
|
|
|
|
|
// 1: configuration register |
|
105
|
|
|
|
|
|
|
|
|
106
|
0
|
|
|
|
|
|
write_buf[0] = 0; |
|
107
|
0
|
0
|
|
|
|
|
if (write(i2c_file, write_buf, 1) != 1){ |
|
108
|
0
|
|
|
|
|
|
continue; |
|
109
|
|
|
|
|
|
|
} |
|
110
|
|
|
|
|
|
|
|
|
111
|
0
|
0
|
|
|
|
|
if (read(i2c_file, read_buf, 2) != 2){ |
|
112
|
0
|
|
|
|
|
|
continue; |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
|
|
115
|
0
|
|
|
|
|
|
conversion = read_buf[0] << 8 | read_buf[1]; |
|
116
|
|
|
|
|
|
|
|
|
117
|
0
|
0
|
|
|
|
|
if (res == 12){ |
|
118
|
0
|
|
|
|
|
|
conversion = conversion >> 4; |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
|
|
121
|
0
|
|
|
|
|
|
got = 1; |
|
122
|
|
|
|
|
|
|
} |
|
123
|
|
|
|
|
|
|
|
|
124
|
0
|
|
|
|
|
|
sum += conversion; |
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
|
|
127
|
0
|
|
|
|
|
|
close(i2c_file); |
|
128
|
|
|
|
|
|
|
|
|
129
|
0
|
|
|
|
|
|
return (int)(sum / samples); |
|
130
|
|
|
|
|
|
|
} |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
// Full-scale range (volts) of the programmed PGA gain (config bits 11-9), |
|
133
|
|
|
|
|
|
|
// per the ADS111x datasheet (SBAS444, Table). The gain bits sit in the config |
|
134
|
|
|
|
|
|
|
// register's most significant byte (wbuf1): bits 3-1 of that byte. |
|
135
|
0
|
|
|
|
|
|
static float pga_fsr(char * wbuf1){ |
|
136
|
|
|
|
|
|
|
|
|
137
|
0
|
|
|
|
|
|
int pga = (strtol(wbuf1, NULL, 0) >> 1) & 0x07; |
|
138
|
|
|
|
|
|
|
|
|
139
|
0
|
|
|
|
|
|
switch (pga){ |
|
140
|
0
|
|
|
|
|
|
case 0: return 6.144; |
|
141
|
0
|
|
|
|
|
|
case 1: return 4.096; // default |
|
142
|
0
|
|
|
|
|
|
case 2: return 2.048; |
|
143
|
0
|
|
|
|
|
|
case 3: return 1.024; |
|
144
|
0
|
|
|
|
|
|
case 4: return 0.512; |
|
145
|
0
|
|
|
|
|
|
default: return 0.256; // 5, 6, 7 |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
} |
|
148
|
|
|
|
|
|
|
|
|
149
|
0
|
|
|
|
|
|
float voltage_c (int addr, char * dev, char * wbuf1, char * wbuf2, int res, int samples){ |
|
150
|
|
|
|
|
|
|
|
|
151
|
0
|
|
|
|
|
|
int conversion = fetch(addr, dev, wbuf1, wbuf2, res, samples); |
|
152
|
|
|
|
|
|
|
|
|
153
|
0
|
|
|
|
|
|
float fsr = pga_fsr(wbuf1); |
|
154
|
0
|
0
|
|
|
|
|
float fs = (res == 12) ? ADS_FS_12 : ADS_FS_16; |
|
155
|
|
|
|
|
|
|
|
|
156
|
0
|
|
|
|
|
|
return (float)conversion * fsr / fs; |
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
|
int raw_c (int addr, char * dev, char * wbuf1, char * wbuf2, int res, int samples){ |
|
160
|
|
|
|
|
|
|
|
|
161
|
0
|
|
|
|
|
|
int conversion = fetch(addr, dev, wbuf1, wbuf2, res, samples); |
|
162
|
|
|
|
|
|
|
|
|
163
|
0
|
|
|
|
|
|
return conversion; |
|
164
|
|
|
|
|
|
|
} |
|
165
|
|
|
|
|
|
|
|
|
166
|
0
|
|
|
|
|
|
float percent_c (int addr, char * dev, char * wbuf1, char * wbuf2, int res, int samples){ |
|
167
|
|
|
|
|
|
|
|
|
168
|
0
|
|
|
|
|
|
int conversion = fetch(addr, dev, wbuf1, wbuf2, res, samples); |
|
169
|
|
|
|
|
|
|
|
|
170
|
0
|
|
|
|
|
|
float fsr = pga_fsr(wbuf1); |
|
171
|
0
|
0
|
|
|
|
|
float fs = (res == 12) ? ADS_FS_12 : ADS_FS_16; |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
// The input as a percentage of the 3.3V GPIO range, now scaled by the |
|
174
|
|
|
|
|
|
|
// programmed PGA's full-scale range rather than a constant 4.096V. |
|
175
|
0
|
|
|
|
|
|
return (float)conversion * fsr / fs / ADS_VREF * 100.0; |
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
MODULE = RPi::ADC::ADS PACKAGE = RPi::ADC::ADS |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
PROTOTYPES: DISABLE |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
int |
|
183
|
|
|
|
|
|
|
fetch (addr, dev, wbuf1, wbuf2, res, samples) |
|
184
|
|
|
|
|
|
|
int addr |
|
185
|
|
|
|
|
|
|
char * dev |
|
186
|
|
|
|
|
|
|
char * wbuf1 |
|
187
|
|
|
|
|
|
|
char * wbuf2 |
|
188
|
|
|
|
|
|
|
int res |
|
189
|
|
|
|
|
|
|
int samples |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
float |
|
192
|
|
|
|
|
|
|
voltage_c (addr, dev, wbuf1, wbuf2, res, samples) |
|
193
|
|
|
|
|
|
|
int addr |
|
194
|
|
|
|
|
|
|
char * dev |
|
195
|
|
|
|
|
|
|
char * wbuf1 |
|
196
|
|
|
|
|
|
|
char * wbuf2 |
|
197
|
|
|
|
|
|
|
int res |
|
198
|
|
|
|
|
|
|
int samples |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
int |
|
201
|
|
|
|
|
|
|
raw_c (addr, dev, wbuf1, wbuf2, res, samples) |
|
202
|
|
|
|
|
|
|
int addr |
|
203
|
|
|
|
|
|
|
char * dev |
|
204
|
|
|
|
|
|
|
char * wbuf1 |
|
205
|
|
|
|
|
|
|
char * wbuf2 |
|
206
|
|
|
|
|
|
|
int res |
|
207
|
|
|
|
|
|
|
int samples |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
float |
|
210
|
|
|
|
|
|
|
percent_c (addr, dev, wbuf1, wbuf2, res, samples) |
|
211
|
|
|
|
|
|
|
int addr |
|
212
|
|
|
|
|
|
|
char * dev |
|
213
|
|
|
|
|
|
|
char * wbuf1 |
|
214
|
|
|
|
|
|
|
char * wbuf2 |
|
215
|
|
|
|
|
|
|
int res |
|
216
|
|
|
|
|
|
|
int samples |