Coverage for /usr/lib/python3/dist-packages/gpiozero/pins/spi.py: 14%
67 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-02-10 12:38 +0000
« 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#
7# SPDX-License-Identifier: BSD-3-Clause
9from __future__ import (
10 unicode_literals,
11 print_function,
12 absolute_import,
13 division,
14 )
15str = type('')
18import operator
19from threading import RLock
21from ..devices import Device, SharedMixin
22from ..input_devices import InputDevice
23from ..output_devices import OutputDevice
26class SPISoftwareBus(SharedMixin, Device):
27 def __init__(self, clock_pin, mosi_pin, miso_pin):
28 self.lock = None
29 self.clock = None
30 self.mosi = None
31 self.miso = None
32 super(SPISoftwareBus, self).__init__()
33 self.lock = RLock()
34 try:
35 self.clock = OutputDevice(clock_pin, active_high=True)
36 if mosi_pin is not None:
37 self.mosi = OutputDevice(mosi_pin)
38 if miso_pin is not None:
39 self.miso = InputDevice(miso_pin)
40 except:
41 self.close()
42 raise
44 def close(self):
45 super(SPISoftwareBus, self).close()
46 if getattr(self, 'lock', None):
47 with self.lock:
48 if self.miso is not None:
49 self.miso.close()
50 self.miso = None
51 if self.mosi is not None:
52 self.mosi.close()
53 self.mosi = None
54 if self.clock is not None:
55 self.clock.close()
56 self.clock = None
57 self.lock = None
59 @property
60 def closed(self):
61 return self.lock is None
63 @classmethod
64 def _shared_key(cls, clock_pin, mosi_pin, miso_pin):
65 return (clock_pin, mosi_pin, miso_pin)
67 def transfer(self, data, clock_phase=False, lsb_first=False, bits_per_word=8):
68 """
69 Writes data (a list of integer words where each word is assumed to have
70 :attr:`bits_per_word` bits or less) to the SPI interface, and reads an
71 equivalent number of words, returning them as a list of integers.
72 """
73 result = []
74 with self.lock:
75 # See https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus
76 # (specifically the section "Example of bit-banging the master
77 # protocol") for a simpler C implementation of this which ignores
78 # clock polarity, phase, variable word-size, and multiple input
79 # words
80 if lsb_first:
81 shift = operator.lshift
82 init_mask = 1
83 else:
84 shift = operator.rshift
85 init_mask = 1 << (bits_per_word - 1)
86 for write_word in data:
87 mask = init_mask
88 read_word = 0
89 for _ in range(bits_per_word):
90 if self.mosi is not None:
91 self.mosi.value = bool(write_word & mask)
92 # read bit on clock activation
93 self.clock.on()
94 if not clock_phase:
95 if self.miso is not None and self.miso.value:
96 read_word |= mask
97 # read bit on clock deactivation
98 self.clock.off()
99 if clock_phase:
100 if self.miso is not None and self.miso.value:
101 read_word |= mask
102 mask = shift(mask, 1)
103 result.append(read_word)
104 return result