-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpython_i2c.py
192 lines (159 loc) · 4.93 KB
/
python_i2c.py
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# import pyftdi
from pyftdi.gpio import GpioController, GpioException
class I2CPort:
"""Class that opens an I2C port in a bit-bang way and inits the bus."""
mask = 0x13 # in, in,in Out, In, In, out, out
def __init__(self, gpio, inmask=mask):
self.gpio = gpio
self.gpio.set_direction(0xFF, inmask)
self.mask = inmask
self.i2c_init()
def i2c_init(self):
"""Initialises the bus."""
self.gpio.write_port(0xff & self.mask)
class I2CDevice:
"""A class for handling a single device on a I2C bus.
Uses bitbang GPIO, which results in unreliable timings (also is horribly slow), but was tested without any problems on the Kasli board.
"""
def __init__(self, port, address):
"""Initialises a member of the class.
:param port: I2C port from I2CPort class.
:param address: Address of the device on the I2C bus (without R/W bit).
"""
self.address = address
self.port = port
self.gpio = self.port.gpio
self.mask = self.port.mask
def i2c_start(self):
"""Sets condition of I2C transaction."""
self.gpio.write_port(0x11 & self.mask)
self.gpio.write_port(0x10 & self.mask)
def i2c_ack(self):
"""Acknowledges transaction."""
self.gpio.write_port(0x10 & self.mask)
self.gpio.write_port(0x11 & self.mask)
def i2c_read_ack(self):
"""Checks if transaction is acknowledged.
:return: True if ACK, False if NACK
"""
self.gpio.set_direction(0xFF, 0x11)
self.gpio.write_port(0x10 & self.mask)
self.gpio.write_port(0x11 & self.mask)
pins = self.gpio.read_port()
# print(pins)
self.gpio.set_direction(0xFF, self.mask)
if not (pins & 0x02):
return True
else:
return False
def i2c_write_bit(self, bit):
"""Writes a single bit on the bus."""
self.gpio.write_port((0x10 + (bit << 1) & self.mask))
self.gpio.write_port((0x11 + (bit << 1) & self.mask))
self.gpio.write_port((0x10 + (bit << 1) & self.mask))
def i2c_read_bit(self):
"""Reads a single bit from the bus.
:return: Bit that was read from the bus.
"""
self.gpio.write_port(0x10)
self.gpio.write_port(0x11)
pins = self.gpio.read_port()
self.gpio.write_port(0x10)
return (pins & 0x02) >> 1
def i2c_end(self):
"""Sets an end condition on bus."""
self.gpio.write_port(0x10 & self.mask)
self.gpio.write_port(0x11 & self.mask)
self.gpio.write_port(0x13 & self.mask)
def i2c_write_address(self, write, address):
"""Writes address with R/W bit at the end.
:param write: R/W bit
:param address: Address to write to bus.
:return: True if ACK, False if NACK.
"""
self.i2c_start()
for i in range(0, 7):
self.i2c_write_bit((address >> (6-i)) & 1)
# print((address >> (6-i)) & 1)
self.i2c_write_bit(write)
v = self.i2c_read_ack()
return v
def i2c_write_byte(self, byte):
"""Writes a single byte to the bus.
:return: True if ACK, False if NACK.
"""
# i2c_start(self.gpio)
for i in range(0, 8):
self.i2c_write_bit((byte >> (7-i)) & 1)
# print((byte >> (7-i)) & 1)
v = self.i2c_read_ack()
return v
def i2c_read_byte(self):
"""Reads a single byte from the bus.
:return: Byte that was read.
"""
self.gpio.set_direction(0xFF, 0x11)
byte = 0x00
for i in range(0, 8):
bit = self.i2c_read_bit()
# print(bit)
byte += bit << (7-i)
self.gpio.set_direction(0xFF, self.mask)
self.i2c_ack()
self.i2c_end()
# print(byte)
return byte
def i2c_read_byte_from(self):
"""Read a single byte from this device (includes writing an address with R bit).
:return: Byte that was read.
"""
v = self.i2c_write_address(1, self.address)
byte = self.i2c_read_byte()
if not v:
print("Error")
return byte
def i2c_write_byte_to(self, byte):
"""Writes a single byte to this device (includes writing an address with W bit).
:return: True if ACK, False if NACK.
"""
v = self.i2c_write_address(0, self.address)
v &= self.i2c_write_byte(byte)
self.i2c_end()
return v
def i2c_write_to_reg(self, reg, byte):
"""Writes a single byte to specified register.
:param reg: Register number to which the byte will be written.
:param byte: Byte to be written.
:return: True if ACK, False if NACK on any of transactions.
"""
v = self.i2c_write_address(0, self.address)
v &= self.i2c_write_byte(reg)
v &= self.i2c_write_byte(byte)
if not v:
print("Error writing to %d register" % reg)
self.i2c_end()
return v
def i2c_read_from_reg(self, reg):
"""Reads a single byte from specified register.
:param reg: Register to be read.
:return: Byte that was read.
"""
v = self.i2c_write_address(0, self.address)
v &= self.i2c_write_byte(reg)
self.i2c_end()
v &= self.i2c_write_address(1, self.address)
byte = self.i2c_read_byte()
if not v:
print("Error")
self.i2c_end()
return byte
if __name__ == '__main__':
mask = 0x13 # in, in,in Out, In, In, out, out
gpio = GpioController()
gpio.open_from_url('ftdi://ftdi:4232h/1', mask)
port = I2CPort(gpio)
switch2 = I2CDevice(port, 0x71)
switch2.i2c_write_byte_to(0x04)
i = switch2.i2c_read_byte_from()
print("%x" % i)
gpio.close()