harbaum / I2C-Tiny-USB

Cheap and simple I²C to USB interface
http://www.harbaum.org/till/i2c_tiny_usb
375 stars 79 forks source link

Multiple digispark USB #14

Open PizzaProgram opened 4 years ago

PizzaProgram commented 4 years ago

How do I change the I2C bus address of a ATTiny85 Digispark dongle, if I would like to use multiple of them on the same Raspberry Pi4? (Or with a USB HUB.)

I guess I have to re-compile the firmware it again for each one? Checked both digital.h & main.c files, but did not find any "I2C_BASE_BUS_ADDRESS" or anything similar.

Raspberry Pi4 has 4 I2C buses by default, so this should start from 8+

... or ... if the BUS address is given by Debian OS, how /where should I change the name or unique identifier of the flashed device so I can distinguish one from the others?

Sorry if my question is wrong, I'm a newbee to this. Trying to drive more than 64 IO pins: https://community.openhab.org/t/compatible-usb-i2c-adapter-for-rpi4/93690/6

harbaum commented 4 years ago

It's not the hardware nor the driver that does the bus enumeration but imho the i2c subsystem of the Linux kernel. And yes, you can simply plug multiple devices into your PC and they'll get individual busses assigned.

PizzaProgram commented 4 years ago

OK, that's good news :+1: But How do I rename those similar named USBs, so I can distinguish one from the other?

If each one is named the same, I won't know if that I2C bus is the one with inputs or the outputs... :-( ... and if I configure the IO panels wrong ...

PizzaProgram commented 4 years ago

This problem is more sever than I've thought.

I've just tested to plug in 2 keys, than unplugged and switched:
(I've attacked multiple boards to the first, none to the other)

[23:11:05] openhabian@openhab:~$ sudo i2cdetect -y 7
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- 21 22 23 -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- 51 -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

Depending which device I've plugged first and what USB order, the BUS# got reordered.
It can cause big problems, if board were previously configured for inputs but suddenly start get output signals. (Planning to plug in similar board to each one.)

[23:15:30] openhabian@openhab:~$ sudo i2cdetect -l
i2c-1   i2c             bcm2835 I2C adapter                     I2C adapter
i2c-8   i2c             i2c-tiny-usb at bus 001 device 006      I2C adapter
i2c-7   i2c             i2c-tiny-usb at bus 001 device 004      I2C adapter
[23:15:59] openhabian@openhab:~$ sudo i2cdetect -l
[sudo] password for openhabian:
i2c-1   i2c             bcm2835 I2C adapter                     I2C adapter
i2c-8   i2c             i2c-tiny-usb at bus 001 device 010      I2C adapter
i2c-7   i2c             i2c-tiny-usb at bus 001 device 008      I2C adapter
[19:45:40] openhabian@openhab:~$ sudo i2cdetect -y 7
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
PizzaProgram commented 4 years ago

Found this, but don't know how to implement it.
Also opened a Topic at RPi forum, but no answers yet.

harbaum commented 4 years ago

Other possible solution: Add an i2c eeprom to each bus with some unique ID. Then read the IDs from eeprom to know which bus you are talking to.

PizzaProgram commented 4 years ago

I still believe it is easier to modify the name of each firmware. Found these 2 lines at usbconfig.h :

#define USB_CFG_DEVICE_NAME 'i','2','c','-','t','i','n','y','-','u','s','b'
#define USB_CFG_DEVICE_NAME_LEN 12

So, if I find out how to recompile 10x with alternate numbered names, like:

#define USB_CFG_DEVICE_NAME 'i','2','c','-','t','i','n','y','-','u','s','b','-','5','1'
#define USB_CFG_DEVICE_NAME_LEN 15

main51.hex main52.hex ... etc... than I can maybe put an overlay to boot loader of RPi. (config.txt) to define a fixed I2C BUS address attached 1-1 to each name.

My fear is:

harbaum commented 4 years ago

The driver recognizes the device by USB IDs. Changing the name should not hurt.

drawkula commented 4 years ago

Maybe setting

/*#define USB_CFG_SERIAL_NUMBER   'N', 'o', 'n', 'e' */                                               
/*#define USB_CFG_SERIAL_NUMBER_LEN   0 */                                                            

and trying to detect this in an own UDEV rule is safer.

I don't know what UDEV can do with I2C devices, but for others it e.g. can make symlinks with names you want.

See: http://hintshop.ludvig.co.nz/show/persistent-names-usb-serial-devices

zgyarmati commented 4 years ago

Indeed, using udev is the canonical way to solve this kind of issues under Linux. If you run udevadm monitor (as root), while plugging in/unplugging the device, you will see the corresponding udev events, for instance on my laptop:

KERNEL[860.626226] add /devices/pci0000:00/0000:00:14.0/usb3/3-2 (usb) KERNEL[860.626618] add /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0 (usb) KERNEL[860.627646] add /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0/i2c-21/i2c-dev/i2c-21 (i2c-dev) KERNEL[860.628248] add /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0/i2c-21 (i2c) KERNEL[860.628390] bind /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0 (usb) KERNEL[860.628478] bind /devices/pci0000:00/0000:00:14.0/usb3/3-2 (usb) UDEV [860.655529] add /devices/pci0000:00/0000:00:14.0/usb3/3-2 (usb) UDEV [860.657505] add /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0 (usb) UDEV [860.659043] add /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0/i2c-21/i2c-dev/i2c-21 (i2c-dev) UDEV [860.659981] add /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0/i2c-21 (i2c) UDEV [860.661190] bind /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0 (usb) UDEV [860.662590] bind /devices/pci0000:00/0000:00:14.0/usb3/3-2 (usb)

------>8------>8------>8------>8------>8------>8--- UNPLUG--->8------>8------>8------>8------>8------->8

KERNEL[862.914521] remove /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0/i2c-21/i2c-dev/i2c-21 (i2c-dev) KERNEL[862.914563] remove /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0/i2c-21 (i2c) KERNEL[862.914591] unbind /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0 (usb) KERNEL[862.914629] remove /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0 (usb) KERNEL[862.914692] unbind /devices/pci0000:00/0000:00:14.0/usb3/3-2 (usb) KERNEL[862.914728] remove /devices/pci0000:00/0000:00:14.0/usb3/3-2 (usb) UDEV [862.916721] remove /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0/i2c-21/i2c-dev/i2c-21 (i2c-dev) UDEV [862.917911] remove /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0/i2c-21 (i2c) UDEV [862.919546] unbind /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0 (usb) UDEV [862.921160] remove /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0 (usb) UDEV [862.922226] unbind /devices/pci0000:00/0000:00:14.0/usb3/3-2 (usb) UDEV [862.928742] remove /devices/pci0000:00/0000:00:14.0/usb3/3-2 (usb)

As you can see, also the USB port is identified, so if you plug the devices always to the same port, you can also identify them, and creating a symlink to the freshly created I2C device accordingly.

If the USB port is not predictable, than you can also run an external program from the udev rule to create the desired name for the device (ie. i2cdetect via a bash script to get the available i2c slave addresses on the plugged in i2c bus), and based on the available addresses, you can figure out which bus you are on. See http://www.reactivated.net/writing_udev_rules.html#external-naming.

harbaum commented 4 years ago

You can also distinguish the devices by their position in the physical USB device tree. This information can be gathered from the sysfs or indirectly using tools line usb-devices.

PizzaProgram commented 4 years ago

while plugging in/unplugging the device

That's not possible if working remotely. The device HAS TO HAVE a unique name so it can be identified. Like: i2c-tiny-usb-pushbuttons-inputs or i2c-tiny-usb-rollersh-outputs

You can also distinguish the devices by their position in the physical USB device tree

That's an other possibility that CAN happen in real life scenarios and needs to be prevented:

A unique identification is needed to set FIXed I2C Bus addresses, so no accidents may happen even if:

A wrong identification of the bus number or device name can cause serious problems. (After a power-outage the solar system overheats, or the roller shutter goes suddenly down to the kids head.. etc.)

zgyarmati commented 4 years ago

while plugging in/unplugging the device

That's not possible if working remotely. The device HAS TO HAVE a unique name so it can be identified. Like: i2c-tiny-usb-pushbuttons-inputs or i2c-tiny-usb-rollersh-outputs

Ah, i meant that you can use the udevadm monitor during development, to figure out what events/filters to implement in your udev rule.

You can also distinguish the devices by their position in the physical USB device tree

That's an other possibility that CAN happen in real life scenarios and needs to be prevented:

* what if someone is switching the order? Or the USB HUB needs to be replaced? etc...

A unique identification is needed to set FIXed I2C Bus addresses, so no accidents may happen even if:

* one of the devices gets unplugged and plugged in into an other USB slot or to a HUB

* if the system reboots and order changes

A wrong identification of the bus number or device name can cause serious problems. (After a power-outage the solar system overheats, or the roller shutter goes suddenly down to the kids head.. etc.)

Well, in this scenario either you have to physically make impossible to connect the devices to other USB plugs or/and indeed identify the bus somehow, for example by the available I2C addresses on the bus (if they are different), or as @harbaum suggested, by placing an i2c eeprom to each bus with some unique ID. Of course it's also possible to flash different fw-s (with different name or PID) to your i2c-tiny-usb boards as suggested above, but in my experience it's can get messy if one site have multiple devices with almost the same fw (what if you have to replace because of malfunction or anything). If you can share same details about your I2C busses (and about the differences between them on which it's possible to distinguish them, if any), i think we can lay out a more specific example.