forked from adafruit/Adafruit_CircuitPython_Register_SPI
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathspi_bits.py
More file actions
111 lines (92 loc) · 3.85 KB
/
spi_bits.py
File metadata and controls
111 lines (92 loc) · 3.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
# SPDX-FileCopyrightText: Copyright (c) 2022 Max Holliday for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`adafruit_register_spi.spi_bits`
====================================================
Multi bit registers
* Author(s): Scott Shawcroft
* Adaptation by Max Holliday
"""
import time
class RWBits:
"""
Multibit register (less than a full byte) that is readable and writeable.
This must be within a byte register.
Values are `int` between 0 and 2 ** ``num_bits`` - 1.
:param int num_bits: The number of bits in the field.
:param int register_address: The register address to read the bit from
:param type lowest_bit: The lowest bits index within the byte at ``register_address``
:param int register_width: The number of bytes in the register. Defaults to 1.
:param bool lsb_first: Is the first byte we read from SPI the LSB? Defaults to true
"""
# pylint: disable=too-many-arguments
def __init__(
self,
num_bits,
register_address,
lowest_bit,
register_width=1,
lsb_first=True,
):
self.bit_mask = ((1 << num_bits) - 1) << lowest_bit
if self.bit_mask >= 1 << (register_width * 8):
raise ValueError("Cannot have more bits than register size")
self.lowest_bit = lowest_bit
self.buffer = bytearray(1 + register_width)
self.buffer[0] = register_address
self.buffer[1] = register_width - 1
self.lsb_first = lsb_first
def _shift_rw_cmd_bit_into_address_byte(self, bit_value):
if bit_value not in {0, 1}:
raise ValueError("bit_value must be 0 or 1")
# Clear the MSB (set bit 7 to 0)
cleared_byte = self.buffer[0] & 0x7F
# Set the MSB to the desired bit value
self.buffer[0] = cleared_byte | (bit_value << 7)
def __get__(self, obj, objtype=None):
with obj.spi_device as spi:
self._shift_rw_cmd_bit_into_address_byte(1)
spi.write(self.buffer, end=1)
time.sleep(0.01)
spi.readinto(self.buffer, start=1)
# read the number of bytes into a single variable
reg = 0
order = range(len(self.buffer) - 1, 0, -1)
if not self.lsb_first:
order = reversed(order)
for i in order:
reg = (reg << 8) | self.buffer[i]
return (reg & self.bit_mask) >> self.lowest_bit
def __set__(self, obj, value):
value <<= self.lowest_bit # shift the value over to the right spot
with obj.spi_device as spi:
self._shift_rw_cmd_bit_into_address_byte(1)
spi.write(self.buffer, end=1)
spi.readinto(self.buffer, start=1)
reg = 0
order = range(len(self.buffer) - 1, 0, -1)
if not self.lsb_first:
order = range(1, len(self.buffer))
for i in order:
reg = (reg << 8) | self.buffer[i]
reg &= ~self.bit_mask # mask off the bits we're about to change
reg |= value # then or in our new value
for i in reversed(order):
self.buffer[i] = reg & 0xFF
reg >>= 8
self._shift_rw_cmd_bit_into_address_byte(0)
spi.write(self.buffer)
class ROBits(RWBits):
"""
Multibit register (less than a full byte) that is read-only. This must be
within a byte register.
Values are `int` between 0 and 2 ** ``num_bits`` - 1.
:param int num_bits: The number of bits in the field.
:param int register_address: The register address to read the bit from
:param type lowest_bit: The lowest bits index within the byte at ``register_address``
:param int register_width: The number of bytes in the register. Defaults to 1.
"""
def __set__(self, obj, value):
raise AttributeError()