title: I2C read error while getting data from sensor with pigpio
body: <p>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.</p>
  <p>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 &quot;I2C read failed&quot; (when the error happens in the check_flags() method) and sometimes I get something like this:</p>
  <pre><code>interrupt 1 True
  4 0 1810275105
  Exception in thread Thread-2:
  Traceback (most recent call last):
    File &quot;/usr/lib/python3.7/threading.py&quot;, line 917, in _bootstrap_inner
      self.run()
    File &quot;/usr/lib/python3.7/threading.py&quot;, line 865, in run
      self._target(*self._args, **self._kwargs)
    File &quot;/home/pi/.../tkinter/mix/mix_interrupt.py&quot;, line 307, in check_flags
      pi.i2c_read_byte_data(acc_sensor, FF_MT_SRC)
    File &quot;/usr/lib/python3/dist-packages/pigpio.py&quot;, line 2874, in i2c_read_byte_data
      return _u2i(_pigpio_command(self.sl, _PI_CMD_I2CRB, handle, reg))
    File &quot;/usr/lib/python3/dist-packages/pigpio.py&quot;, line 1011, in _u2i
      raise error(error_text(v))
  pigpio.error: 'I2C read failed'
  </code></pre>
  <p>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</p>
  <p>My important code parts:</p>
  <p>This is the thread:</p>
  <pre><code>threading.Thread(target=self.check_flags).start() #This is in the init method
  </code></pre>
  <p>This function runs in a thread like this and checks if self.interrupt_flag is set</p>
  <pre><code>def check_flags(self):
          while(True):
              #print(&quot;check the flags&quot;)
              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) &lt; 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 &gt; self.threshold or y2 &gt; 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(&quot;error:&quot;, e)
                  self.save_data()
                  self.plot_data()
                  self.interrupt_flag = False
  </code></pre>
  <p>This is one of the functions i use to read sensor data. The other two are almost identical</p>
  <pre><code>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 &lt;&lt; 8) | comp_acc_x1) &gt;&gt;4
          if acc_combined &lt; 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
  </code></pre>
  <p>This is my interrupt routine:</p>
  <pre><code>def my_callback1(self, gpio, level, tick): #first interrupt function
          self.interrupt_flag = True
          print(&quot;interrupt 1&quot;, self.interrupt_flag)
          
          print(gpio, level, tick)
  </code></pre>
  <p>EDIT (ALMOST PERFECT) WORKING CODE:</p>
  <pre><code>protect = threading.Lock() # this is outside of any class at the top
  
  def check_flags(self): # new data capture method
          while(True):
              #print(&quot;check the flags&quot;)
              if (self.interrupt_flag == True):
                  protect.acquire()
                  ff_flag = pi.i2c_read_byte_data(acc_sensor, FF_MT_SRC)
                  print(&quot;interrupt cleared&quot;, 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) &lt; 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 &gt; self.threshold or y2 &gt; self.threshold):
                              self.timeframe += 5
                      except pigpio.error as e:
                          print(&quot;error:&quot;, e)
                  self.save_data()
                  self.plot_data()
                  self.interrupt_flag = False
                  self.timeframe = self.config.getint('setting', 'timeframe')
                  print(&quot;scale_variable: &quot;, scale_variable)
                  protect.release()
  </code></pre>