2 magnetomètres LIS3MDL (même adresse) en I2C oui c'est possible

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

Modérateur : Francois

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

2 magnetomètres LIS3MDL (même adresse) en I2C oui c'est possible

Message par decxjo » jeu. 10 janv. 2019 19:20

+ après beaucoup d'exploration pour mon robot, et pour accéder à 2 magnétomètres ayant la même adresse I2C je vous fait part d'une solution possible.

+ le principe consiste à déconnecter du SCL chaque magnétomètre de façon indépendante et ne rétablir le SCL qu'en cas de besoin de communication.
+ Pour se faire il faut attribuer un GPIO pour commander un BC547 (transistor banal, avec un pont diviseur 5K/10) par sa base. La ligne SCL entre au collecteur et sort au drain et est donc interrompue quand le GPIO dévolu est au niveau bas et rétablie lorsqu'il est au niveau haut.
+ Par logiciel il suffit de rétablir le SCL du magnétomètre souhaité pour que lui seul soit visible sur le bus I2C.

Ce dispositif très simple et économique permet de ne pas se résigner à abandonner l'I2C dans le cas où plusieurs capteurs ont la même adresse I2C et qu'elle n'est pas programmable
Modifié en dernier par decxjo le sam. 12 janv. 2019 00:01, modifié 1 fois.

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

Re: 2 magnetomètres LIS3MDL (même adresse) en I2C oui c'est possible

Message par destroyedlolo » jeu. 10 janv. 2019 20:33

Salut,

Y'a pas plusieurs bus I2C exposés sur la framboise ?
Il me semblait qu'il y en avait 2 sur le port 40 broches comme sur le BananaPro, non ?

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.

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

Re: 2 magnetomètres LIS3MDL (même adresse) en I2C oui c'est possible

Message par decxjo » ven. 11 janv. 2019 23:57

ben non je ne trouve qu'un bus I2C documenté sur Raspberry 2 ou 3 ...... ou je me trompe ?
d'ailleurs quel est l'intérêt d'en avoir 2 à moins de vouloir communiquer avec 2 fois 127 capteur?
Avec le petit montage proposé ci dessus, le bus reste exploitable par 125 autres capteurs pourvus qu'ils aient des adresse différentes ou si pour certains la collision d'adresse se présente, il est possible en consacrant d'autres GPIO d'étendre le contrôle du SCL à ces jumeaux.

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

Re: 2 magnetomètres LIS3MDL (même adresse) en I2C oui c'est possible

Message par destroyedlolo » sam. 12 janv. 2019 16:23

decxjo a écrit :
ven. 11 janv. 2019 23:57
ben non je ne trouve qu'un bus I2C documenté sur Raspberry 2 ou 3 ...... ou je me trompe ?
d'ailleurs quel est l'intérêt d'en avoir 2 à moins de vouloir communiquer avec 2 fois 127 capteur?
Ben justement d'avoir plusieurs fois le meme capteurs avec la meme adresse (meme si ton montage est parfaitement valide).
En plus, ca permet d'avoir plus de bande passante plus importante par exemple, si tu as des écrans I2C.
  • 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.

Bud Spencer
Raspinaute
Messages : 911
Enregistré le : lun. 15 août 2016 21:38

Re: 2 magnetomètres LIS3MDL (même adresse) en I2C oui c'est possible

Message par Bud Spencer » mar. 15 janv. 2019 10:17

decxjo a écrit :
jeu. 10 janv. 2019 19:20
Ce dispositif très simple et économique permet de ne pas se résigner à abandonner l'I2C dans le cas où plusieurs capteurs ont la même adresse I2C et qu'elle n'est pas programmable
il y a plus simple et plus efficace sans avoir a utiliser un GPIO de sélection et pour pas beaucoup plus cher. Il suffit simplement d'utiliser un switch I2C. On trouve des modules tca9548a (switch 8xI2C) tout monté pour a peine 5€. En plus ces modules ont 3 bits d'adressages, et là, l'usage d'une ou plusieurs GPIO prend un autres sens puisque qu'a chaque gpio utilisée (0 à 3) on double le nombre de perif. I2C utilisable avec la meme adresse (8,16,32,64).
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

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

Re: 2 magnetomètres LIS3MDL (même adresse) en I2C oui c'est possible

Message par decxjo » mar. 15 janv. 2019 11:06

Merci beaucoup je garde cette idée pour mon deuxième proto ... ça fera moins de soudure bien que le plaisir de "voir" par où passe le signal ;)

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

Re: 2 magnetomètres LIS3MDL (même adresse) en I2C oui c'est possible

Message par decxjo » jeu. 8 oct. 2020 10:28

voilà j'ai suivi le conseil et comme un exemple vaut mieux qu'un long discours je vous livre le programme en micropython avec les commentaires désolé il semble que les tabulations soient écrasées


Clopeau mycropyhton pour wipy 3
""" attention ce programme contient l'exploitation de 1 multiplexeur I2C TCA9548A
par défaut on ne connecte à A0 A1 A2 à rien , la connection à 3,3volt de ces ligne d'adresse permet d'incrémenter l'adresse
du multiplexer dont l'adresse de base sur le bus I2C est 0x70 ainsi avec ce trois fils d'adresse il est possible de fixer les adresses de 8 multiplexeurs entre
il est possible d'obtenir la communication avec 8 multiplexeurs on programme en mettant les Ax à 3,3 volt les adresses ainsi de 0xF0 à 0xF7.
Ceci étant l’ouverture d'un des canaux du multiplexeur se fait par une "commande envoyée 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 nigne d'adresse ne sont pas active et que donc par dé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 jsuqu'à 8 de composants identiques 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 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>32767:
raw_accel=raw_accel-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 = round(accel / 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>32767:
raw_mag=raw_mag-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)

domi
Administrateur
Messages : 2873
Enregistré le : mer. 17 sept. 2014 18:12
Localisation : Seine et Marne

Re: 2 magnetomètres LIS3MDL (même adresse) en I2C oui c'est possible

Message par domi » jeu. 8 oct. 2020 15:35

decxjo a écrit :
jeu. 8 oct. 2020 10:28
.... désolé il semble que les tabulations soient écrasées
Pour garder la mise en forme, et éviter les long fil de code, il faut mettre le code entre les balises "code"
Passionné de Raspberry, Arduino, ESP8266, ESP32, et objets connectés :
Spécial débutant, concevez vous-même votre domotique DIY : https://www.youtube.com/c/DomoticDIY

Répondre

Retourner vers « Les BUS interfaces »