multiple I²C sur RPi4

Des infos, des conseils sur les bus DSI,CSI, I2C, SPI... du Raspberry Pi

Modérateur : Francois

Répondre
Mercusyo
Messages : 6
Enregistré le : ven. 12 juin 2020 16:02

multiple I²C sur RPi4

Message par Mercusyo » lun. 15 juin 2020 09:43

Bonjour à toutes et à tous,

Voilà, j'utilise des RPi 3 B+ depuis quelques années désormais; depuis peu, j'ai acheté la version 4 du RPi (1 Go de RAM).
J'ai acheté cette version de RPi car j'avais vu qu'il y a plusieurs ports I²C et non 1 seul comme sur la version 3; de ce que j'ai pu comprendre, il y a 6 ports I²C possible ?
De i2c-7 à i2c-3 et le i2c-1 déjà existant sans aucun rajout de résistance pull up, car j'ai déjà utilisé ce port par le passé sur RPi3 mais un seul périphérique.

Je suis donc en plein tests, et j'aimerais déjà brancher 2 Convertisseur Numérique Analogique type MCP4725. J'ai donc suivi un "tuto" sur le net pour paramétrer par exemple le port i2c-7.
https://www.instructables.com/id/Raspbe ... c-Devices/

Je réalise donc la modification à apporter dans le fichier de boot "config.txt", mais lors du re démarrage, le RPi 4 ne démarre plus ... écran noir ... :shock:
dtoverlay=i2c-gpio,bus=7,i2c_gpio_delay_us=1,i2c_gpio_sda=17,i2c_gpio_scl=27
J'ai testé en ajoutant 2 résistances de pull up de 10 KOhms ... mais pareil, black screen ... du coup, je ne comprends pas bien

Est-ce que quelqu'un a déjà paramétrer plusieurs ports I²C sur RPi 4.

Sinon en parallèle, j'ai commandé un multiplexeur I²C : https://learn.adafruit.com/adafruit-tca ... r-breakout
qui promet de pouvoir brancher plusieurs périphériques ayant la même adresse, ce qui est mon cas évidement car à terme 7 CNA

Merci beaucoup pour vos conseils et aide,
Bien à vous,

destroyedlolo
Raspinaute
Messages : 1585
Enregistré le : dim. 10 mai 2015 18:44
Localisation : Dans la campagne à côté d'Annecy
Contact :

Re: multiple I²C sur RPi4

Message par destroyedlolo » lun. 15 juin 2020 12:05

Salut,

Ouai, c'est chiant les devices tree et surtout pas facile a débugger (je suis en train de me faire chier avec un écran 3.5 sur mon Banana ... quelle galère).

Comme ca, a brule pour point, je commencerai avec le port 3 et non le 7 comme tu le fais. A la lecture du lien que tu as donné, j'ai l'impression
  • qu'il faut définir dans l'ordre inverse
  • mais qu'il faut descendre jusqu'au 3
Donc, il est possible qu'il n'aime pas s'il n'y a rien entre le 2 et le 7.

(une idée comme ca, hein, je n'ai pas de rPI4 pour essayer).

A+
  • BananaPI : Gentoo, disque SATA de 2 To
  • Domotique : 1-wire, TéléInfo, Tablette passée sous Gentoo, ESP8266
  • Multimedia par DNLA
  • Et pleins d'idées ... et bien sûr, pas assez de temps.
Un descriptif de ma domotique 100% fait maison.

Mercusyo
Messages : 6
Enregistré le : ven. 12 juin 2020 16:02

Re: multiple I²C sur RPi4

Message par Mercusyo » mar. 16 juin 2020 09:47

Bonjour,

Tout d'abord, merci pour votre réponse. Je viens de faire un test à l'instant et malheureusement cela ne fonctionne pas non plus :cry:
J'ai branché avec 2 résistances pull up de 1.8KOhms entre le 3.3V et les broches SDA et SCL du second MCP4725 et des GPIO 17 et 27 côté RPi4 ....
J'ai cherché sur le net et des personnes réussissent à paramétrer plusieurs I²C (au moins 4), sans aucun souci et surtout pas d'écran noir, du coup, je ne comprends pas bien ...

destroyedlolo
Raspinaute
Messages : 1585
Enregistré le : dim. 10 mai 2015 18:44
Localisation : Dans la campagne à côté d'Annecy
Contact :

Re: multiple I²C sur RPi4

Message par destroyedlolo » mar. 16 juin 2020 11:05

L'écran noir n'a rien a voir avec la présence ou non de résistance a mon avis (au pire, son absence ferait que tu ne verrais aucun périph) : c'est plus qu'il y a qq chose qui ne va pas dans ton Device Tree.

Je pense qu'il faudrait que t'essaye de voir avec eux si :
* ils ont la meme version de l'OS et surtout du kernel
* s'ils ont changer qq chose dans le system (genre pas l'outils de configuration **-config dont le nom m'échappe).

A+
  • BananaPI : Gentoo, disque SATA de 2 To
  • Domotique : 1-wire, TéléInfo, Tablette passée sous Gentoo, ESP8266
  • Multimedia par DNLA
  • Et pleins d'idées ... et bien sûr, pas assez de temps.
Un descriptif de ma domotique 100% fait maison.

Mercusyo
Messages : 6
Enregistré le : ven. 12 juin 2020 16:02

Re: multiple I²C sur RPi4

Message par Mercusyo » mar. 16 juin 2020 14:13

Re Bonjour,

J'avais eu justement la même idée, à savoir reprendre une ancienne version de Raspbian, et j'ai donc téléchargé la première version de Buster datant du 20/06/2019, et avec les mêmes manipulations, cela fonctionne, enfin pour 2 ports I²C pour l'instant, mais c'est déjà mieux :) :)

Pour cette version, le firmware est: Linux raspberrypi 4.19.50-v7l+ #895 SMP Thu Jun 20 16:03:42 BST 2019 armv7l GNU/Linux

PRETTY_NAME="Raspbian GNU/Linux 10 (buster)"
NAME="Raspbian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"

Mercusyo
Messages : 6
Enregistré le : ven. 12 juin 2020 16:02

Re: multiple I²C sur RPi4

Message par Mercusyo » mar. 16 juin 2020 14:39

Bon, j'ai même poussé le vice jusque réaliser un update/upgrade .... reboot, et hop ...écran noir ...

Mercusyo
Messages : 6
Enregistré le : ven. 12 juin 2020 16:02

Re: multiple I²C sur RPi4

Message par Mercusyo » mar. 16 juin 2020 15:53

J'ai encore poussé le vice et j'ai testé avec les versions suivantes et cela fonctionne : :mrgreen:
20/06/2019
10/07/2019
26/09/2019
05/02/2020
13/02/2020

Par contre, la dernière version du 20/06/2020 ne fonctionne pas

decxjo
Messages : 9
Enregistré le : jeu. 10 janv. 2019 19:01

Re: multiple I²C sur RPi4

Message par decxjo » jeu. 8 oct. 2020 12:46

voilà une programme ne micropython mais très facielemnt adaptable pour python3 sur Raspi

Code : Tout sélectionner

""" attention ce programme contient l'exploitation d'une multiplexeur I2C TCA9548A
par défaut on ne connecte à A0 A1 A2 à rien , la connexion à 3,3volt de ces lignes d'adresse permet d'incrémenter l'adresse
du multiplexer  dont l'adresse de base sur le bus I2C est 0x70  ainsi avec ces trois fils d'adresse
il est possible d'obtenir la communication avec 8 multiplexeurs qui redoivent dont on programme les adresses ainsi de 0xF0 à 0xF7.
Ceci étant l'ouverture d'un des port du multiplexeur se fait par une "commande envoyé sur le bus I2C lui même.
par exemple pour ouvrir le canal "0" du multiplexeur il faut en voyer sur le bus I2c  par writeto(0xF0,1) ensuite on constate
par exemple en scanant le bus que c'est bien le composant qui répond sur ce canal et lui seul. un print du scan donne
 la ou les adresses du composant connecté sur ce port suivi toujours de l'adresse du multiplexeur lui même, ici 112  puisque
 les lignes d'adresse ne sont pas actives et que donc par de faut l'adresse I2c du multiplexeur est 0xF0  soit 112  valeur numérique.
 par la on comprend que les autres ports étant isolés nous pourrons mettre ensuquer 8 de composants identique de mêmes adresses
 sans générer de conflit.  par exemple un write(0xf0, 128) permettra de communiquer uniquement avec le composant connecté au port 8.
 la valeur transmise dans cette ordre de connexion est fait un octet donc chaque bit à 1  active un port 
 d'où les seules valeurs autorisées: 1,2,4,8,16,32,64,128.  Un scan après un commande type write(0xF0, 5)
 qui en valeur digitale donne 00000101 entre comme seule réponse invariable 112 qui indique que le mutiplexeur qui répond toujours 
 présent à son adresse n'a ouvert aucun de ses ports   
"""

import time
from machine import I2C
import math
import utime
from machine import Pin

print("c'est fait")

# configure the I2C bus
bus = I2C(0,I2C.MASTER, baudrate=100000)


accel_address=25
mag_address=30

class lsm303DLHC:
    # LSM303 Address definitions
    LSM303Accel_ADDR    = 25 # ou l'inverse
    LSM303Mag_ADDR      = 30

    CTRL_REG1_A = 0x20
    CTRL_REG2_A = 0x21
    CTRL_REG3_A = 0x22
    CTRL_REG4_A = 0x23
    CTRL_REG5_A = 0x24
    CTRL_REG6_A = 0x25
    REFERENCE_A = 0x26
    STATUS_REG_A = 0x27
    OUT_X_L_A = 0x28
    OUT_X_H_A = 0x29
    OUT_Y_L_A = 0x2A
    OUT_Y_H_A = 0x2B
    OUT_Z_L_A = 0x2C
    OUT_Z_H_A = 0x2D
    FIFO_CTRL_REG_A = 0x2E
    FIFO_SRC_REG_A = 0x2F
    INT1_CFG_A = 0x30
    INT1_SRC_A = 0x31
    INT1_THS_A = 0x32
    INT1_DURATION_A = 0x33
    INT2_CFG_A = 0x34
    INT2_SRC_A = 0x35
    INT2_THS_A = 0x36
    INT2_DURATION_A = 0x37
    CLICK_CFG_A = 0x38
    CLICK_SRC_A = 0x39
    CLICK_THS_A = 0x3A
    TIME_LIMIT_A = 0x3B
    TIME_LATENCY_A = 0x3C
    TIME_WINDOW_A = 0x3D
    #Magnetic field sensing register description . . . . . . . . . . . . . . . . . . . . . . . 37
    CRA_REG_M = 0x00
    CRB_REG_M = 0x01
    MR_REG_M = 0x02
    OUT_X_H_M = 0x03
    OUT_X_L_M = 0x04
    OUT_Z_H_M = 0x05
    OUT_Z_L_M = 0x06
    OUT_Y_H_M = 0x07
    OUT_Y_L_M = 0x08
    SR_REG_M = 0x09
    MAG_IRA_REG_M = 0x0A
    MAG_IRB_REG_M = 0x0B
    MAG_IRC_REG_M = 0x0C
    TEMP_OUT_H_M = 0x31
    TEMP_OUT_L_M = 0x32
####################""""
    MAG_DEVICE_ID = 0b01000000
# Magnetometer gains
    MAGGAIN_1_3 = 0x20  # +/- 1.3
    MAGGAIN_1_9 = 0x40  # +/- 1.9
    MAGGAIN_2_5 = 0x60  # +/- 2.5
    MAGGAIN_4_0 = 0x80  # +/- 4.0
    MAGGAIN_4_7 = 0xA0  # +/- 4.7
    MAGGAIN_5_6 = 0xC0  # +/- 5.6
    MAGGAIN_8_1 = 0xE0  # +/- 8.1

# Magentometer rates
    MAGRATE_0_7 = 0x00  # 0.75 Hz
    MAGRATE_1_5 = 0x01  # 1.5 Hz
    MAGRATE_3_0 = 0x02  # 3.0 Hz
    MAGRATE_7_5 = 0x03  # 7.5 Hz
    MAGRATE_15 = 0x04  # 15 Hz
    MAGRATE_30 = 0x05  # 30 Hz
    MAGRATE_75 = 0x06  # 75 Hz
    MAGRATE_220 = 0x07  # 220 Hz

# Conversion constants
    GRAVITY_STANDARD = 9.80665  # Earth's gravity in m/s^2
    GAUSS_TO_MICROTESLA = 100.0  # Gauss to micro-Tesla multiplier

    ###################""""""
    ACCELE_SCALE     = 2

    X                 = 0
    Y                 = 1
    Z                 = 2

    # Set up the sensor
    def __init__(self,):

        self.write_regAccel(0b01000111, self.CTRL_REG1_A)                # 0x57 = ODR=50hz, all accel axes on
        self.write_regAccel(0x00, self.CTRL_REG2_A)      # set full-scale
        self.write_regAccel(0x00, self.CTRL_REG3_A)              # no interrupt
        self.write_regAccel(0x00, self.CTRL_REG4_A)              # no interrupt
        self.write_regAccel(0x00, self.CTRL_REG5_A)              # 0x10 = mag 50Hz output rate
        self.write_regAccel(0x00, self.CTRL_REG6_A)
        self.write_regMag(0b10010000,self.CRA_REG_M)     # activation température et frequence mag à 35 Hz
        self.write_regMag(0b00100000,self.CRB_REG_M)     # +- 1,3 Gauss champ terrete 0,5 gauss
        self.write_regMag(0b00000000,self.MR_REG_M)      #  pour mesure continuelle 00000011 pour mise en sommeil
        self.lsm303mag_gauss_lsb_xy= 1100.0
        self.lsm303mag_gauss_lsb_z= 980.0

        print("toto")

    # get the status of the sensor
    def status(self):
        if self.read_regAccel(self.STATUS_REG_A) !=73:
            return -1
        return 1



    # Write data to a reg on the I2C device
    def write_regAccel(self,data,reg):
        bus.writeto_mem(self.LSM303Accel_ADDR, reg, data)

    # Read data from the sensor
    def read_regAccel(self,reg):
        return bus.readfrom_mem(self.LSM303Accel_ADDR, reg,1)

    # Write data to a reg on the I2C device
    def write_regMag(self,data,reg):
        bus.writeto_mem(self.LSM303Mag_ADDR, reg, data)

    # Read data from the sensor
    def read_regMag(self,reg):
        return bus.readfrom_mem(self.LSM303Mag_ADDR, reg,1)

    # Check if compass is ready
    def isMagReady(self):
        if int.from_bytes(self.read_regMag(self.SR_REG_M),"big") & 0x03 != 0 :
            return 1
        return 0
    def dec2bin(self,d,nb):
    #"""Représentation d'un nombre entier en chaine binaire (nb: nombre de bits du mot)"""
        if d == 0:
            return "0".zfill(nb)
        if d<0:
            d += 1<<nb
        b=""
        while d != 0:
            d, r = divmod(d, 2)
            b = "01"[r] + b
        return '{:0>{w}}'.format(b, w=nb)   # en effet en micropyhton il n'y a pas de fonction zfill

    def temperature2(self):
        temp=((int.from_bytes(self.read_regMag(self.TEMP_OUT_H_M),"big")<<8)|(int.from_bytes(self.read_regMag(self.TEMP_OUT_L_M),"big")))
        if temp > 32767:  # 2's complement
            temp -= 65536
        temperature = float( 20 + ( temp >> 4 )/ 8 )
        return temperature
    # Get raw accelerometer values
    def getAccel(self):
        raw_accel=[0,0,0]
        #print("titi ",int.from_bytes(self.read_reg(self.OUT_X_H_A),"big"))
        raw_accel[0]=((int.from_bytes(self.read_regAccel(self.OUT_X_H_A),"big")<<8)|int.from_bytes(self.read_regAccel(self.OUT_X_L_A),"big"))
        raw_accel[1]=((int.from_bytes(self.read_regAccel(self.OUT_Y_H_A),"big")<<8)|int.from_bytes(self.read_regAccel(self.OUT_Y_L_A),"big"))
        raw_accel[2]=((int.from_bytes(self.read_regAccel(self.OUT_Z_H_A),"big")<<8)|int.from_bytes(self.read_regAccel(self.OUT_Z_L_A),"big"))
        #2's compiment
        for i in range(3):
            if raw_accel[i]>32767:
                raw_accel[i]=raw_accel[i]-65536

        return raw_accel

    # Get accelerometer values in g
    def getRealAccel(self):
        realAccel=[0.0,0.0,0.0]
        accel=self.getAccel()
        for i in range(3):
            realAccel[i] = round(accel[i] / math.pow(2, 15) * self.ACCELE_SCALE,3)
        return realAccel

    # Get compass raw values
    def getMag(self):
        raw_mag=[0,0,0]
        raw_mag[0]=((int.from_bytes(self.read_regMag(self.OUT_X_H_M),"big")<<8)|int.from_bytes(self.read_regMag(self.OUT_X_L_M),"big"))
        raw_mag[1]=((int.from_bytes(self.read_regMag(self.OUT_Y_H_M),"big")<<8)|int.from_bytes(self.read_regMag(self.OUT_Y_L_M),"big"))
        raw_mag[2]=((int.from_bytes(self.read_regMag(self.OUT_Z_H_M),"big")<<8)|int.from_bytes(self.read_regMag(self.OUT_Z_L_M),"big"))
        #2's compiment
        for i in range(3):
            if raw_mag[i]>32767:
                raw_mag[i]=raw_mag[i]-65536

        return raw_mag

    # Get heading from the compass
    def getHeading(self):
        magValue=self.getMag()
        print(magValue)
        heading = 180*math.atan2(magValue[self.Y], magValue[self.X])/math.pi#  // assume pitch, roll are 0

        if (heading <0):
            heading += 360

        return round(heading,3)

    def getTiltHeading(self):
        magValue=self.getMag()
        raw_accel=self.getAccel()
        if [0.0,0.0,0.0] != raw_accel:
            accXnorm= raw_accel[0]/math.sqrt(raw_accel[0]*raw_accel[0]+raw_accel[1]*raw_accel[1]+raw_accel[2]*raw_accel[2])
            accYnorm= raw_accel[1]/math.sqrt(raw_accel[0]*raw_accel[0]+raw_accel[1]*raw_accel[1]+raw_accel[2]*raw_accel[2])

            pitch = math.asin(accXnorm)
            roll = -math.asin(accYnorm/math.cos(pitch))
        #print(accelValue[Y],pitch,math.cos(pitch),accelValue[Y]/math.cos(pitch),math.asin(accelValue[Y]/math.cos(pitch)))

            xh = (magValue[0] * math.cos(pitch)) +( magValue[2] * math.sin(pitch))
            yh = (magValue[1] * math.sin(roll) * math.sin(pitch)) + (magValue[1] * math.cos(roll)) - (magValue[2] * math.sin(roll) * math.cos(pitch))
            zh = (-magValue[0] * (roll) * math.sin(pitch)) +( magValue[1] * math.sin(roll)) +( magValue[2] * math.cos(roll) * math.cos(pitch))
            heading = 180 * math.atan2(yh, xh)/math.pi
            #heading = 180 * math.atan2(yh*zh, xh*zh)/math.pi
            print("xh ", xh,"yh ",yh, "zh  ",zh)

            if (yh >= 0):
                return heading
            else:
                return (360 + heading)


if __name__ == "__main__":
    bus.writeto( 0x70, 1) # ouverture du bus N° 0
    print(bus.scan()) # returns list of slave addresses
    acc_mag=lsm303DLHC() #  création de l'objet gérant le premier acc-mag
    time.sleep(1)
    bus.writeto( 0x70, 128) # ouverture du bus N° 7
    print(bus.scan()) # returns list of slave addresses
    acc_mag2=lsm303DLHC() #   création de l'objet gérant le deuxième acc-mag
    while True:
        #if acc_mag.status()==1:
            bus.writeto( 0x70, 1) # ouverture du bus N° 0
            print("accélération",acc_mag.getRealAccel())
            while True:
                if acc_mag.isMagReady():
                    break
                    print("*")
            print(acc_mag.getHeading())
            print (acc_mag.getTiltHeading())
            print("température2 ", acc_mag.temperature2())
            time.sleep(5)
            # ici on change de canal du multiplexeur I2c
            bus.writeto( 0x70, 128) # ouverture du bus N° 0
            print("accélération",acc_mag2.getRealAccel())
            while True:
               if acc_mag2.isMagReady():
                    break
                    print("*")
            print(acc_mag2.getHeading())
            print (acc_mag2.getTiltHeading())
            print("température2 ", acc_mag2.temperature2())
            time.sleep(5)


Répondre

Retourner vers « Les BUS interfaces »