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