File Coverage

ADS.xs
Criterion Covered Total %
statement 0 67 0.0
branch 0 30 0.0
condition n/a
subroutine n/a
pod n/a
total 0 97 0.0


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