Gordons Projects

--> Projects Top-Level GIT

Many changes - tidying up the extensions interfaces.
[wiringPi] / wiringPi / ads1115.c
1 /*
2  * ads1115.c:
3  *      Extend wiringPi with the ADS1115 I2C 16-bit ADC
4  *      Copyright (c) 2016 Gordon Henderson
5  ***********************************************************************
6  * This file is part of wiringPi:
7  *      https://projects.drogon.net/raspberry-pi/wiringpi/
8  *
9  *    wiringPi is free software: you can redistribute it and/or modify
10  *    it under the terms of the GNU Lesser General Public License as
11  *    published by the Free Software Foundation, either version 3 of the
12  *    License, or (at your option) any later version.
13  *
14  *    wiringPi is distributed in the hope that it will be useful,
15  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *    GNU Lesser General Public License for more details.
18  *
19  *    You should have received a copy of the GNU Lesser General Public
20  *    License along with wiringPi.
21  *    If not, see <http://www.gnu.org/licenses/>.
22  ***********************************************************************
23  */
24
25 /*
26  *********************************************************************************
27  * We're going to work in a hybrid mode to fit in with the wiringPi way of
28  * doing things, so there will be 4 analog pin which read the 4 single-ended
29  * channels as usual, also some fake digitalOutputs - these are the control
30  * registers that allow the user to put it into single/diff mode, set the
31  * gain and data rates.
32  *********************************************************************************
33  */
34
35 #include <byteswap.h>
36 #include <stdio.h>
37 #include <stdint.h>
38
39 #include <wiringPi.h>
40 #include <wiringPiI2C.h>
41
42 #include "ads1115.h"
43
44 // Bits in the config register (it's a 16-bit register)
45
46 #define CONFIG_OS_MASK          (0x8000)        // Operational Status Register
47 #define CONFIG_OS_SINGLE        (0x8000)        // Write - Starts a single-conversion
48                                                 // Read    1 = Conversion complete
49
50 // The multiplexor
51
52 #define CONFIG_MUX_MASK         (0x7000)
53
54 // Differential modes
55
56 #define CONFIG_MUX_DIFF_0_1     (0x0000)        // Pos = AIN0, Neg = AIN1 (default)
57 #define CONFIG_MUX_DIFF_0_3     (0x1000)        // Pos = AIN0, Neg = AIN3
58 #define CONFIG_MUX_DIFF_1_3     (0x2000)        // Pos = AIN1, Neg = AIN3
59 #define CONFIG_MUX_DIFF_2_3     (0x3000)        // Pos = AIN2, Neg = AIN3 (2nd differential channel)
60
61 // Single-ended modes
62
63 #define CONFIG_MUX_SINGLE_0     (0x4000)        // AIN0
64 #define CONFIG_MUX_SINGLE_1     (0x5000)        // AIN1
65 #define CONFIG_MUX_SINGLE_2     (0x6000)        // AIN2
66 #define CONFIG_MUX_SINGLE_3     (0x7000)        // AIN3
67
68 // Programmable Gain Amplifier
69
70 #define CONFIG_PGA_MASK         (0x0E00)
71 #define CONFIG_PGA_6_144V       (0x0000)        // +/-6.144V range = Gain 2/3
72 #define CONFIG_PGA_4_096V       (0x0200)        // +/-4.096V range = Gain 1
73 #define CONFIG_PGA_2_048V       (0x0400)        // +/-2.048V range = Gain 2 (default)
74 #define CONFIG_PGA_1_024V       (0x0600)        // +/-1.024V range = Gain 4
75 #define CONFIG_PGA_0_512V       (0x0800)        // +/-0.512V range = Gain 8
76 #define CONFIG_PGA_0_256V       (0x0A00)        // +/-0.256V range = Gain 16
77
78 #define CONFIG_MODE             (0x0100)        // 0 is continuous, 1 is single-shot (default)
79
80 // Data Rate
81
82 #define CONFIG_DR_MASK          (0x00E0)
83 #define CONFIG_DR_8SPS          (0x0000)        //   8 samples per second
84 #define CONFIG_DR_16SPS         (0x0020)        //  16 samples per second
85 #define CONFIG_DR_32SPS         (0x0040)        //  32 samples per second
86 #define CONFIG_DR_64SPS         (0x0060)        //  64 samples per second
87 #define CONFIG_DR_128SPS        (0x0080)        // 128 samples per second (default)
88 #define CONFIG_DR_475SPS        (0x00A0)        // 475 samples per second
89 #define CONFIG_DR_860SPS        (0x00C0)        // 860 samples per second
90
91 // Comparator mode
92
93 #define CONFIG_CMODE_MASK       (0x0010)
94 #define CONFIG_CMODE_TRAD       (0x0000)        // Traditional comparator with hysteresis (default)
95 #define CONFIG_CMODE_WINDOW     (0x0010)        // Window comparator
96
97 // Comparator polarity - the polarity of the output alert/rdy pin
98
99 #define CONFIG_CPOL_MASK        (0x0008)
100 #define CONFIG_CPOL_ACTVLOW     (0x0000)        // Active low (default)
101 #define CONFIG_CPOL_ACTVHI      (0x0008)        // Active high
102
103 // Latching comparator - does the alert/rdy pin latch
104
105 #define CONFIG_CLAT_MASK        (0x0004)
106 #define CONFIG_CLAT_NONLAT      (0x0000)        // Non-latching comparator (default)
107 #define CONFIG_CLAT_LATCH       (0x0004)        // Latching comparator
108
109 // Comparitor queue
110
111 #define CONFIG_CQUE_MASK        (0x0003)
112 #define CONFIG_CQUE_1CONV       (0x0000)        // Assert after one conversions
113 #define CONFIG_CQUE_2CONV       (0x0001)        // Assert after two conversions
114 #define CONFIG_CQUE_4CONV       (0x0002)        // Assert after four conversions
115 #define CONFIG_CQUE_NONE        (0x0003)        // Disable the comparator (default)
116
117 #define CONFIG_DEFAULT          (0x8583)        // From the datasheet
118
119
120 static const uint16_t dataRates [8] =
121 {
122   CONFIG_DR_8SPS, CONFIG_DR_16SPS, CONFIG_DR_32SPS, CONFIG_DR_64SPS, CONFIG_DR_128SPS, CONFIG_DR_475SPS, CONFIG_DR_860SPS
123 } ;
124
125 static const uint16_t gains [6] =
126 {
127   CONFIG_PGA_6_144V, CONFIG_PGA_4_096V, CONFIG_PGA_2_048V, CONFIG_PGA_1_024V, CONFIG_PGA_0_512V, CONFIG_PGA_0_256V
128 } ;
129
130
131 /*
132  * analogRead:
133  *      Pin is the channel to sample on the device.
134  *      Channels 0-3 are single ended inputs,
135  *      channels 4-7 are the various differential combinations.
136  *********************************************************************************
137  */
138
139 static int myAnalogRead (struct wiringPiNodeStruct *node, int pin)
140 {
141   int chan = pin - node->pinBase ;
142   int16_t  result ;
143   uint16_t config = CONFIG_DEFAULT ;
144
145   chan &= 7 ;
146
147 // Setup the configuration register
148
149 //      Set PGA/voltage range
150
151   config &= ~CONFIG_PGA_MASK ;
152   config |= node->data0 ;
153
154 //      Set sample speed
155
156   config &= ~CONFIG_DR_MASK ;
157   config |= node->data1 ;
158
159 //      Set single-ended channel or differential mode
160
161   config &= ~CONFIG_MUX_MASK ;
162
163   switch (chan)
164   {
165     case 0: config |= CONFIG_MUX_SINGLE_0 ; break ;
166     case 1: config |= CONFIG_MUX_SINGLE_1 ; break ;
167     case 2: config |= CONFIG_MUX_SINGLE_2 ; break ;
168     case 3: config |= CONFIG_MUX_SINGLE_3 ; break ;
169
170     case 4: config |= CONFIG_MUX_DIFF_0_1 ; break ;
171     case 5: config |= CONFIG_MUX_DIFF_2_3 ; break ;
172     case 6: config |= CONFIG_MUX_DIFF_0_3 ; break ;
173     case 7: config |= CONFIG_MUX_DIFF_1_3 ; break ;
174   }
175
176 //      Start a single conversion
177
178   config |= CONFIG_OS_SINGLE ;
179   config = __bswap_16 (config) ;
180   wiringPiI2CWriteReg16 (node->fd, 1, config) ;
181
182 // Wait for the conversion to complete
183
184   for (;;)
185   {
186     result =  wiringPiI2CReadReg16 (node->fd, 1) ;
187     result = __bswap_16 (result) ;
188     if ((result & CONFIG_OS_MASK) != 0)
189       break ;
190     delayMicroseconds (100) ;
191   }
192
193   result =  wiringPiI2CReadReg16 (node->fd, 0) ;
194   result = __bswap_16 (result) ;
195
196 // Sometimes with a 0v input on a single-ended channel the internal 0v reference
197 //      can be higher than the input, so you get a negative result...
198
199   if ( (chan < 4) && (result < 0) ) 
200     return 0 ;
201   else
202     return (int)result ;
203 }
204
205
206 /*
207  * digitalWrite:
208  *      It may seem odd to have a digital write here, but it's the best way
209  *      to pass paramters into the chip in the wiringPi way of things.
210  *      We have 2 digital registers:
211  *              0 is the gain control
212  *              1 is the data rate control
213  *********************************************************************************
214  */
215
216 static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int data)
217 {
218   int chan = pin - node->pinBase ;
219   chan &= 3 ;
220
221   if (chan == 0)        // Gain Control
222   {
223     if ( (data < 0) || (data > 6) )     // Use default if out of range
224       data = 2 ;
225     node->data0 = gains [data] ;
226   }
227   else                  // Data rate control
228   {
229     if ( (data < 0) || (data > 7) )     // Use default if out of range
230       data = 4 ;
231     node->data0 = dataRates [data] ;
232   }
233   
234 }
235
236
237 /*
238  * analogWrite:
239  *      We're using this to write to the 2 comparitor threshold registers.
240  *      We could use a digitalWrite here but as it's an analog comparison
241  *      then it feels better to do it this way.
242  *********************************************************************************
243  */
244
245 static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int data)
246 {
247   int chan = pin - node->pinBase ;
248   int reg ;
249   int16_t ndata ;
250
251   chan &= 3 ;
252
253   reg = chan + 2 ;
254
255   /**/ if (data < -32767)
256     ndata = -32767 ;
257   else if (data > 32767)
258     ndata = 32767 ;
259   else
260     ndata = (int16_t)data ;
261
262   ndata = __bswap_16 (ndata) ;
263   wiringPiI2CWriteReg16 (node->fd, reg, data) ;
264 }
265
266
267
268 /*
269  * ads1115Setup:
270  *      Create a new wiringPi device node for an ads1115 on the Pi's
271  *      I2C interface.
272  *********************************************************************************
273  */
274
275 int ads1115Setup (const int pinBase, int i2cAddr)
276 {
277   struct wiringPiNodeStruct *node ;
278   int fd ;
279
280   if ((fd = wiringPiI2CSetup (i2cAddr)) < 0)
281     return FALSE ;
282
283   node = wiringPiNewNode (pinBase, 8) ;
284
285   node->fd           = fd ;
286   node->data0        = CONFIG_PGA_4_096V ;      // Gain in data0
287   node->data1        = CONFIG_DR_128SPS ;       // Samples/sec in data1
288   node->analogRead   = myAnalogRead ;
289   node->analogWrite  = myAnalogWrite ;
290   node->digitalWrite = myDigitalWrite ;
291
292   return TRUE ;
293 }