hardware i2c deprecated

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Grumpy_Pig_Skin
Posts: 5
Joined: Sun Feb 28, 2021 8:41 pm

hardware i2c deprecated

Post by Grumpy_Pig_Skin » Sun Feb 28, 2021 8:55 pm

Hi, i'm having an issue while trying to set the hardware i2c bus.

the code I enter is:

import machine
i2c = machine.I2C(scl=machine.Pin(22), sda = machine.Pin(21))

the error message I get back is:

Warning: I2C(-1, ...) is deprecated, use SoftI2C(...) instead

is there something I'm missing while setting the i2c?

thanks in advance
Ollie

User avatar
jimmo
Posts: 2754
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: hardware i2c deprecated

Post by jimmo » Sun Feb 28, 2021 10:51 pm

Grumpy_Pig_Skin wrote:
Sun Feb 28, 2021 8:55 pm
is there something I'm missing while setting the i2c?
Previously we use to have a single I2C class, and depending on which ID was specified, it was either Software (bitbanging) or Hardware. In this case, with no ID specified, it's defaulting to -1 (i.e. software I2C). This led to some confusing behavior due to port-specific differences (i.e. some ports allow you to specify pins for hardware I2C, whereas others require using the pre-defined pins).

As of version 1.14, the idea is that you can explicitly use machine.I2C for hardware I2C, and machine.SoftI2C if you want software I2C, but the old way is provided for compatibility.

Grumpy_Pig_Skin
Posts: 5
Joined: Sun Feb 28, 2021 8:41 pm

Re: hardware i2c deprecated

Post by Grumpy_Pig_Skin » Mon Mar 01, 2021 12:44 am

ahh okay.
So if i specify a channel e.g:
i2c = machine.I2C(1, scl = machine.Pin(22), sda = machine.Pin(21), freq = 400000) then hopefully i should have some luck with that?

rather than st using 'deafault' settings?

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: hardware i2c deprecated

Post by pythoncoder » Mon Mar 01, 2021 12:27 pm

That should work so long as you have pullup resistors: the ESP32 should be able to use any pins. If you have trouble try the default pins.

Code: Select all

i2c = machine.I2C(1, scl = machine.Pin(25), sda = machine.Pin(26), freq = 400000)
Peter Hinch
Index to my micropython libraries.

Wimphot
Posts: 4
Joined: Sun Mar 07, 2021 10:01 pm

Re: hardware i2c deprecated

Post by Wimphot » Tue Mar 23, 2021 11:38 pm

I am using a WEMOS LOLIN32 Lite. for the project in RNT’s MicroPython_Programming_with_ESP32_and_ESP8266_V1_2 book
BME280 sending readings using IFTTT.
Although the message came through OK I got the “Warning: I2C(-1, ...) is deprecated, use SoftI2C(...) instead” message.
Thinking I might learn something here (I am very new to MicroPython)
I tried the line: i2c = machine.I2C(1,scl=machine.Pin(19), sda=machine.Pin(23), freq=10000)
but then got “NameError: name ‘machine’ isn’t defined’
I think this is because I am only importing Pin and I2C
BUT
I am not sure what else I should import?
Perhaps I could simply import machine but it is my understanding that doing so clutters up the code on the ESP32 with data that isn’t used.
(not necessarily an issue with what I am doing but not good practice?
Thanks in advance

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: hardware i2c deprecated

Post by Roberthh » Wed Mar 24, 2021 6:43 am

You can use either:

Code: Select all

import machine
i2c = machine.I2C(1,scl=machine.Pin(19), sda=machine.Pin(23), freq=10000)
or

Code: Select all

from machine import Pin, I2C
i2c = I2C(1,scl=Pin(19), sda=Pin(23), freq=10000)
That's the way, Python works. Besides that, importing machine is not that memory consuming. So it's more a matter of style which way you prefer. If you have many modules with similar classes and methods, than it is more clear to use the first form.

Wimphot
Posts: 4
Joined: Sun Mar 07, 2021 10:01 pm

Re: hardware i2c deprecated

Post by Wimphot » Wed Mar 24, 2021 9:12 pm

Robert
Thank you for the advice.

jbar
Posts: 11
Joined: Mon Nov 15, 2021 1:07 pm
Location: Nebraska USA
Contact:

Re: hardware i2c deprecated

Post by jbar » Sat Jan 01, 2022 3:01 pm

Roberthh wrote:
Wed Mar 24, 2021 6:43 am
You can use either:

Code: Select all

import machine
i2c = machine.I2C(1,scl=machine.Pin(19), sda=machine.Pin(23), freq=10000)
or

Code: Select all

from machine import Pin, I2C
i2c = I2C(1,scl=Pin(19), sda=Pin(23), freq=10000)
That's the way, Python works. Besides that, importing machine is not that memory consuming. So it's more a matter of style which way you prefer. If you have many modules with similar classes and methods, than it is more clear to use the first form.
I'm using a SHT30 driver written by Roberto Sanchez (rsc1975 on github). His code currently returns the same:
Warning: I2C(-1, ...) is deprecated, use SoftI2C(...) instead
I tried adding a 1 to the I2C statement on line 40 of the code, but it dosen't work. What am I doing wrong? I'm trying to ammend his driver so it dosen't throw the Warning.

Code: Select all

from machine import I2C, Pin
import time

__version__ = '0.2.1'
__author__ = 'Roberto Sánchez'
__license__ = "Apache License 2.0. https://www.apache.org/licenses/LICENSE-2.0"

# I2C address B 0x45 ADDR (pin 2) connected to VDD
DEFAULT_I2C_ADDRESS = 0x45

class SHT30():
    """
    SHT30 sensor driver in pure python based on I2C bus
    
    References: 
    * https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf
    * https://www.wemos.cc/sites/default/files/2016-11/SHT30-DIS_datasheet.pdf
    * https://github.com/wemos/WEMOS_SHT3x_Arduino_Library
    * https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/11_Sample_Codes_Software/Humidity_Sensors/Sensirion_Humidity_Sensors_SHT3x_Sample_Code_V2.pdf
    """
    POLYNOMIAL = 0x131  # P(x) = x^8 + x^5 + x^4 + 1 = 100110001

    ALERT_PENDING_MASK = 0x8000 # 15
    HEATER_MASK = 0x2000        # 13
    RH_ALERT_MASK = 0x0800		# 11
    T_ALERT_MASK = 0x0400		# 10
    RESET_MASK = 0x0010	        # 4
    CMD_STATUS_MASK = 0x0002	# 1
    WRITE_STATUS_MASK = 0x0001	# 0

    # MSB = 0x2C LSB = 0x06 Repeatability = High, Clock stretching = enabled
    MEASURE_CMD = b'\x2C\x10'
    STATUS_CMD = b'\xF3\x2D'
    RESET_CMD = b'\x30\xA2'
    CLEAR_STATUS_CMD = b'\x30\x41'
    ENABLE_HEATER_CMD = b'\x30\x6D'
    DISABLE_HEATER_CMD = b'\x30\x66'

    def __init__(self, scl_pin=22, sda_pin=21, delta_temp = 0, delta_hum = 0, i2c_address=DEFAULT_I2C_ADDRESS):
        self.i2c = I2C(scl=Pin(scl_pin), sda=Pin(sda_pin))
        self.i2c_addr = i2c_address
        self.set_delta(delta_temp, delta_hum)
        time.sleep_ms(50)
    
    def init(self, scl_pin=22, sda_pin=21):
        """
        Init the I2C bus using the new pin values
        """
        self.i2c.init(scl=Pin(scl_pin), sda=Pin(sda_pin))
    
    def is_present(self):
        """
        Return true if the sensor is correctly conneced, False otherwise
        """
        return self.i2c_addr in self.i2c.scan()
    
    def set_delta(self, delta_temp = 0, delta_hum = 0):
        """
        Apply a delta value on the future measurements of temperature and/or humidity
        The units are Celsius for temperature and percent for humidity (can be negative values)
        """
        self.delta_temp = delta_temp
        self.delta_hum = delta_hum
    
    def _check_crc(self, data):
        # calculates 8-Bit checksum with given polynomial
        crc = 0xFF
        
        for b in data[:-1]:
            crc ^= b;
            for _ in range(8, 0, -1):
                if crc & 0x80:
                    crc = (crc << 1) ^ SHT30.POLYNOMIAL;
                else:
                    crc <<= 1
        crc_to_check = data[-1]
        return crc_to_check == crc
    
    def send_cmd(self, cmd_request, response_size=6, read_delay_ms=100):
        """
        Send a command to the sensor and read (optionally) the response
        The responsed data is validated by CRC
        """
        try:
            self.i2c.start(); 
            self.i2c.writeto(self.i2c_addr, cmd_request); 
            if not response_size:
                self.i2c.stop(); 	
                return
            time.sleep_ms(read_delay_ms)
            data = self.i2c.readfrom(self.i2c_addr, response_size) 
            self.i2c.stop(); 
            for i in range(response_size//3):
                if not self._check_crc(data[i*3:(i+1)*3]): # pos 2 and 5 are CRC
                    raise SHT30Error(SHT30Error.CRC_ERROR)
            if data == bytearray(response_size):
                raise SHT30Error(SHT30Error.DATA_ERROR)
            return data
        except OSError as ex:
            if 'I2C' in ex.args[0]:
                raise SHT30Error(SHT30Error.BUS_ERROR)
            raise ex

    def clear_status(self):
        """
        Clear the status register
        """
        return self.send_cmd(SHT30.CLEAR_STATUS_CMD, None); 

    def reset(self):
        """
        Send a soft-reset to the sensor
        """
        return self.send_cmd(SHT30.RESET_CMD, None); 

    def status(self, raw=False):
        """
        Get the sensor status register. 
        It returns a int value or the bytearray(3) if raw==True
        """
        data = self.send_cmd(SHT30.STATUS_CMD, 3, read_delay_ms=20); 

        if raw:
            return data

        status_register = data[0] << 8 | data[1]
        return status_register
    
    def measure(self, raw=False):
        """
        If raw==True returns a bytearrya(6) with sensor direct measurement otherwise
        It gets the temperature (T) and humidity (RH) measurement and return them.
        
        The units are Celsius and percent
        """
        data = self.send_cmd(SHT30.MEASURE_CMD, 6); 

        if raw:
            return data

        t_celsius = (((data[0] << 8 |  data[1]) * 175) / 0xFFFF) - 45 + self.delta_temp;
        rh = (((data[3] << 8 | data[4]) * 100.0) / 0xFFFF) + self.delta_hum;
        return t_celsius, rh

    def measure_int(self, raw=False):
        """
        Get the temperature (T) and humidity (RH) measurement using integers.
        If raw==True returns a bytearrya(6) with sensor direct measurement otherwise
        It returns a tuple with 4 values: T integer, T decimal, H integer, H decimal
        For instance to return T=24.0512 and RH= 34.662 This method will return
        (24, 5, 34, 66) Only 2 decimal digits are returned, .05 becomes 5
        Delta values are not applied in this method
        The units are Celsius and percent.
        """
        data = self.send_cmd(SHT30.MEASURE_CMD, 6); 
        if raw: 
            return data
        aux = (data[0] << 8 | data[1]) * 175
        t_int = (aux // 0xffff) - 45;
        t_dec = (aux % 0xffff * 100) // 0xffff
        aux = (data[3] << 8 | data[4]) * 100
        h_int = aux // 0xffff
        h_dec = (aux % 0xffff * 100) // 0xffff
        return t_int, t_dec, h_int, h_dec


class SHT30Error(Exception):
    """
    Custom exception for errors on sensor management
    """
    BUS_ERROR = 0x01 
    DATA_ERROR = 0x02
    CRC_ERROR = 0x03

    def __init__(self, error_code=None):
        self.error_code = error_code
        super().__init__(self.get_message())
    
    def get_message(self):
        if self.error_code == SHT30Error.BUS_ERROR:
            return "Bus error"
        elif self.error_code == SHT30Error.DATA_ERROR:
            return "Data error"
        elif self.error_code == SHT30Error.CRC_ERROR:
            return "CRC error"
        else:
            return "Unknown error"

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: hardware i2c deprecated

Post by Roberthh » Sat Jan 01, 2022 3:26 pm

You did not tell which board you use. Is it an ESP32? Or RPi Pico? And you could show the error message which you get.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: hardware i2c deprecated

Post by pythoncoder » Sun Jan 02, 2022 8:13 am

See @jimmo's post above. The machine module has changed. Hardware I2C is still specified in the same way, but soft I2C used to be specified with a bus number of -1. Now this produces the deprecation warning. The correct way is to write

Code: Select all

i2c = machine.SoftI2C(scl=scl_pin, sda=sda_pin)
Please see the docs.
Peter Hinch
Index to my micropython libraries.

Post Reply