Coverage for /usr/lib/python3/dist-packages/gpiozero/spi_devices.py: 34%

161 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2024-02-10 12:38 +0000

1# vim: set fileencoding=utf-8: 

2# 

3# GPIO Zero: a library for controlling the Raspberry Pi's GPIO pins 

4# 

5# Copyright (c) 2016-2021 Dave Jones <dave@waveform.org.uk> 

6# Copyright (c) 2020 Grzegorz Szymaszek <gszymaszek@short.pl> 

7# Copyright (c) 2016-2019 Andrew Scheller <github@loowis.durge.org> 

8# Copyright (c) 2016-2018 Ben Nuttall <ben@bennuttall.com> 

9# 

10# SPDX-License-Identifier: BSD-3-Clause 

11 

12from __future__ import ( 

13 unicode_literals, 

14 print_function, 

15 absolute_import, 

16 division, 

17 ) 

18str = type('') 

19 

20 

21from math import log, ceil 

22from operator import or_ 

23try: 

24 from functools import reduce 

25except ImportError: 

26 pass # py2's reduce is built-in 

27 

28from .exc import DeviceClosed, SPIBadChannel, InputDeviceError 

29from .devices import Device 

30 

31 

32class SPIDevice(Device): 

33 """ 

34 Extends :class:`Device`. Represents a device that communicates via the SPI 

35 protocol. 

36 

37 See :ref:`spi_args` for information on the keyword arguments that can be 

38 specified with the constructor. 

39 """ 

40 def __init__(self, **spi_args): 

41 self._spi = None 

42 super(SPIDevice, self).__init__( 

43 pin_factory=spi_args.pop('pin_factory', None) 

44 ) 

45 self._spi = self.pin_factory.spi(**spi_args) 

46 

47 def close(self): 

48 if getattr(self, '_spi', None): 

49 self._spi.close() 

50 self._spi = None 

51 super(SPIDevice, self).close() 

52 

53 @property 

54 def closed(self): 

55 return self._spi is None 

56 

57 def _int_to_words(self, pattern): 

58 """ 

59 Given a bit-pattern expressed an integer number, return a sequence of 

60 the individual words that make up the pattern. The number of bits per 

61 word will be obtained from the internal SPI interface. 

62 """ 

63 try: 

64 bits_required = int(ceil(log(pattern, 2))) + 1 

65 except ValueError: 

66 # pattern == 0 (technically speaking, no bits are required to 

67 # transmit the value zero ;) 

68 bits_required = 1 

69 shifts = range(0, bits_required, self._spi.bits_per_word)[::-1] 

70 mask = 2 ** self._spi.bits_per_word - 1 

71 return [(pattern >> shift) & mask for shift in shifts] 

72 

73 def _words_to_int(self, words, expected_bits=None): 

74 """ 

75 Given a sequence of words which each fit in the internal SPI 

76 interface's number of bits per word, returns the value obtained by 

77 concatenating each word into a single bit-string. 

78 

79 If *expected_bits* is specified, it limits the size of the output to 

80 the specified number of bits (by masking off bits above the expected 

81 number). If unspecified, no limit will be applied. 

82 """ 

83 if expected_bits is None: 

84 expected_bits = len(words) * self._spi.bits_per_word 

85 shifts = range(0, expected_bits, self._spi.bits_per_word)[::-1] 

86 mask = 2 ** expected_bits - 1 

87 return reduce(or_, (word << shift for word, shift in zip(words, shifts))) & mask 

88 

89 def __repr__(self): 

90 try: 

91 self._check_open() 

92 return "<gpiozero.%s object using %r>" % (self.__class__.__name__, self._spi) 

93 except DeviceClosed: 

94 return "<gpiozero.%s object closed>" % self.__class__.__name__ 

95 

96 

97class AnalogInputDevice(SPIDevice): 

98 """ 

99 Represents an analog input device connected to SPI (serial interface). 

100 

101 Typical analog input devices are `analog to digital converters`_ (ADCs). 

102 Several classes are provided for specific ADC chips, including 

103 :class:`MCP3004`, :class:`MCP3008`, :class:`MCP3204`, and :class:`MCP3208`. 

104 

105 The following code demonstrates reading the first channel of an MCP3008 

106 chip attached to the Pi's SPI pins:: 

107 

108 from gpiozero import MCP3008 

109 

110 pot = MCP3008(0) 

111 print(pot.value) 

112 

113 The :attr:`value` attribute is normalized such that its value is always 

114 between 0.0 and 1.0 (or in special cases, such as differential sampling, 

115 -1 to +1). Hence, you can use an analog input to control the brightness of 

116 a :class:`PWMLED` like so:: 

117 

118 from gpiozero import MCP3008, PWMLED 

119 

120 pot = MCP3008(0) 

121 led = PWMLED(17) 

122 led.source = pot 

123 

124 The :attr:`voltage` attribute reports values between 0.0 and *max_voltage* 

125 (which defaults to 3.3, the logic level of the GPIO pins). 

126 

127 .. _analog to digital converters: https://en.wikipedia.org/wiki/Analog-to-digital_converter 

128 """ 

129 

130 def __init__(self, bits, max_voltage=3.3, **spi_args): 

131 if bits is None: 

132 raise InputDeviceError('you must specify the bit resolution of the device') 

133 self._bits = bits 

134 self._min_value = -(2 ** bits) 

135 self._range = 2 ** (bits + 1) - 1 

136 if max_voltage <= 0: 

137 raise InputDeviceError('max_voltage must be positive') 

138 self._max_voltage = float(max_voltage) 

139 super(AnalogInputDevice, self).__init__(shared=True, **spi_args) 

140 

141 @property 

142 def bits(self): 

143 """ 

144 The bit-resolution of the device/channel. 

145 """ 

146 return self._bits 

147 

148 def _read(self): 

149 raise NotImplementedError 

150 

151 @property 

152 def value(self): 

153 """ 

154 The current value read from the device, scaled to a value between 0 and 

155 1 (or -1 to +1 for certain devices operating in differential mode). 

156 """ 

157 return (2 * (self._read() - self._min_value) / self._range) - 1 

158 

159 @property 

160 def raw_value(self): 

161 """ 

162 The raw value as read from the device. 

163 """ 

164 return self._read() 

165 

166 @property 

167 def max_voltage(self): 

168 """ 

169 The voltage required to set the device's value to 1. 

170 """ 

171 return self._max_voltage 

172 

173 @property 

174 def voltage(self): 

175 """ 

176 The current voltage read from the device. This will be a value between 

177 0 and the *max_voltage* parameter specified in the constructor. 

178 """ 

179 return self.value * self._max_voltage 

180 

181 

182class MCP3xxx(AnalogInputDevice): 

183 """ 

184 Extends :class:`AnalogInputDevice` to implement an interface for all ADC 

185 chips with a protocol similar to the Microchip MCP3xxx series of devices. 

186 """ 

187 

188 def __init__(self, channel=0, bits=10, differential=False, max_voltage=3.3, 

189 **spi_args): 

190 self._channel = channel 

191 self._differential = bool(differential) 

192 super(MCP3xxx, self).__init__(bits, max_voltage, **spi_args) 

193 

194 @property 

195 def channel(self): 

196 """ 

197 The channel to read data from. The MCP3008/3208/3304 have 8 channels 

198 (0-7), while the MCP3004/3204/3302 have 4 channels (0-3), the 

199 MCP3002/3202 have 2 channels (0-1), and the MCP3001/3201/3301 only 

200 have 1 channel. 

201 """ 

202 return self._channel 

203 

204 @property 

205 def differential(self): 

206 """ 

207 If ``True``, the device is operated in differential mode. In this mode 

208 one channel (specified by the channel attribute) is read relative to 

209 the value of a second channel (implied by the chip's design). 

210 

211 Please refer to the device data-sheet to determine which channel is 

212 used as the relative base value (for example, when using an 

213 :class:`MCP3008` in differential mode, channel 0 is read relative to 

214 channel 1). 

215 """ 

216 return self._differential 

217 

218 def _read(self): 

219 return self._words_to_int( 

220 self._spi.transfer(self._send())[-2:], self.bits 

221 ) 

222 

223 def _send(self): 

224 # MCP3004/08 protocol looks like the following: 

225 # 

226 # Byte 0 1 2 

227 # ==== ======== ======== ======== 

228 # Tx 00000001 MCCCxxxx xxxxxxxx 

229 # Rx xxxxxxxx xxxxx0RR RRRRRRRR 

230 # 

231 # MCP3204/08 protocol looks like the following: 

232 # 

233 # Byte 0 1 2 

234 # ==== ======== ======== ======== 

235 # Tx 000001MC CCxxxxxx xxxxxxxx 

236 # Rx xxxxxxxx xxx0RRRR RRRRRRRR 

237 # 

238 # The transmit bits start with several preamble "0" bits, the number 

239 # of which is determined by the amount required to align the last byte 

240 # of the result with the final byte of output. A start "1" bit is then 

241 # transmitted, followed by the single/differential bit (M); 1 for 

242 # single-ended read, 0 for differential read. Next comes three bits for 

243 # channel (C). 

244 # 

245 # Read-out begins with a don't care bit (x), then a null bit (0) 

246 # followed by the result bits (R). All other bits are don't care (x). 

247 # 

248 # The 3x01 variant of the chips always operates in differential mode 

249 # and effectively only has one channel (composed of an IN+ and IN-). As 

250 # such it requires no input, just output. 

251 return self._int_to_words( 

252 (0b10000 | (not self.differential) << 3 | self.channel) << (self.bits + 2) 

253 ) 

254 

255 

256class MCP3xx2(MCP3xxx): 

257 def _send(self): 

258 # MCP3002 protocol looks like the following: 

259 # 

260 # Byte 0 1 

261 # ==== ======== ======== 

262 # Tx 01MCLxxx xxxxxxxx 

263 # Rx xxxxx0RR RRRRRRRR for the 3002 

264 # 

265 # MCP3202 protocol looks like the following: 

266 # 

267 # Byte 0 1 2 

268 # ==== ======== ======== ======== 

269 # Tx 00000001 MCLxxxxx xxxxxxxx 

270 # Rx xxxxxxxx xxx0RRRR RRRRRRRR 

271 # 

272 # The transmit bits start with several preamble "0" bits, the number of 

273 # which is determined by the amount required to align the last byte of 

274 # the result with the final byte of output. A start "1" bit is then 

275 # transmitted, followed by the single/differential bit (M); 1 for 

276 # single-ended read, 0 for differential read. Next comes a single bit 

277 # for channel (C) then the MSBF bit (L) which selects whether the data 

278 # will be read out in MSB form only (1) or whether LSB read-out will 

279 # occur after MSB read-out (0). 

280 # 

281 # Read-out begins with a null bit (0) followed by the result bits (R). 

282 # All other bits are don't care (x). 

283 return self._int_to_words( 

284 (0b1001 | (not self.differential) << 2 | self.channel << 1) << (self.bits + 1) 

285 ) 

286 

287 

288class MCP30xx(MCP3xxx): 

289 """ 

290 Extends :class:`MCP3xxx` to implement an interface for all ADC 

291 chips with a protocol similar to the Microchip MCP30xx series of devices. 

292 """ 

293 

294 def __init__(self, channel=0, differential=False, max_voltage=3.3, 

295 **spi_args): 

296 super(MCP30xx, self).__init__(channel, 10, differential, max_voltage, 

297 **spi_args) 

298 

299 

300class MCP32xx(MCP3xxx): 

301 """ 

302 Extends :class:`MCP3xxx` to implement an interface for all ADC 

303 chips with a protocol similar to the Microchip MCP32xx series of devices. 

304 """ 

305 

306 def __init__(self, channel=0, differential=False, max_voltage=3.3, **spi_args): 

307 super(MCP32xx, self).__init__(channel, 12, differential, max_voltage, 

308 **spi_args) 

309 

310 

311class MCP33xx(MCP3xxx): 

312 """ 

313 Extends :class:`MCP3xxx` with functionality specific to the MCP33xx family 

314 of ADCs; specifically this handles the full differential capability of 

315 these chips supporting the full 13-bit signed range of output values. 

316 """ 

317 

318 def __init__(self, channel=0, differential=False, max_voltage=3.3, **spi_args): 

319 super(MCP33xx, self).__init__(channel, 12, differential, max_voltage, 

320 **spi_args) 

321 

322 def _read(self): 

323 if self.differential: 

324 result = self._words_to_int( 

325 self._spi.transfer(self._send())[-2:], self.bits + 1) 

326 # Account for the sign bit 

327 if result > 4095: 

328 return -(8192 - result) 

329 else: 

330 return result 

331 else: 

332 return super(MCP33xx, self)._read() 

333 

334 def _send(self): 

335 # MCP3302/04 protocol looks like the following: 

336 # 

337 # Byte 0 1 2 

338 # ==== ======== ======== ======== 

339 # Tx 00001MCC Cxxxxxxx xxxxxxxx 

340 # Rx xxxxxxxx xx0SRRRR RRRRRRRR 

341 # 

342 # The transmit bits start with 4 preamble bits "0000", a start bit "1" 

343 # followed by the single/differential bit (M) which is 1 for 

344 # single-ended read, and 0 for differential read, followed by 3-bits 

345 # for the channel (C). The remainder of the transmission are "don't 

346 # care" bits (x). 

347 # 

348 # The first byte received and the top 2 bits of the second byte are 

349 # don't care bits (x). These are followed by a null bit (0), then the 

350 # sign bit (S), and then the 12 result bits (R). 

351 # 

352 # In single read mode (the default) the sign bit is always zero and the 

353 # result is effectively 12-bits. In differential mode, the sign bit is 

354 # significant and the result is a two's-complement 13-bit value. 

355 # 

356 # The MCP3301 variant operates similarly to the other MCP3x01 variants; 

357 # no input, just output and always differential. 

358 return self._int_to_words( 

359 (0b10000 | (not self.differential) << 3 | self.channel) << (self.bits + 3) 

360 ) 

361 

362 @property 

363 def differential(self): 

364 """ 

365 If ``True``, the device is operated in differential mode. In this mode 

366 one channel (specified by the channel attribute) is read relative to 

367 the value of a second channel (implied by the chip's design). 

368 

369 Please refer to the device data-sheet to determine which channel is 

370 used as the relative base value (for example, when using an 

371 :class:`MCP3304` in differential mode, channel 0 is read relative to 

372 channel 1). 

373 """ 

374 return super(MCP33xx, self).differential 

375 

376 @property 

377 def value(self): 

378 """ 

379 The current value read from the device, scaled to a value between 0 and 

380 1 (or -1 to +1 for devices operating in differential mode). 

381 """ 

382 return super(MCP33xx, self).value 

383 

384 

385class MCP3001(MCP30xx): 

386 """ 

387 The `MCP3001`_ is a 10-bit analog to digital converter with 1 channel. 

388 Please note that the MCP3001 always operates in differential mode, 

389 measuring the value of IN+ relative to IN-. 

390 

391 .. _MCP3001: http://www.farnell.com/datasheets/630400.pdf 

392 """ 

393 def __init__(self, max_voltage=3.3, **spi_args): 

394 super(MCP3001, self).__init__(0, True, max_voltage, **spi_args) 

395 

396 def _read(self): 

397 # MCP3001 protocol looks like the following: 

398 # 

399 # Byte 0 1 

400 # ==== ======== ======== 

401 # Rx xx0RRRRR RRRRRxxx 

402 return self._words_to_int(self._spi.read(2), 13) >> 3 

403 

404 

405class MCP3002(MCP30xx, MCP3xx2): 

406 """ 

407 The `MCP3002`_ is a 10-bit analog to digital converter with 2 channels 

408 (0-1). 

409 

410 .. _MCP3002: http://www.farnell.com/datasheets/1599363.pdf 

411 """ 

412 def __init__(self, channel=0, differential=False, max_voltage=3.3, **spi_args): 

413 if not 0 <= channel < 2: 

414 raise SPIBadChannel('channel must be 0 or 1') 

415 super(MCP3002, self).__init__(channel, differential, max_voltage, **spi_args) 

416 

417 

418class MCP3004(MCP30xx): 

419 """ 

420 The `MCP3004`_ is a 10-bit analog to digital converter with 4 channels 

421 (0-3). 

422 

423 .. _MCP3004: http://www.farnell.com/datasheets/808965.pdf 

424 """ 

425 def __init__(self, channel=0, differential=False, max_voltage=3.3, **spi_args): 

426 if not 0 <= channel < 4: 

427 raise SPIBadChannel('channel must be between 0 and 3') 

428 super(MCP3004, self).__init__(channel, differential, max_voltage, **spi_args) 

429 

430 

431class MCP3008(MCP30xx): 

432 """ 

433 The `MCP3008`_ is a 10-bit analog to digital converter with 8 channels 

434 (0-7). 

435 

436 .. _MCP3008: http://www.farnell.com/datasheets/808965.pdf 

437 """ 

438 def __init__(self, channel=0, differential=False, max_voltage=3.3, **spi_args): 

439 if not 0 <= channel < 8: 

440 raise SPIBadChannel('channel must be between 0 and 7') 

441 super(MCP3008, self).__init__(channel, differential, max_voltage, **spi_args) 

442 

443 

444class MCP3201(MCP32xx): 

445 """ 

446 The `MCP3201`_ is a 12-bit analog to digital converter with 1 channel. 

447 Please note that the MCP3201 always operates in differential mode, 

448 measuring the value of IN+ relative to IN-. 

449 

450 .. _MCP3201: http://www.farnell.com/datasheets/1669366.pdf 

451 """ 

452 def __init__(self, max_voltage=3.3, **spi_args): 

453 super(MCP3201, self).__init__(0, True, max_voltage, **spi_args) 

454 

455 def _read(self): 

456 # MCP3201 protocol looks like the following: 

457 # 

458 # Byte 0 1 

459 # ==== ======== ======== 

460 # Rx xx0RRRRR RRRRRRRx 

461 return self._words_to_int(self._spi.read(2), 13) >> 1 

462 

463 

464class MCP3202(MCP32xx, MCP3xx2): 

465 """ 

466 The `MCP3202`_ is a 12-bit analog to digital converter with 2 channels 

467 (0-1). 

468 

469 .. _MCP3202: http://www.farnell.com/datasheets/1669376.pdf 

470 """ 

471 def __init__(self, channel=0, differential=False, max_voltage=3.3, **spi_args): 

472 if not 0 <= channel < 2: 

473 raise SPIBadChannel('channel must be 0 or 1') 

474 super(MCP3202, self).__init__(channel, differential, max_voltage, **spi_args) 

475 

476 

477class MCP3204(MCP32xx): 

478 """ 

479 The `MCP3204`_ is a 12-bit analog to digital converter with 4 channels 

480 (0-3). 

481 

482 .. _MCP3204: http://www.farnell.com/datasheets/808967.pdf 

483 """ 

484 def __init__(self, channel=0, differential=False, max_voltage=3.3, **spi_args): 

485 if not 0 <= channel < 4: 

486 raise SPIBadChannel('channel must be between 0 and 3') 

487 super(MCP3204, self).__init__(channel, differential, max_voltage, **spi_args) 

488 

489 

490class MCP3208(MCP32xx): 

491 """ 

492 The `MCP3208`_ is a 12-bit analog to digital converter with 8 channels 

493 (0-7). 

494 

495 .. _MCP3208: http://www.farnell.com/datasheets/808967.pdf 

496 """ 

497 def __init__(self, channel=0, differential=False, max_voltage=3.3, **spi_args): 

498 if not 0 <= channel < 8: 

499 raise SPIBadChannel('channel must be between 0 and 7') 

500 super(MCP3208, self).__init__(channel, differential, max_voltage, **spi_args) 

501 

502 

503class MCP3301(MCP33xx): 

504 """ 

505 The `MCP3301`_ is a signed 13-bit analog to digital converter. Please note 

506 that the MCP3301 always operates in differential mode measuring the 

507 difference between IN+ and IN-. Its output value is scaled from -1 to +1. 

508 

509 .. _MCP3301: http://www.farnell.com/datasheets/1669397.pdf 

510 """ 

511 def __init__(self, max_voltage=3.3, **spi_args): 

512 super(MCP3301, self).__init__(0, True, max_voltage, **spi_args) 

513 

514 def _read(self): 

515 # MCP3301 protocol looks like the following: 

516 # 

517 # Byte 0 1 

518 # ==== ======== ======== 

519 # Rx xx0SRRRR RRRRRRRR 

520 result = self._words_to_int(self._spi.read(2), 13) 

521 # Account for the sign bit 

522 if result > 4095: 

523 return -(8192 - result) 

524 else: 

525 return result 

526 

527 

528class MCP3302(MCP33xx): 

529 """ 

530 The `MCP3302`_ is a 12/13-bit analog to digital converter with 4 channels 

531 (0-3). When operated in differential mode, the device outputs a signed 

532 13-bit value which is scaled from -1 to +1. When operated in single-ended 

533 mode (the default), the device outputs an unsigned 12-bit value scaled from 

534 0 to 1. 

535 

536 .. _MCP3302: http://www.farnell.com/datasheets/1486116.pdf 

537 """ 

538 def __init__(self, channel=0, differential=False, max_voltage=3.3, **spi_args): 

539 if not 0 <= channel < 4: 

540 raise SPIBadChannel('channel must be between 0 and 4') 

541 super(MCP3302, self).__init__(channel, differential, max_voltage, **spi_args) 

542 

543 

544class MCP3304(MCP33xx): 

545 """ 

546 The `MCP3304`_ is a 12/13-bit analog to digital converter with 8 channels 

547 (0-7). When operated in differential mode, the device outputs a signed 

548 13-bit value which is scaled from -1 to +1. When operated in single-ended 

549 mode (the default), the device outputs an unsigned 12-bit value scaled from 

550 0 to 1. 

551 

552 .. _MCP3304: http://www.farnell.com/datasheets/1486116.pdf 

553 """ 

554 def __init__(self, channel=0, differential=False, max_voltage=3.3, **spi_args): 

555 if not 0 <= channel < 8: 

556 raise SPIBadChannel('channel must be between 0 and 7') 

557 super(MCP3304, self).__init__(channel, differential, max_voltage, **spi_args)