Reputation: 91
i have a Tkinter GUI and the acceleration sensor MMA8452Q. I set up the sensor that if a threshold is reached, a interrupt flag gets set and data for a specific period of time gets collected and plotted through the GUI.
Sometimes when I read the data or at any other point of using an I2C read function to read a register i get the error "I2C read failed" (when the error happens in the check_flags() method) and sometimes I get something like this:
interrupt 1 True
4 0 1810275105
Exception in thread Thread-2:
Traceback (most recent call last):
File "/usr/lib/python3.7/threading.py", line 917, in _bootstrap_inner
self.run()
File "/usr/lib/python3.7/threading.py", line 865, in run
self._target(*self._args, **self._kwargs)
File "/home/pi/.../tkinter/mix/mix_interrupt.py", line 307, in check_flags
pi.i2c_read_byte_data(acc_sensor, FF_MT_SRC)
File "/usr/lib/python3/dist-packages/pigpio.py", line 2874, in i2c_read_byte_data
return _u2i(_pigpio_command(self.sl, _PI_CMD_I2CRB, handle, reg))
File "/usr/lib/python3/dist-packages/pigpio.py", line 1011, in _u2i
raise error(error_text(v))
pigpio.error: 'I2C read failed'
Is there maybe something wrong with my code or should i could the baudrate be the fault of this problem? It doesn't happen all the time, but seemingly at random times. Just to clarify, if the error happens in the try-except-block, my data still gets plotted, but some data gets missing and the plot looks sometimes incomplete
My important code parts:
This is the thread:
threading.Thread(target=self.check_flags).start() #This is in the init method
This function runs in a thread like this and checks if self.interrupt_flag is set
def check_flags(self):
while(True):
#print("check the flags")
if (self.interrupt_flag == True):
pi.i2c_read_byte_data(acc_sensor, FF_MT_SRC)
global scale_variable
self.x_graph = []
self.y1_graph = []
self.y2_graph = []
self.y3_graph = []
a = datetime.datetime.now()
one_time = True
start_time = time.time()*1000
while(time.time()*1000-start_time) < self.timeframe:
try:
b = datetime.datetime.now()
delta = b-a
y1 = self.readACCx()
y2 = self.readACCy()
y3 = self.readACCz()
self.y1_graph.append(y1)
self.y2_graph.append(y2)
self.y3_graph.append(y3)
self.x_graph.append(delta.total_seconds()*1000)
if (y1 > self.threshold or y2 > self.threshold): # this is for catching the whole movement if its longer than the set timeframe
self.timeframe += 5
except pigpio.error as e:
print("error:", e)
self.save_data()
self.plot_data()
self.interrupt_flag = False
This is one of the functions i use to read sensor data. The other two are almost identical
def readACCx(self): #reads x axis value 12 bit
global scale_variable
comp_acc_x2 = pi.i2c_read_byte_data(acc_sensor, OUT_X_MSB)
comp_acc_x1 = pi.i2c_read_byte_data(acc_sensor, OUT_X_LSB)
acc_combined = ((comp_acc_x2 << 8) | comp_acc_x1) >>4
if acc_combined < 2048:
acc_combined = acc_combined*scale_variable
return acc_combined
else:
acc_combined = acc_combined - 4096
acc_combined = acc_combined*scale_variable
return acc_combined
This is my interrupt routine:
def my_callback1(self, gpio, level, tick): #first interrupt function
self.interrupt_flag = True
print("interrupt 1", self.interrupt_flag)
print(gpio, level, tick)
EDIT (ALMOST PERFECT) WORKING CODE:
protect = threading.Lock() # this is outside of any class at the top
def check_flags(self): # new data capture method
while(True):
#print("check the flags")
if (self.interrupt_flag == True):
protect.acquire()
ff_flag = pi.i2c_read_byte_data(acc_sensor, FF_MT_SRC)
print("interrupt cleared", ff_flag)
global scale_variable
self.x_graph = []
self.y1_graph = []
self.y2_graph = []
self.y3_graph = []
a = datetime.datetime.now()
one_time = True
start_time = time.time()*1000
while(time.time()*1000-start_time) < self.timeframe:
try:
b = datetime.datetime.now()
delta = b-a
y1 = self.readACCx()
y2 = self.readACCy()
y3 = self.readACCz()
self.y1_graph.append(y1)
self.y2_graph.append(y2)
self.y3_graph.append(y3)
self.x_graph.append(delta.total_seconds()*1000)
if (y1 > self.threshold or y2 > self.threshold):
self.timeframe += 5
except pigpio.error as e:
print("error:", e)
self.save_data()
self.plot_data()
self.interrupt_flag = False
self.timeframe = self.config.getint('setting', 'timeframe')
print("scale_variable: ", scale_variable)
protect.release()
Upvotes: 0
Views: 351
Reputation: 54698
Your traceback doesn't match your code. The traceback shows the i2c_read_byte_data
result not being saved anywhere. The I2C clock must be right, otherwise you'd get nothing at all.
The problem is probably synchronization. When you said "interrupt", that raised a red flag. If your interrupt handler tries to do an I2C operation while your mainline code is also doing one, the two will clash, especially since you have to do MSB and LSB separately. I suggest you use a threading.Lock
to make sure your sequences aren't interrupted.
Upvotes: 1