I2C bus already used error



  • I have gotten the M5StickC up and running with micropython and VSCode. It looks like it's going to work very well, and it's much faster development than compared to the Arduino IDE.

    I continue to hit an error when using I2C that I can't figure out. I can run my code successfull yon the first upload, but then once I change it and rerun it errors with I2C bus already used. The only way around this is to perform a hard reset and reupload each time.

    Its my first go at micropython, and I'm still relativey new to i2c, so I'm not sure what to do. I've tried using deinit from the micropython docs, but that creates more errors. Below is my code. I'm grateful for any help in troubleshooting this.

    from m5stack import *
    from m5ui import *
    from uiflow import *
    from stemma_soil_sensor import *
    
    setScreenColor(0x000000)
    i2c = machine.I2C(sda=machine.Pin(32), scl=machine.Pin(33), freq=100000)
    seesaw = StemmaSoilSensor(i2c)
    
    while(1):
      # get moisture
      moisture = seesaw.get_moisture()
      lcd.print(moisture, 10, 0, 0xFFFFFF)
      wait_ms(10)
    


  • @dwarrenku Check the stemma file as it may be trying to define the I2c bus as well as you trying to initialise it.


  • M5Stack

    are you using the uiflow version of micropython? sometimes the i2c_bus module conflicts, I cant remember how i worked around it but i was getting that error before too



  • Yes, I'm using the uiflow version of micropython. For now I'm working around this by resetting it each time I rerun. It's kind of annoying but it works.
    From what I can see the stemma modules aren't defining the I2C bus, just saving the I2C object.

    class StemmaSoilSensor(seesaw.Seesaw):
        """Driver for Adafruit STEMMA Soil Sensor - I2C Capacitive Moisture Sensor
           :param I2C i2c: I2C bus the SeeSaw is connected to.
           :param int addr: I2C address of the SeeSaw device. Default is 0x36."""
        def __init__(self, i2c, addr=0x36):
            super().__init__(i2c, addr)
    

    and the seesaw module is the superclass of StemmaSoilSensor:

    class Seesaw:
        """Driver for SeeSaw I2C generic conversion trip.
           :param I2C i2c: I2C bus the SeeSaw is connected to.
           :param int addr: I2C address of the SeeSaw device."""
        def __init__(self, i2c, addr):
            self.i2c = i2c
            self.addr = addr
            self.sw_reset()
    


  • @dwarrenku
    Adafruit is using a programmed microcontroller in their stemma lines (Arm line) in order to interface different sensors to an i2c bus. M5Stack is using the same approach using the Atmel328 (Arduino line) microcontroller eg in their PbHub, servo controller, Makey etc. For the PbHub you can use the library provided or use the pure I2C blocks from the flow advanced sections. Using the I2C blocks I was able to read analog values from the PbHub, which is described in their unit data sheet, but the function is not provided as a flow block.

    Adafruit doesn't provide the details in their documents for their STEMMA Soil Sensor. But I probably found a solution described in following forum
    https://elixirforum.com/t/adafruit-stemma-soil-sensor-i2c/25990/2

    I think you are facing 2 problems:
    - timing problem ( you have to wait for for the sensor)
    - in the Stemma line, you can change the I2C adress of the sensors writing the values into ??? register !

    Because I don't have the STEMMA sensor, I can't try it out. But in my opinion, you don't need to include the seesaw STEMMA library (which may have the wrong timing for the M5Stack), but you can read the moisture values using M5Stack I2C blocks:

    0_1588021594822_a4627e8f-809e-46be-bcdd-1a36f4b063d9-image.png

    and translated into micropython:

    0_1588021744584_6abea805-c9ff-44be-8a06-778bb8850703-image.png



  • Thank you! I switched back to the i2c_bus module and the code you provided and it worked. No more errors.

    All that was missing was converting the struct to a short:

    def get_moisture():
      i2c = i2c_bus.easyI2C(i2c_bus.PORTA, 0x36)
      i2c.write_u8(0x0f, 0x10)
      wait_ms(5)
      val = i2c.read(2)
      val = ustruct.unpack(">H", val)[0]
      return val