]> Repositories - Adafruit_Blinka-hackapet.git/blob - src/adafruit_blinka/microcontroller/nxp_lpc4330/spi.py
37cc6c4aace1081ca481318b66142e09a3992db1
[Adafruit_Blinka-hackapet.git] / src / adafruit_blinka / microcontroller / nxp_lpc4330 / spi.py
1 """SPI Class for NXP LPC4330"""
2 from greatfet import GreatFET
3
4 class SPI:
5     """Custom I2C Class for NXP LPC4330"""
6
7     MSB = 0
8
9     def __init__(self):
10         self._gf = GreatFET()
11         self._frequency = None
12         self.buffer_size = 255
13         self._presets = {
14             204000: (100, 9),
15             408000: (100, 4),
16             680000: (100, 2),
17             1020000: (100, 1),
18             2040000: (50, 1),
19             4250000: (24, 1),
20             8500000: (12, 1),
21             12750000: (8, 1),
22             17000000: (6, 1),
23             20400000: (2, 4),
24             25500000: (4, 1),
25             34000000: (2, 2),
26             51000000: (2, 1),
27             102000000: (2, 0),
28        }
29         
30     # pylint: disable=too-many-arguments
31     def init(
32         self,
33         baudrate=100000,
34         polarity=0,
35         phase=0,
36         bits=8,
37         firstbit=MSB,
38         sck=None,
39         mosi=None,
40         miso=None,
41     ):
42         """Initialize the Port"""
43         # Figure out the mode based on phase and polarity
44         polarity = int(polarity)
45         phase = int(phase)
46         self._mode = (polarity << 1) | phase
47         
48         # Using API due to possible interface change
49         self._spi = self._gf.apis.spi
50         # Check baudrate against presets and adjust to the closest one
51         if self._frequency is None:
52             preset = self._find_closest_preset(baudrate)
53         else:
54             preset = self._presets[self._frequency]
55         clock_prescale_rate, serial_clock_rate = preset
56         self._spi.init(serial_clock_rate, clock_prescale_rate)
57
58         # Set the polarity and phase (the "SPI mode").
59         self._spi.set_clock_polarity_and_phase(self._mode)
60     # pylint: enable=too-many-arguments
61
62     def _find_closest_preset(self, target_frequency):
63         """Loop through self._frequencies and find the closest
64         setting. Return the preset values and set the frequency
65         to the found value
66         """
67         closest_preset = None
68         for frequency in self._presets:
69             preset = self._presets[frequency]
70             if self._frequency is None or abs(frequency - target_frequency) < abs(self._frequency - target_frequency):
71                 self._frequency = frequency
72                 closest_preset = preset
73
74         return closest_preset
75
76     @property
77     def frequency(self):
78         """Return the current frequency"""
79         return self._frequency
80
81     def write(self, buf, start=0, end=None):
82         """Write data from the buffer to SPI"""
83         end = end if end else len(buf)
84         self._transmit(buf[start:end])
85
86     # pylint: disable=unused-argument
87     def readinto(self, buf, start=0, end=None, write_value=0):
88         """Read data from SPI and into the buffer"""
89         end = end if end else len(buf)
90         result = self._transmit([], end - start)
91         for i, b in enumerate(result):
92             buf[start + i] = b
93
94     # pylint: enable=unused-argument
95
96     # pylint: disable=too-many-arguments
97     def write_readinto(
98         self, buffer_out, buffer_in, out_start=0, out_end=None, in_start=0, in_end=None
99     ):
100         """Perform a half-duplex write from buffer_out and then
101         read data into buffer_in
102         """
103         out_end = out_end if out_end else len(buffer_out)
104         in_end = in_end if in_end else len(buffer_in)
105
106         result = self._transmit(buffer_out[out_start:out_end], in_end - in_start)
107         for i, b in enumerate(result):
108             buf[start + i] = b
109         for i, b in enumerate(result):
110             buffer_in[in_start + i] = b
111
112     # pylint: enable=too-many-arguments
113
114     def _transmit(self, data, receive_length=None):
115         data_to_transmit = bytearray(data)
116         data_received = bytearray()
117
118         if receive_length is None:
119             receive_length = len(data)
120
121         # If we need to receive more than we've transmitted, extend the data out.
122         if receive_length > len(data):
123             padding = receive_length - len(data)
124             data_to_transmit.extend([0] * padding)
125
126         # Transmit our data in chunks of the buffer size.
127         while data_to_transmit:
128             # Extract a single data chunk from the transmit buffer.
129             chunk = data_to_transmit[0:self.buffer_size]
130             del data_to_transmit[0:self.buffer_size]
131
132             # Finally, exchange the data.
133             response = self._spi.clock_data(len(chunk), bytes(chunk))
134             data_received.extend(response)
135
136         # Once we're done, return the data received.
137         return bytes(data_received)