node-red-contrib-waveshare-shield-adda-11010
Loading...
Searching...
No Matches
ads1256.py
Go to the documentation of this file.
1
#!/usr/bin/env python3
2
# ads1256.py
3
#
4
# Copyright (c) 2020-2022 Spring City Solutions LLC and other contributors
5
# Licensed under the Apache License, Version 2.0
6
#
7
# Need to have the rpi.gpio and spidev python libraries installed
8
#
9
# For development, need to install the pytest system.
10
# sudo apt-get install python3-pytest
11
# See also tests/ads1256_test.py
12
# Running 'python -m pytest' should result in no errors
13
#
14
# For development, need to install the flake8 system.
15
# sudo apt-get install python3-flake8
16
# Running flake8 should report no serious problems,
17
# with E501 being ignored and excluding tests/
18
#
19
# Hardware Links:
20
#
21
# Board Manufacturer Store:
22
# https://www.waveshare.com/High-Precision-AD-DA-Board.htm
23
#
24
# Board Manufacturer Wiki:
25
# https://www.waveshare.com/wiki/High-Precision_AD/DA_Board
26
#
27
# Links for ADS1256 chip:
28
# https://www.ti.com/product/ADS1256
29
# https://www.ti.com/lit/gpn/ads1256
30
# Book "Fundamentals of Precision ADC Noise Analysis" https://www.ti.com/lit/pdf/slyy192
31
# Journal Series "How delta-sigma ADCs work" https://www.ti.com/lit/pdf/slyt423 https://www.ti.com/lit/pdf/slyt438
32
# App Note "Digital Filter Types in Delta-Sigma ADCs" https://www.ti.com/lit/pdf/sbaa230
33
#
34
# Link for LM285 chip, connected to the ADS1256:
35
# https://www.ti.com/product/LM285-2.5-N
36
# https://www.ti.com/lit/gpn/lm285-2.5-n
37
#
38
# Link for DAC8532 chip:
39
# https://www.ti.com/product/DAC8532
40
# https://www.ti.com/lit/gpn/dac8532
41
#
42
# Spring City Solutions Links:
43
#
44
# Spring City Solutions Node-RED project page:
45
# https://www.springcitysolutions.com/nodered
46
#
47
# Spring City Solutions page for this node:
48
# https://www.springcitysolutions.com/nodered-waveshare-adda-shield
49
#
50
# Spring City Solutions Node-RED project email:
51
# nodered@springcitysolutions.com
52
#
53
# Spring City Solutions Gitlab for this node:
54
# https://gitlab.com/SpringCitySolutionsLLC/waveshare-shield-adda-11010
55
#
56
# Patreon Page:
57
# https://www.patreon.com/springcitysolutions_nodered
58
#
59
# Software Links:
60
#
61
# Spring City Solutions Gitlab for this node:
62
# https://gitlab.com/SpringCitySolutionsLLC/waveshare-shield-adda-11010
63
#
64
# Doxygen docs for this node autogenerated by Gitlab CI/CD:
65
# https://springcitysolutionsllc.gitlab.io/waveshare-shield-adda-11010/index.html
66
#
67
# npmjs for this node:
68
# https://npmjs.org/package/node-red-contrib-waveshare-shield-adda-11010
69
#
70
# Node-RED flows for this node:
71
# https://flows.nodered.org/node/node-red-contrib-waveshare-shield-adda-11010
72
#
73
# Documentation Links:
74
#
75
# Gitlab wiki for this node (the master copy of list of links is here):
76
# https://gitlab.com/SpringCitySolutionsLLC/waveshare-shield-adda-11010/-/wikis/home
77
#
78
# Waveshare's libraries for this hardware:
79
# https://github.com/waveshare/High-Precision-AD-DA-Board
80
#
81
# Youtube video "How to set up":
82
# TODO
83
#
84
# Youtube video "How to use":
85
# TODO
86
#
87
# Youtube video "Testing Results":
88
# TODO
89
#
90
# Usage:
91
#
92
# ads1256.py analog "channel number 0 to 7" "gain 1 to 64" "rate 2.5 to 30000" "on or off buffer" "sdcs off of current"
93
# returns 0 for 0 volts and decimal 0x7fffff for 5 volts
94
#
95
# ads1256.py calibrationFSC
96
# returns fullscale calibration register value as a decimal integer
97
#
98
# ads1256.py calibrationOFC
99
# returns offset calibration register value as a decimal integer
100
#
101
# ads1256.py digitalIn "D0 to D3"
102
# returns 0 or 1 as per input to the specified pin
103
#
104
# ads1256.py digitalOut "D0 to D3" "0 or 1"
105
106
import
argparse
107
import
json
108
import
sys
109
110
import
RPi.GPIO
as
GPIO
111
import
spidev
112
113
# TODO: Could make the SPI control pins configurable.
114
cs = 22
115
drdy = 17
116
117
# The overall mode of operation
118
mode =
'analog'
119
# For GPIO
120
output = -1
121
122
register_address = dict([(
'status'
, 0x00),
123
(
'mux'
, 0x01),
124
(
'adcon'
, 0x02),
125
(
'drate'
, 0x03),
126
(
'gpio'
, 0x04),
127
(
'ofc0'
, 0x05),
128
(
'ofc1'
, 0x06),
129
(
'ofc2'
, 0x07),
130
(
'fsc0'
, 0x08),
131
(
'fsc1'
, 0x09),
132
(
'fsc2'
, 0x0a)])
133
134
register_data = dict([(
'adcon'
, 0x00),
135
(
'drate'
, 0x00),
136
(
'fsc'
, 0x000000),
137
(
'gpio_direction_bitmask'
, 0x00),
138
(
'gpio_status_bitmask'
, 0x00),
139
(
"mux"
, 0x00),
140
(
'ofc'
, 0x000000),
141
(
'status'
, 0x00)])
142
143
144
# Functions that do things.
145
146
147
def
output_json
():
148
"""Prints a JSON of the register_data for development and testing."""
149
print(json.dumps(register_data, sort_keys=
True
, indent=4))
150
151
152
def
parse_args
(raw_args):
153
"""Parses the args into ready to write register_data."""
154
# First parse the CLI.
155
parser = argparse.ArgumentParser()
156
parser.add_argument(
"--mode"
, type=str, default=
"analog"
,
157
help=
"Mode: analog, calibrationFSC, calibrationOFC, digitalIn, digitalOut default analog"
)
158
parser.add_argument(
"--port_p"
, type=str, default=
"0"
,
159
help=
"Positive Analog Input Port: 0 thru 8 default 0"
)
160
parser.add_argument(
"--port_n"
, type=str, default=
"8"
,
161
help=
"Negative Analog Input Port: 0 thru 8 default 8 (AINCOM)"
)
162
parser.add_argument(
"--gain"
, type=str, default=
"1"
,
163
help=
"Input Amp Gain: 1, 2, 4, 8, 16, 32, 64 default 1"
)
164
parser.add_argument(
"--rate"
, type=str, default=
"2.5"
,
165
help=
"Data Rate in samples per second: 2.5, 5, 10, 15, 25, 30, 50, 60, 100, 500, 1000, 2000, 3750, 7500, 15000, 30000 default 2.5"
)
166
parser.add_argument(
"--buffer"
, type=str, default=
"off"
,
167
help=
"Input Buffer: off, on default off"
)
168
parser.add_argument(
"--sdcs"
, type=str, default=
"off"
,
169
help=
"SDCS sensor direct current source microamps: off, 0.5, 2, 10 default off"
)
170
parser.add_argument(
"--pin"
, type=str, default=
"D0"
,
171
help=
"Specify pin for modes digitalIn and digitalOut: D0, D1, D2, D3 default D0"
)
172
parser.add_argument(
"--output"
, type=str, default=
"-1"
,
173
help=
"Absence means input mode, or specify output for modes digitalIn and digitalOut: 0, 1 default input mode"
)
174
parser.add_argument(
"-t"
,
"--test"
, action=
"store_true"
,
175
help=
"Print JSON of register_data"
)
176
args = parser.parse_args(raw_args)
177
178
# Save global configs
179
global
mode
180
mode = args.mode
181
global
output
182
output = args.output
183
184
# Process the STATUS register, including the BUFEN analog input buffer property.
185
register_data[
'status'
] = 0x00
186
if
(args.buffer ==
'on'
):
187
register_data[
'status'
] = 0x02
188
if
(args.buffer ==
'off'
):
189
register_data[
'status'
] = 0x00
190
191
# Process the ADCON register, including PGA gain and SDCS property.
192
register_data[
'adcon'
] = 0x20
# Default clock out rate setting
193
if
(args.gain ==
'1'
):
194
register_data[
'adcon'
] += 0x00
195
if
(args.gain ==
'2'
):
196
register_data[
'adcon'
] += 0x01
197
if
(args.gain ==
'4'
):
198
register_data[
'adcon'
] += 0x02
199
if
(args.gain ==
'8'
):
200
register_data[
'adcon'
] += 0x03
201
if
(args.gain ==
'16'
):
202
register_data[
'adcon'
] += 0x04
203
if
(args.gain ==
'32'
):
204
register_data[
'adcon'
] += 0x05
205
if
(args.gain ==
'64'
):
206
register_data[
'adcon'
] += 0x06
207
if
(args.sdcs ==
'off'
):
208
register_data[
'adcon'
] += 0x00
209
if
(args.sdcs ==
'0.5'
):
210
register_data[
'adcon'
] += 0x08
211
if
(args.sdcs ==
'2'
):
212
register_data[
'adcon'
] += 0x10
213
if
(args.sdcs ==
'10'
):
214
register_data[
'adcon'
] += 0x18
215
216
# Process the DRATE register, including the rate property.
217
register_data[
'drate'
] = 0x03
218
if
(args.rate ==
'30000'
):
219
register_data[
'drate'
] = 0xF0
220
if
(args.rate ==
'15000'
):
221
register_data[
'drate'
] = 0xE0
222
if
(args.rate ==
'7500'
):
223
register_data[
'drate'
] = 0xD0
224
if
(args.rate ==
'3750'
):
225
register_data[
'drate'
] = 0xC0
226
if
(args.rate ==
'2000'
):
227
register_data[
'drate'
] = 0xB0
228
if
(args.rate ==
'1000'
):
229
register_data[
'drate'
] = 0xA1
230
if
(args.rate ==
'500'
):
231
register_data[
'drate'
] = 0x92
232
if
(args.rate ==
'100'
):
233
register_data[
'drate'
] = 0x82
234
if
(args.rate ==
'60'
):
235
register_data[
'drate'
] = 0x72
236
if
(args.rate ==
'50'
):
237
register_data[
'drate'
] = 0x63
238
if
(args.rate ==
'30'
):
239
register_data[
'drate'
] = 0x53
240
if
(args.rate ==
'25'
):
241
register_data[
'drate'
] = 0x43
242
if
(args.rate ==
'15'
):
243
register_data[
'drate'
] = 0x33
244
if
(args.rate ==
'10'
):
245
register_data[
'drate'
] = 0x23
246
if
(args.rate ==
'5'
):
247
register_data[
'drate'
] = 0x13
248
if
(args.rate ==
'2.5'
):
249
register_data[
'drate'
] = 0x03
250
251
# Process the MUX register, including the port.
252
# register_data['mux'] = 0x08
253
register_data[
'mux'
] = (int(args.port_p) << 4) | int(args.port_n)
254
255
# Process the gpio_direction_bitmask and gpio_status_bitmask registers, including the pin property.
256
register_data[
'gpio_direction_bitmask'
] = 0x10
257
register_data[
'gpio_status_bitmask'
] = 0x01
258
if
(args.pin ==
'D0'
):
259
register_data[
'gpio_direction_bitmask'
] = 0x10
260
register_data[
'gpio_status_bitmask'
] = 0x01
261
if
(args.pin ==
'D1'
):
262
register_data[
'gpio_direction_bitmask'
] = 0x20
263
register_data[
'gpio_status_bitmask'
] = 0x02
264
if
(args.pin ==
'D2'
):
265
register_data[
'gpio_direction_bitmask'
] = 0x40
266
register_data[
'gpio_status_bitmask'
] = 0x04
267
if
(args.pin ==
'D3'
):
268
register_data[
'gpio_direction_bitmask'
] = 0x80
269
register_data[
'gpio_status_bitmask'
] = 0x08
270
271
# Optionally output register state for development purposes.
272
if
args.test:
273
output_json
()
274
exit()
275
276
277
# Functions that read or write to the device.
278
# Device commands are run by functions named after the datasheet provided device command names.
279
# The datasheet names are all caps, Python names are lowercase, other than that issue, they match.
280
# The complete list of commands is on datasheet page 34 table 24.
281
282
283
def
rreg
(register):
284
"""Run RREG command as explained on datasheet page 36."""
285
GPIO.output(cs, 0)
286
firstbyte = 0x10 + register
287
secondbyte = 0x01
288
spi.writebytes([firstbyte, secondbyte])
289
data = spi.readbytes(1)
290
GPIO.output(cs, 1)
291
return
data[0]
292
293
294
def
wreg
(register, data):
295
"""Run WREG command as explained on datasheet page 36."""
296
GPIO.output(cs, 0)
297
firstbyte = 0x50 + register
298
secondbyte = 0x01
299
spi.writebytes([firstbyte, secondbyte, data])
300
GPIO.output(cs, 1)
301
302
303
def
selfcal
():
304
"""Run SELFCAL command as explained on datasheet page 36."""
305
GPIO.output(cs, 0)
306
spi.writebytes([0xf0])
307
GPIO.output(cs, 1)
308
while
True
:
309
if
(GPIO.input(drdy) == 0):
310
break
311
312
313
def
rdata
():
314
"""Run RDATA command as explained on datasheet page 34."""
315
while
True
:
316
if
(GPIO.input(drdy) == 0):
317
break
318
GPIO.output(cs, 0)
319
spi.writebytes([0x01])
320
buf = spi.readbytes(3)
321
GPIO.output(cs, 1)
322
read = (buf[0] << 16) & 0xff0000
323
read |= (buf[1] << 8) & 0xff00
324
read |= (buf[2]) & 0xff
325
return
twos_complement_to_integer_24bit
(read)
326
327
328
def
sync
():
329
"""Run SYNC command as explained on datasheet page 37."""
330
GPIO.output(cs, 0)
331
spi.writebytes([0xfc])
332
GPIO.output(cs, 1)
333
334
335
def
wakeup
():
336
"""Run WAKEUP command as explained on datasheet page 37."""
337
GPIO.output(cs, 0)
338
spi.writebytes([0xff])
339
GPIO.output(cs, 1)
340
341
342
def
read_fsc_reg
():
343
"""Read the FSC calibration value."""
344
# See datasheet page 33 to read the raw byte values.
345
# FSC per datasheet pg 24 is an unsigned 24 bit integer.
346
register_data[
'fsc'
] = 0x000000
347
register_data[
'fsc'
] += (
rreg
(register_address[
'fsc2'
]) << 16)
348
register_data[
'fsc'
] += (
rreg
(register_address[
'fsc1'
]) << 8)
349
register_data[
'fsc'
] +=
rreg
(register_address[
'fsc0'
])
350
351
352
def
read_ofc_reg
():
353
"""Read the OFC calibration value."""
354
# See datasheet page 33 to read the raw byte values.
355
# OFC per datasheet pg 24 is a twos complement 24 bit signed integer.
356
ofc_twos_complement = 0x000000
357
ofc_twos_complement += (
rreg
(register_address[
'ofc2'
]) << 16)
358
ofc_twos_complement += (
rreg
(register_address[
'ofc1'
]) << 8)
359
ofc_twos_complement +=
rreg
(register_address[
'ofc0'
])
360
register_data[
'ofc'
] =
twos_complement_to_integer_24bit
(ofc_twos_complement)
361
362
363
def
write_adcon_reg
():
364
"""Write the ADCON register. See datasheet page 31."""
365
wreg
(register_address[
'adcon'
], register_data[
'adcon'
])
366
367
368
def
write_drate_reg
():
369
"""Write the DRATE register. See datasheet page 32."""
370
wreg
(register_address[
'drate'
], register_data[
'drate'
])
371
372
373
def
write_mux_reg
():
374
"""Write the MUX register. See datasheet page 31."""
375
wreg
(register_address[
'mux'
], register_data[
'mux'
])
376
377
378
def
write_status_reg
():
379
"""Write the STATUS register. See datasheet page 30."""
380
wreg
(register_address[
'status'
], register_data[
'status'
])
381
382
383
# Functions that convert
384
385
386
def
twos_complement_to_integer_24bit
(twos_complement):
387
"""Convert a 24 bit twos complement value to a plain Python integer."""
388
result = twos_complement
389
if
(twos_complement & (1 << 23)):
390
result = twos_complement & ~(1 << 24)
391
result = -(1 << 24) + result
392
return
result
393
394
395
parse_args
(sys.argv[1:])
396
397
398
GPIO.setmode(GPIO.BCM)
399
GPIO.setwarnings(
False
)
400
GPIO.setup(cs, GPIO.OUT)
401
GPIO.output(cs, 1)
402
GPIO.setup(drdy, GPIO.IN)
403
404
spi = spidev.SpiDev()
405
spi.open(0, 0)
406
spi.max_speed_hz = 20000
407
spi.mode = 0b01
408
409
if
(mode ==
'analog'
):
410
# Write the registers in the correct order.
411
write_status_reg
()
412
write_adcon_reg
()
413
write_drate_reg
()
414
write_mux_reg
()
415
# Self Calibration required after MUX change.
416
selfcal
()
417
# Sync and Wakeup, in that order, are required to start a conversion.
418
sync
()
419
wakeup
()
420
# Read data.
421
print(
rdata
())
422
423
if
(mode ==
'calibrationFSC'
):
424
read_fsc_reg
()
425
print(register_data[
'fsc'
])
426
427
if
(mode ==
'calibrationOFC'
):
428
read_ofc_reg
()
429
print(register_data[
'ofc'
])
430
431
if
(mode ==
'digitalIn'
):
432
# Change exactly one bit to input mode.
433
wreg
(0x04,
rreg
(0x04) | register_data[
'gpio_direction_bitmask'
])
434
if
((
rreg
(0x04) & register_data[
'gpio_status_bitmask'
]) > 0):
435
print(
'1'
)
436
else
:
437
print(
'0'
)
438
439
if
(mode ==
'digitalOut'
):
440
if
(output ==
'0'
):
441
wreg
(0x04,
442
rreg
(0x04) & ~register_data[
'gpio_direction_bitmask'
] & ~register_data[
'gpio_status_bitmask'
])
443
if
(output ==
'1'
):
444
wreg
(0x04,
445
rreg
(0x04) & ~register_data[
'gpio_direction_bitmask'
] | register_data[
'gpio_status_bitmask'
])
ads1256.sync
sync()
Definition
ads1256.py:328
ads1256.twos_complement_to_integer_24bit
twos_complement_to_integer_24bit(twos_complement)
Definition
ads1256.py:386
ads1256.write_mux_reg
write_mux_reg()
Definition
ads1256.py:373
ads1256.wakeup
wakeup()
Definition
ads1256.py:335
ads1256.rdata
rdata()
Definition
ads1256.py:313
ads1256.read_fsc_reg
read_fsc_reg()
Definition
ads1256.py:342
ads1256.write_status_reg
write_status_reg()
Definition
ads1256.py:378
ads1256.write_adcon_reg
write_adcon_reg()
Definition
ads1256.py:363
ads1256.parse_args
parse_args(raw_args)
Definition
ads1256.py:152
ads1256.selfcal
selfcal()
Definition
ads1256.py:303
ads1256.output_json
output_json()
Definition
ads1256.py:147
ads1256.write_drate_reg
write_drate_reg()
Definition
ads1256.py:368
ads1256.read_ofc_reg
read_ofc_reg()
Definition
ads1256.py:352
ads1256.wreg
wreg(register, data)
Definition
ads1256.py:294
ads1256.rreg
rreg(register)
Definition
ads1256.py:283
ads1256.py
Generated on Sat Sep 14 2024 04:54:43 for node-red-contrib-waveshare-shield-adda-11010 by
1.11.0