uC chip interface arduino  0.9.0
A interface for async and neuromrphic IC testing
Loading...
Searching...
No Matches
interface_i2c.py
Go to the documentation of this file.
2# This file is part of the Firmware project to interface with small Async or Neuromorphic chips
3# Copyright (C) 2023 Ole Richter - University of Groningen
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18
19
20from .header import ConfigMainHeader, DataI2CHeader, ConfigSubHeader
21from .packet import ConfigPacket, DataI2CPacket
22import logging
23
25 """ This class is the API for the I2C interfaces of the uC
26 It is used to configure, send and recive data from the I2C interfaces
27 """
28 def __init__(self, api_object, interface_id):
29 """ Constructor for the I2C interface
30 @param api_object: the parent API object
31 @param interface_id: the id of the I2C interface
32 """
33 # the status of the I2C interface, and the time of when this status was processed by the uC
34 # 0 means not activated
35 # 1 means activation pending
36 # 2 means activted
37 # -1 means error
38 self.__status = 0
39 self.__status_timestamp = 0
40 # the protocol data word width of the I2C interface, and the time of when this status was processed by the uC
41 self.__number_of_bytes = 0
43 # the speed of the I2C interface, and the time of when this status was processed by the uC
44 # 10000, 100000, 400000, 1000000, 3400000
45 self.__speed = 0
46 self.__speed_timestamp = 0
47 # the byte order of the I2C interface, and the time of when this status was processed by the uC
48 self.__order = "NONE"
49 self.__order_timestamp = 0
50 # the data recived from the chip, and the time it was processed by the uC
51 self.__data_from_chip = []
53 # the data send to the chip, and the time it was processed by the uC
54 self.__data_to_chip = []
55 self.__data_to_chip_times = []
56 # the errors and unhandled packets reported by the uC
57 self.__errors = []
58 # the parent API object
59 self.__api = api_object
60 # the headers this I2C interface object is responsible for
61 if interface_id == 0:
62 self.__header = [ConfigMainHeader.IN_CONF_I2C0, DataI2CHeader.IN_I2C0, DataI2CHeader.OUT_I2C0]
63 elif interface_id == 1:
64 self.__header = [ConfigMainHeader.IN_CONF_I2C1, DataI2CHeader.IN_I2C1, DataI2CHeader.OUT_I2C1]
65 elif interface_id == 2:
66 self.__header = [ConfigMainHeader.IN_CONF_I2C2, DataI2CHeader.IN_I2C2, DataI2CHeader.OUT_I2C2]
67 else:
68 logging.error("I2C only up to 3 interfaces are supported at the moment")
69
70 def header(self):
71 """ Returns the headers this I2C interface object is responsible for
72 @return: the headers this I2C interface object is responsible for
73 """
74 return self.__header
75
76 def status(self):
77 """ Returns the status of the I2C interface, and the time of when this status was processed by the uC
78 @return: (state_str,timestamp) where state_str is the status of the I2C interface, and timestamp is the time of when this status was processed by the uC
79 """
80 self.update()
81 state_str = ("active" if self.__status == 2 else ("activation pending" if self.__status == 1 else ("not active" if self.__status == 0 else "error" )))
82 return (state_str,self.__status_timestamp)
83
84 def number_of_bytes(self):
85 """ Returns the protocol data word width of the I2C interface, and the time of when this status was processed by the uC
86 @return: (number_of_bytes,timestamp) where number_of_bytes is the protocol data word width of the I2C interface, and timestamp is the time of when this status was processed by the uC
87 """
88 self.update()
90
91 def speed(self):
92 """ Returns the speed of the I2C interface, and the time of when this status was processed by the uC
93 @return: (speed,timestamp) where speed is the speed of the I2C interface, and timestamp is the time of when this status was processed by the uC
94 """
95 self.update()
96 return (self.__speed,self.__speed_timestamp)
97
98 def byte_order(self):
99 """ Returns the byte order of the I2C interface, and the time of when this status was processed by the uC
100 @return: (order,timestamp) where order is the byte order of the I2C interface, and timestamp is the time of when this status was processed by the uC
101 """
102 self.update()
103 return (self.__order,self.__order_timestamp)
104
105 def data_from_chip(self):
106 """ Returns the data recived from the chip, and the time it was processed by the uC
107
108 will retun 2 lists: one with the word recoded and one with the time when it was recorded, linked by index
109
110 @return: ([data_from_chip], [data_from_chip_times]) where data_from_chip is the data recived from the chip, and data_from_chip_times is the time it was processed by the uC
111 """
112 self.update()
113 return (self.__data_from_chip, data_from_chip_times)
114
115 def data_to_chip(self):
116 """ Returns the data send to the chip, and the time it was processed by the uC
117
118 data_to_chip will retun the data send by the uC to the device under test (DUT)
119
120 will retun 2 lists: one with the word send and one with the exact time when it was send, linked by index
121
122 the time might differ slightly from the time you sheduled the send word,
123 as it is the time when it was send out and the uC can only send one word at a time
124
125 @return: ([data_to_chip], [data_to_chip_times]) where data_to_chip is the data send to the chip, and data_to_chip_times is the time it was processed by the uC
126 """
127 self.update()
128 return (self.__data_to_chip, self.__data_to_chip_times)
129
131 """ Returns the data recived from the chip, and the time it was processed by the uC, and clears the data
132
133 will retun 2 lists: one with the word recoded and one with the time when it was recorded, linked by index
134
135 @return: ([data_from_chip], [data_from_chip_times]) where data_from_chip is the data recived from the chip, and data_from_chip_times is the time it was processed by the uC
136 """
137 self.update()
138 data = self.__data_from_chip
139 time = self.__data_from_chip_times
140 self.__data_from_chip = []
141 self.__data_from_chip_times = []
142 return (data, time)
143
145 """ Returns the data send to the chip, and the time it was processed by the uC, and clears the data
146 data_to_chip will retun the data send by the uC to the device under test (DUT)
147
148 will retun 2 lists: one with the word send and one with the exact time when it was send, linked by index
149
150 the time might differ slightly from the time you sheduled the send word,
151 as it is the time when it was send out and the uC can only send one word at a time
152
153 @return: ([data_to_chip], [data_to_chip_times]) where data_to_chip is the data send to the chip, and data_to_chip_times is the time it was processed by the uC
154 """
155 self.update()
156 data = self.__data_to_chip
157 time = self.__data_to_chip_times
158 self.__data_to_chip = []
159 self.__data_to_chip_times = []
160 return (data, time)
161
162 def errors(self):
163 """ Returns the errors and unhandled packets reported by the uC for this interface
164 @return: [errors] where errors is the errors and unhandled packets reported by the uC for this interface
165 """
166 self.update()
167 return self.__errors
168
169 def __str__(self):
170 self.update()
171 state_str = ("active" if self.__status == 2 else ("activation pending" if self.__status == 1 else ("not active" if self.__status == 0 else "error" )))
172 return "I2C"+ \
173 "\nHeader: " + str(self.__header) + \
174 "\nStatus: " + state_str + " at " + str(self.__status_timestamp) + "us" + \
175 "\nNumber of Bytes "+ str(self.__number_of_bytes) +" at " + str(self.__number_of_bytes_timestamp) + "us" + \
176 "\nSpeed "+ str(self.__speed) +" at " + str(self.__speed_timestamp) + "us" + \
177 "\nOrder "+ str(self.__order) +" at " + str(self.__order_timestamp) + "us" + \
178 "\nSend: "+ str(self.__data_to_chip) +" at " + str(self.__data_to_chip_times) + "us" + \
179 "\nRecived: "+ str(self.__data_from_chip) +" at " + str(self.__data_from_chip_times) + "us" + \
180 "\nERRORS: "+str(self.__errors) + "\n"
181
182 def process_packet(self, packet):
183 """ Processes a packet from the uC, and updates the status and stores the data of/in the I2C interface object
184 @param packet: the packet to process
185 """
186 if packet.header() in self.__header:
187 # handle a configuration acknoledgement
188 if packet.header() == self.__header[0]:
189 # activation of the interface
190 if packet.config_header() == ConfigSubHeader.CONF_ACTIVE:
191 self.__status = 2
192 self.__status_timestamp = packet.time()
193 return
194 # byte order
195 elif packet.config_header() == ConfigSubHeader.CONF_BYTE_ORDER:
196 self.__order = "MSBFIRST" if (packet.value() > 0) else "LSBFIRST"
197 self.__order_timestamp = packet.time()
198 return
199 # number of bytes
200 elif packet.config_header() == ConfigSubHeader.CONF_WIDTH:
201 self.__number_of_bytes = packet.value()
202 self.__number_of_bytes_timestamp = packet.time()
203 return
204 # speed
205 elif packet.config_header() == ConfigSubHeader.CONF_SPEED_CLASS:
206 if packet.value() == 4:
207 self.__speed = 10000
208 elif packet.value() == 0:
209 self.__speed == 100000
210 elif packet.value() == 1:
211 self.__speed == 400000
212 elif packet.value() == 2:
213 self.__speed == 1000000
214 elif packet.value() == 3:
215 self.__speed == 3400000
216 else:
217 self.__speed = packet.value()
218 self.__speed_timestamp = packet.time()
219 return
220 # handle a data packet
221 elif packet.header() == self.__header[1]:
222 self.__data_to_chip.append((packet.read(),packet.device_address(),packet.register_address(),packet.value()))
223 self.__data_to_chip_times.append(packet.time())
224 return
225 elif packet.header() == self.__header[2]:
226 self.__data_from_chip.append((packet.read(),packet.device_address(),packet.register_address(),packet.value()))
227 self.__data_from_chip_times.append(packet.time())
228 return
229 # if it was not handled, store it as an error
230 self.__errors.append(str(packet))
231 self.__status = -1
232
233 def activate(self, speed=400000, order="LSBFIRST", number_of_bytes=1, time=0):
234 """ Activat the I2C interface and configure it with the given speed, byte order and number of bytes
235 @param speed: the speed of the I2C interface possible values are 10000, 100000, 400000, 1000000, 3400000
236 @param order: the byte order of the I2C interface possible values are "LSBFIRST" or "MSBFIRST"
237 @param number_of_bytes: the protocol data word width of the I2C interface possible values are 1 or 2
238 @param time: the time when the activation should be processed by the uC (0 means as soon as possible)
239 """
240 self.__api.update_state()
241 # if the interface is already active or waiting activation, do nothing
242 if self.__status >= 1:
243 logging.warning("I2C interface "+str(self.__header[0])+" is already activated or waiting activation, doing nothing")
244 else:
245 # byte order
246 self.__api.send_packet(ConfigPacket(header = self.__header[0], config_header = ConfigSubHeader.CONF_BYTE_ORDER, value= (1 if (order == "MSBFIRST") else 0),time = time))
247 # speed
248 if speed == 10000:
249 self.__api.send_packet(ConfigPacket(header = self.__header[0], config_header = ConfigSubHeader.CONF_SPEED_CLASS, value=4,time = time))
250 elif speed == 100000:
251 self.__api.send_packet(ConfigPacket(header = self.__header[0], config_header = ConfigSubHeader.CONF_SPEED_CLASS, value=0,time = time))
252 elif speed == 400000:
253 self.__api.send_packet(ConfigPacket(header = self.__header[0], config_header = ConfigSubHeader.CONF_SPEED_CLASS, value=1,time = time))
254 elif speed == 1000000:
255 self.__api.send_packet(ConfigPacket(header = self.__header[0], config_header = ConfigSubHeader.CONF_SPEED_CLASS, value=2,time = time))
256 elif speed == 3400000:
257 self.__api.send_packet(ConfigPacket(header = self.__header[0], config_header = ConfigSubHeader.CONF_SPEED_CLASS, value=3,time = time))
258 else:
259 logging.warning("I2C only supports 10000,100000,400000,1000000,3400000 Hz, defaulting to 100000")
260 # number of bytes
261 if number_of_bytes > 2:
262 logging.warning("I2C ony supports one or two bytes, defaulting to 1")
263 else:
264 self.__api.send_packet(ConfigPacket(header = self.__header[0], config_header = ConfigSubHeader.CONF_WIDTH, value=number_of_bytes,time = time))
265 # and activate
266 self.__api.send_packet(ConfigPacket(header = self.__header[0], config_header = ConfigSubHeader.CONF_ACTIVE,time = time))
267 self.__status = 1
268
269 def send_write(self,device_address, register_address, word, time = 0):
270 """ Send a write request on the I2C interface
271 @param device_address: the address of the device to write to (7bit)
272 @param register_address: the address of the register to write to (8bit)
273 @param word: the word to write (8 or 16 bit depending on the number of bytes configured)
274 @param time: the time when the write request should be processed by the uC (0 means as soon as possible)
275 """
276 # we dont check the status here anymore as the uC will report the error anyway
277 self.__api.send_packet(DataI2CPacket(self.__header[1], device_address=device_address, register_address=register_address,read=0,value=word,time=time))
278
279
280 def send_read_request(self, device_address, register_address, word, time = 0):
281 """ Send a read request on the I2C interface
282 @param device_address: the address of the device to read from (7bit)
283 @param register_address: the address of the register to read from (8bit)
284 @param word: ?
285 @param time: the time when the read request should be processed by the uC (0 means as soon as possible)
286 """
287 # we dont check the status here anymore as the uC will report the error anyway
288 self.__api.send_packet(DataI2CPacket(self.__header[1], device_address=device_address, register_address=register_address,read=1,value=word,time=time))
289
290 def update(self):
291 """ update the data repersentation of the API object
292 """
293 self.__api.update_state()
This class is the API for the I2C interfaces of the uC It is used to configure, send and recive data ...
def status(self)
Returns the status of the I2C interface, and the time of when this status was processed by the uC.
def process_packet(self, packet)
Processes a packet from the uC, and updates the status and stores the data of/in the I2C interface ob...
def data_to_chip_and_clear(self)
Returns the data send to the chip, and the time it was processed by the uC, and clears the data data_...
def data_from_chip_and_clear(self)
Returns the data recived from the chip, and the time it was processed by the uC, and clears the data.
def activate(self, speed=400000, order="LSBFIRST", number_of_bytes=1, time=0)
Activat the I2C interface and configure it with the given speed, byte order and number of bytes.
def number_of_bytes(self)
Returns the protocol data word width of the I2C interface, and the time of when this status was proce...
def update(self)
update the data repersentation of the API object
def __init__(self, api_object, interface_id)
Constructor for the I2C interface.
def byte_order(self)
Returns the byte order of the I2C interface, and the time of when this status was processed by the uC...
def speed(self)
Returns the speed of the I2C interface, and the time of when this status was processed by the uC.
def send_write(self, device_address, register_address, word, time=0)
Send a write request on the I2C interface.
def errors(self)
Returns the errors and unhandled packets reported by the uC for this interface.
def data_from_chip(self)
Returns the data recived from the chip, and the time it was processed by the uC.
def data_to_chip(self)
Returns the data send to the chip, and the time it was processed by the uC.
def send_read_request(self, device_address, register_address, word, time=0)
Send a read request on the I2C interface.
The ConfigPacket is used to cumunicate configuration instructions with the uC all availible instructi...
Definition: packet.py:375
The DataI2CPacket is used for I2C communication and all types which need 3x 8bit values instread of 1...
Definition: packet.py:179