0
# SPI Devices
1
2
SPI-connected devices including analog-to-digital converters (ADCs) from the MCP3xxx family. These devices enable reading analog sensor values and can be used as sources for other devices.
3
4
## Base Classes
5
6
### SPIDevice
7
8
Base class for all SPI-connected devices.
9
10
```python { .api }
11
class SPIDevice(Device):
12
def __init__(self, *, port=0, device=0, pin_factory=None):
13
"""
14
Base class for SPI devices.
15
16
Parameters:
17
- port: int - SPI port number (usually 0)
18
- device: int - SPI device number (chip select)
19
- pin_factory: Factory or None - Pin factory for advanced usage
20
"""
21
22
@property
23
def closed(self) -> bool:
24
"""Returns True if device is closed."""
25
26
def close(self):
27
"""Close the device and release resources."""
28
```
29
30
### AnalogInputDevice
31
32
Base class for analog-to-digital converter devices.
33
34
```python { .api }
35
class AnalogInputDevice(SPIDevice):
36
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
37
"""
38
Base class for ADC devices.
39
40
Parameters:
41
- channel: int - ADC channel number to read from
42
- differential: bool - True for differential reading, False for single-ended
43
- max_voltage: float - Maximum input voltage for scaling
44
- **spi_args: Additional SPI configuration arguments
45
"""
46
47
@property
48
def value(self) -> float:
49
"""Current analog reading scaled to 0.0-1.0 range."""
50
51
@property
52
def voltage(self) -> float:
53
"""Current reading as voltage (0.0 to max_voltage)."""
54
55
@property
56
def raw_value(self) -> int:
57
"""Raw ADC reading as integer."""
58
59
@property
60
def channel(self) -> int:
61
"""ADC channel being read."""
62
63
@property
64
def differential(self) -> bool:
65
"""True if using differential reading mode."""
66
67
@property
68
def max_voltage(self) -> float:
69
"""Maximum input voltage for scaling."""
70
```
71
72
## MCP30xx Series (10-bit ADCs)
73
74
### MCP3001
75
76
Single-channel 10-bit ADC.
77
78
```python { .api }
79
class MCP3001(AnalogInputDevice):
80
def __init__(self, *, max_voltage=3.3, **spi_args):
81
"""
82
MCP3001 10-bit single-channel ADC.
83
84
Parameters:
85
- max_voltage: float - Maximum input voltage (default 3.3V)
86
- **spi_args: SPI configuration (port, device, etc.)
87
"""
88
```
89
90
### MCP3002
91
92
Dual-channel 10-bit ADC.
93
94
```python { .api }
95
class MCP3002(AnalogInputDevice):
96
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
97
"""
98
MCP3002 10-bit dual-channel ADC.
99
100
Parameters:
101
- channel: int - Channel number (0 or 1)
102
- differential: bool - True for differential mode
103
- max_voltage: float - Maximum input voltage
104
- **spi_args: SPI configuration
105
"""
106
```
107
108
### MCP3004
109
110
4-channel 10-bit ADC.
111
112
```python { .api }
113
class MCP3004(AnalogInputDevice):
114
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
115
"""
116
MCP3004 10-bit 4-channel ADC.
117
118
Parameters:
119
- channel: int - Channel number (0-3)
120
- differential: bool - True for differential mode
121
- max_voltage: float - Maximum input voltage
122
- **spi_args: SPI configuration
123
"""
124
```
125
126
### MCP3008
127
128
8-channel 10-bit ADC (most commonly used).
129
130
```python { .api }
131
class MCP3008(AnalogInputDevice):
132
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
133
"""
134
MCP3008 10-bit 8-channel ADC.
135
136
Parameters:
137
- channel: int - Channel number (0-7)
138
- differential: bool - True for differential mode
139
- max_voltage: float - Maximum input voltage
140
- **spi_args: SPI configuration (port=0, device=0)
141
"""
142
```
143
144
## MCP32xx Series (12-bit ADCs)
145
146
### MCP3201
147
148
Single-channel 12-bit ADC.
149
150
```python { .api }
151
class MCP3201(AnalogInputDevice):
152
def __init__(self, *, max_voltage=3.3, **spi_args):
153
"""
154
MCP3201 12-bit single-channel ADC.
155
156
Parameters:
157
- max_voltage: float - Maximum input voltage
158
- **spi_args: SPI configuration
159
"""
160
```
161
162
### MCP3202
163
164
Dual-channel 12-bit ADC.
165
166
```python { .api }
167
class MCP3202(AnalogInputDevice):
168
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
169
"""
170
MCP3202 12-bit dual-channel ADC.
171
172
Parameters:
173
- channel: int - Channel number (0 or 1)
174
- differential: bool - True for differential mode
175
- max_voltage: float - Maximum input voltage
176
- **spi_args: SPI configuration
177
"""
178
```
179
180
### MCP3204
181
182
4-channel 12-bit ADC.
183
184
```python { .api }
185
class MCP3204(AnalogInputDevice):
186
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
187
"""
188
MCP3204 12-bit 4-channel ADC.
189
190
Parameters:
191
- channel: int - Channel number (0-3)
192
- differential: bool - True for differential mode
193
- max_voltage: float - Maximum input voltage
194
- **spi_args: SPI configuration
195
"""
196
```
197
198
### MCP3208
199
200
8-channel 12-bit ADC.
201
202
```python { .api }
203
class MCP3208(AnalogInputDevice):
204
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
205
"""
206
MCP3208 12-bit 8-channel ADC.
207
208
Parameters:
209
- channel: int - Channel number (0-7)
210
- differential: bool - True for differential mode
211
- max_voltage: float - Maximum input voltage
212
- **spi_args: SPI configuration
213
"""
214
```
215
216
## MCP33xx Series (13-bit Signed ADCs)
217
218
### MCP3301
219
220
Single-channel 13-bit signed ADC.
221
222
```python { .api }
223
class MCP3301(AnalogInputDevice):
224
def __init__(self, *, max_voltage=3.3, **spi_args):
225
"""
226
MCP3301 13-bit single-channel signed ADC.
227
228
Parameters:
229
- max_voltage: float - Maximum input voltage
230
- **spi_args: SPI configuration
231
"""
232
```
233
234
### MCP3302
235
236
4-channel 13-bit signed ADC.
237
238
```python { .api }
239
class MCP3302(AnalogInputDevice):
240
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
241
"""
242
MCP3302 13-bit 4-channel signed ADC.
243
244
Parameters:
245
- channel: int - Channel number (0-3)
246
- differential: bool - True for differential mode
247
- max_voltage: float - Maximum input voltage
248
- **spi_args: SPI configuration
249
"""
250
```
251
252
### MCP3304
253
254
8-channel 13-bit signed ADC.
255
256
```python { .api }
257
class MCP3304(AnalogInputDevice):
258
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
259
"""
260
MCP3304 13-bit 8-channel signed ADC.
261
262
Parameters:
263
- channel: int - Channel number (0-7)
264
- differential: bool - True for differential mode
265
- max_voltage: float - Maximum input voltage
266
- **spi_args: SPI configuration
267
"""
268
```
269
270
## Usage Examples
271
272
### Basic Analog Reading
273
274
```python
275
from gpiozero import MCP3008
276
from time import sleep
277
278
# Single channel reading
279
adc = MCP3008(channel=0)
280
281
while True:
282
value = adc.value # 0.0 to 1.0
283
voltage = adc.voltage # 0.0 to 3.3V (or max_voltage)
284
raw = adc.raw_value # Raw ADC counts
285
286
print(f"Value: {value:.3f}, Voltage: {voltage:.2f}V, Raw: {raw}")
287
sleep(0.5)
288
```
289
290
### Multiple Channel Reading
291
292
```python
293
from gpiozero import MCP3008
294
295
# Create ADC objects for different channels
296
channels = [MCP3008(channel=i) for i in range(4)]
297
298
while True:
299
readings = [adc.value for adc in channels]
300
print(f"Channels 0-3: {readings}")
301
sleep(0.1)
302
```
303
304
### Potentiometer Control
305
306
```python
307
from gpiozero import MCP3008, PWMLED
308
from signal import pause
309
310
pot = MCP3008(channel=0)
311
led = PWMLED(17)
312
313
# LED brightness follows potentiometer
314
led.source = pot
315
316
pause()
317
```
318
319
### Analog Sensor with Thresholds
320
321
```python
322
from gpiozero import MCP3008, LED
323
from time import sleep
324
325
sensor = MCP3008(channel=0)
326
warning_led = LED(17)
327
alarm_led = LED(18)
328
329
while True:
330
value = sensor.value
331
332
if value > 0.8:
333
warning_led.off()
334
alarm_led.on()
335
print("ALARM: High reading!")
336
elif value > 0.6:
337
warning_led.on()
338
alarm_led.off()
339
print("Warning: Elevated reading")
340
else:
341
warning_led.off()
342
alarm_led.off()
343
print(f"Normal: {value:.3f}")
344
345
sleep(0.5)
346
```
347
348
### Temperature Sensor (TMP36)
349
350
```python
351
from gpiozero import MCP3008
352
from time import sleep
353
354
# TMP36 temperature sensor on channel 0
355
temp_sensor = MCP3008(channel=0)
356
357
while True:
358
voltage = temp_sensor.voltage
359
# TMP36: 10mV per degree C, 500mV offset, 0°C = 0.5V
360
temperature_c = (voltage - 0.5) * 100
361
temperature_f = temperature_c * 9/5 + 32
362
363
print(f"Temperature: {temperature_c:.1f}°C ({temperature_f:.1f}°F)")
364
sleep(1)
365
```
366
367
### Light Sensor (Photoresistor)
368
369
```python
370
from gpiozero import MCP3008, LED
371
from signal import pause
372
373
# Photoresistor voltage divider on channel 0
374
light_sensor = MCP3008(channel=0)
375
night_light = LED(17)
376
377
def update_light():
378
light_level = light_sensor.value
379
# Turn on LED when it's dark (low light reading)
380
night_light.value = 1 - light_level
381
382
# Update every 100ms
383
light_sensor.when_changed = update_light
384
385
pause()
386
```
387
388
### Differential Reading
389
390
```python
391
from gpiozero import MCP3008
392
393
# Differential reading between channels 0 and 1
394
diff_adc = MCP3008(channel=0, differential=True)
395
396
while True:
397
# This reads the voltage difference between CH0+ and CH0- (CH1)
398
diff_voltage = diff_adc.voltage
399
print(f"Differential voltage: {diff_voltage:.3f}V")
400
sleep(0.1)
401
```
402
403
### Data Logging
404
405
```python
406
from gpiozero import MCP3008
407
import csv
408
import time
409
410
sensors = [MCP3008(channel=i) for i in range(3)]
411
412
with open('sensor_data.csv', 'w', newline='') as csvfile:
413
writer = csv.writer(csvfile)
414
writer.writerow(['timestamp', 'channel_0', 'channel_1', 'channel_2'])
415
416
try:
417
while True:
418
timestamp = time.time()
419
readings = [sensor.voltage for sensor in sensors]
420
writer.writerow([timestamp] + readings)
421
print(f"Logged: {readings}")
422
time.sleep(1)
423
except KeyboardInterrupt:
424
print("Data logging stopped")
425
```
426
427
### Custom Voltage Reference
428
429
```python
430
from gpiozero import MCP3008
431
432
# Using 5V reference instead of default 3.3V
433
adc_5v = MCP3008(channel=0, max_voltage=5.0)
434
435
while True:
436
voltage = adc_5v.voltage # Now scaled to 0-5V range
437
print(f"Voltage (5V ref): {voltage:.2f}V")
438
sleep(0.5)
439
```
440
441
## SPI Configuration
442
443
All MCP3xxx devices support additional SPI configuration parameters:
444
445
```python
446
# Custom SPI configuration
447
adc = MCP3008(
448
channel=0,
449
port=0, # SPI port (usually 0)
450
device=1, # Chip select (CE1 instead of CE0)
451
max_voltage=5.0, # Voltage reference
452
differential=False # Single-ended reading
453
)
454
```
455
456
Common SPI connections on Raspberry Pi:
457
- **MOSI**: GPIO 10 (Pin 19)
458
- **MISO**: GPIO 9 (Pin 21)
459
- **SCLK**: GPIO 11 (Pin 23)
460
- **CE0**: GPIO 8 (Pin 24) - device=0
461
- **CE1**: GPIO 7 (Pin 26) - device=1