Giter Site home page Giter Site logo

harbaum / i2c-tiny-usb Goto Github PK

View Code? Open in Web Editor NEW
375.0 38.0 79.0 13.32 MB

Cheap and simple I²C to USB interface

Home Page: http://www.harbaum.org/till/i2c_tiny_usb

Shell 0.20% C 49.79% Assembly 38.77% Makefile 2.03% Python 0.37% PHP 7.56% OpenSCAD 1.27%

i2c-tiny-usb's Introduction

i2c-tiny-usb

Update 2022-01-10

The common firmware(-directory) now is also capable to compile firmwares for different tinyusbboard (16MHz/20MHz, atmega8, atmega88p, atmega168p, atmega328p) types.

Introduction

Attach any I2C client chip (thermo sensors, AD converter, displays, relais driver, ...) to your PC via USB ... quick, easy and cheap! Drivers for Linux, Windows and MacOS available.

The i2c-tiny-usb project is an open source/open hardware project. The goal of i2c-tiny-usb is to provide a cheap generic i2c interface to be attached to the usb. It is meant as a replacement for those simple and cheap printer port to i2c adapters. A USB solution has several advantages incl. the built-in power supply and a more future proof interface. Furthermore no cpu intense bitbanging is required on the host side. This USB solution even requires less parts than some printer port solutions.

While the i2c-tiny-usb was developed under and for Linux it also works under Windows and MacOS X. A windows demo driver and demo application is included to get you started immediately.

The i2c-tiny-usb project is based on:

Hardware

The prototype board including The final hardware with
a ds1621 temperature sensor the same sensor added

The hardware of the i2c-tiny-usb interface consists of the Atmel AVR ATtiny45 CPU, a cheap and easy to obtain microcontroller with 4 KBytes flash (of which ~2k are used in this application) and 256 Bytes RAM. The processor is surrounded by few other parts.

The USB interface

The USB interface of the i2c-tiny-usb interface is based on a pure software implementation and uses two pins of the AVR (PB0 and PB2). This software implementation supports low speed USB only which is signalled to the PC by resistor R1.

The I2C interface is implemented using a bitbanging approach. The hardware supported twi interface of the attiny45 is bound to hardware pins at the chip that are required for USB operation and can thus not be used for I2C. The bitbanging I2C interface being used instead may not be fully I2C compatible and thus not every I2C client chip may function correctly at this bus. No incompatibilities have been reported so far. The i2c-tiny-usb provides a software adjustable i2c clock delay allowing to configure the i2c clock. The default delay is 10us. Due to additional delays in the i2c bitbanging code this results in a i2c clock of about 50kHz.

For simplicity reasons all USB transfers are done via the control endpoint. Since the avr usb library does only support low speed devices it cannot use bulk transfers which are specified for high and full speed devices only. Low speed devices support so called interrupt transfers which are limited to a preset bandwidth while control transfers can use any free bandwidth (if there's any at all).

The device therefore uses control transfers for all of its communication. This requires some additional limitation to prevent multiple driver software (e.g. the kernel driver and the libusb based test application) to access the device at the same time. Under Linux this can be achieved by selecting certain access request types. This kind of access control may not be possible under other operating systems.

Power consumption

The whole device is a so called bus powered device. This means that the complete device is powered directly from USB. Therefore the AVR and one or more I2C client chips are powered from the USB VBUS signal.

The adapter itself draws less than 10mA and reports this to the host via its USB descriptors. The device is able to power I2C client chips as well. But since these chips vary in power consumption it is not possible to correctly include their demands into the device descriptors. It's your responsibility to keep an eye on the total power supply and especially to make sure that the entire device does not exceed the total USB limit of 500mA.

It is planned for future firmware versions to make the reported power consumption software configurable so the value can easily be adopted to the real power demands of the entire device.

Kernel driver

The i2c-tiny-usb is meant to be used with Linux. It comes with a Linux kernel driver that bridges between the USB and I2C subsystems in the Linux kernel. The driver then attaches to the USB device and make the i2c bus available to the i2c subsystem. Thus the entire setup is transparent to client applications like the lm_sensors framework and no special client chip drivers are required. Instead the drivers already present in the linux kernel are used with the i2c-tiny-usb as well. With e.g. the ds1621 temperature sensors used in the prototype the output of sensors may e.g. look like this:

ds1621-i2c-2-48
Adapter: i2c-tiny-usb at bus 003 device 017
temp:     +21.50°C (low  = +15.0°C, high = +10.0°C)  ALARM (HIGH)

Schematics and PCB

The zener diodes in the schematic are optional. They may be required since the i2c-tiny-usb is directly powered from the USBs VBUS singnal at 5V. The USB data lines (D+ and D-) are supposed to be operated at 3.3V only. Some PCs encounter problems at 5V and limiting the voltage to at most 3.6V may help. My prototype lacks these diodes since my PC works fine with D+ and D- at 5V.

Resistor R1 is 2k2 instead of 1k5 for the same reason. It is meant to pullup to 3.3V. Since we are pulling up to 5V the higher resistance is required.

Below is the final PCB layout. It consists of the USB and I2C parts only and does not include a I2C client chip. Instead it comes with a solder area for easy prototyping. I do have some of these PCBs left. Just drop me an email if you want to buy one (6 EUR per PCB + 4 EUR shipping). You can easily etch a PCB youself. Since most of the connections are on the bottom side even a single sided PCB will work. You'll just have to add the four missing connections using thin wires.

Part placement Top PCB side Bottom PCB side The final PCB

The USB connector space on the PCB provides two additional holes to allow an USB cable to be directly and firmly attached to the device without the use of the USB connector. See the image below for the desired pinout.

Direct cable wiring schema ... ... and in reality (with pcf8574 client).

Part list

You can get all parts directly via my i2c-tiny-usb part list at Reichelt. This list includes the following parts:

Part Qty Name Reichelt Part No.
D1, D2 2 3.6V zener diode ZF 3,6
Q1 1 12Mhz crystal, HC49U package 12,0000-HC49U-S
R1 1 2.2 kilo ohm resistor 1/4W 2,2k
R2, R3 2 68 ohm resistor 1/4W 68
R4, R5 2 10 kilo ohm resistor 1/4W 10k
C1, C2 2 22pF ceramic capacitor, 2.54mm KERKO 22P
C3 1 100nF capacitor, 5.08mm X7R-5 100N
C6 1 10μF electrolytic capacitor RAD 10/35
-- 1 USB-B print connector USB BW
JP1 1 4 pin I2C connector SL 1X36G 2,54
U$1 1 Attiny45 DIP 20Mhz ATTINY 45-20PU
-- 1 socket for U$1 GS 8P

Compiling the firmware

You need the AVR version of the GCC compiler to compile the firmware. Under Ubuntu you can install these with the following command:

sudo apt-get install avr-libc binutils-avr gcc-avr avrdude make

Afterwards you need to clone this repository and update the dependencies:

$ git clone https://github.com/harbaum/I2C-Tiny-USB
$ cd I2C-Tiny-USB; git submodule update --init --recursive

Finally change into the firmware directory and trigger a build of the version you need. E.g. for the version running on the ATTiny45:

$ cd firmware
$ make -f Makefile-avrusb.tiny45

This will result in the firmware stored the file firmware.hex.

Uploading the firmware

If you are familiar with Atmel programming you probably know what you are doing. The Makefile in i2c-tiny-usb/firmware/Makefile assumes, that you are using the stk500 for programming the attiny45. Since all 6 user configurable pins of the ATtiny45 are required, the so called high voltage serial programming (hvsp) mode of the attiny45 has to be used. E.g. the stk500, the AVR-Doper and the AVR Dragon are supporting this mode.

Two versions of the firmware can be compiled which are based on different USB software implementations for the AVR. If in doubt use the pre-compiled firmware.hex file distributed with the source code.

Troubleshooting

Problem: The device seems to work fine, it is detected correctly by Linux, but i get various error messages when accessing it from the test application.

Solution: First make sure that the kernel driver is not loaded when trying to use the libusb based test application. Since the kernel driver is part of the main kernel line, it may even be already installed on your system. Type rmmod i2c_tiny_usb to remove it. Also make sure that you run the test application as the root user since the standard user may lack the rights to access all aspects of the i2c_tiny_usb hardware.

Problem: The device is not properly detected. Linux reports an error like "device not accepting address" in the system log.

Solution: The USB interface is not working at all. Please make sure that the AVR CPU is correctly flashed and that the fuses are set correctly. Another reason may be that the zener diodes are too slow (see next problem).

Problem: The device is not properly detected. Linux reports an error like "device descriptor read/all, error -71" in the system log.

Solution: The device is working partly and the USB transfers are unreliable. This is often cauesed by "slow" high current zener diodes. On a previous reichelt list i had those wrong zener types. These slow diodes often seem to have thicker wires than the other parts. You can just try to remove the zener diodes and the device will work if your host PC copes with 5V on the USB data lines. Also using a USB hub between a device without zener diodes and the PC may lead to a working setup. Otherwise you need faster diodes as a replacement (reichelt no "zf 3,6" as on the current reichelt list).

Using the device with a Nokia N800

The i2c_tiny_usb works at various hosts. One of the most interesting ones is the Nokia N800. You need to enable USB host mode capabilities on your N800 to make use of the i2c-tiny-usb.

The demo application (contained in the i2c_tiny_usb archive) can easily be installed on the N800 from the harbaum.org repository using the install button below. Once it's installed it can be run from extras menu. The current version comes with a udev rules file granting user access to the i2c-tiny-usb and thus not requiring root rights anymore. Below is a screenshot of my n800 with a ds1621 equipped i2c-tiny-usb.

The i2c_usb demo application currently supports two I2C client chips, a ds1621 temperature sensor and a pcf8574 parallel port driver (with some LEDs attached to it, so you can see what's happening). Further chips can easily be supported, just use the source above ... Happy hacking with the N800!

Links

User contributions


Till Harbaum

http://www.harbaum.org/till

i2c-tiny-usb's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

i2c-tiny-usb's Issues

submodule update

you need to add to the description what must be done after the clone to update the submodule.
git submodule update --init --recursive

Will I2C-Tiny-USB work with LilyPads based on the ATTiny85

I want to try to replicate this project. However, I have a hard time obtaining a ATTiny85 chip with a MicroUSB-Port (like the blue one here: https://www.aliexpress.com/item/32432747996.html). I tried to order it twice but the order got cancelled each time as it doesn't seem to be available atm.

However, there are plenty of offers for a LilyPad with the ATTiny85 (e.g. here: https://www.aliexpress.com/item/4000943968380.html).

Is there any reason the project would not work with this board?

Side note: I also found offers for the digispark, however I would prefer a solution with a MicroUSB cable.

/dev/i2c-* disappears after one access

Hi.
i got it working after about 2 hours of googleing around the world.
module i2c-dev have to be loaded!!!

now i can execute i2cdetect -y 8
it read all adresses.. find my BME280 at 0x76 and after that, the bus is disappeared in /dev.

why?

can you help me?

EDIT: the usb device isn't listed any more at lsusb after read.

Multiple digispark USB

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

USB_CFG_LONG_TRANSFERS?

Hello.
I am trtying i2c-tiny-usb + digispark for my project.
This is a linux host.

I am now trying CFG_USB_LONG_TRANSFERS in usbconfig.h with 1 since I am seeing my I2C read() fails with 205 bytes or larger data.

Though I have not succeeded yet with the larger data transfers, at least I think following changes are needed in order to build this configuration properly.
(At least, passing compilation.)

I wonder if anyone already tried CFG_USB_LONG_TRANSFER configuration.
Or possible clue to solve my issue of not able to read() 205 bytes or more?

====
diff --git a/digispark/main.c b/digispark/main.c
index 472595c..1b7b76e 100644
--- a/digispark/main.c
+++ b/digispark/main.c
@@ -359,7 +359,8 @@ struct i2c_cmd {
static uchar status = STATUS_IDLE;

-static uchar i2c_do(struct i2c_cmd *cmd) {
+//static uchar i2c_do(struct i2c_cmd *cmd) {
+static usbMsgLen_t i2c_do(struct i2c_cmd *cmd) {
uchar addr;

LED_PORT |= LED_BV
@@ -398,7 +399,8 @@ static uchar i2c_do(struct i2c_cmd *cmd) {

LED_PORT &= ~LED_BV;

  • return(cmd->len?0xff:0x00);
  • //return(cmd->len?0xff:0x00);
  • return(cmd->len?USB_NO_MSG:0x00);
    }

@@ -484,7 +486,8 @@ uchar usbFunctionWrite(uchar data, uchar len)
/
------------------------------------------------------------------------- /
/
------------------------ interface to USB driver ------------------------ /
/
------------------------------------------------------------------------- */
-uchar usbFunctionSetup(uchar data[8])
+//uchar usbFunctionSetup(uchar data[8])
+usbMsgLen_t usbFunctionSetup(uchar data[8])
{
static uchar replyBuf[4];
usbMsgPtr = replyBuf;

"Failed to read functionality" after program

After programming my ATTiny85 with the included main.hex I am getting the following messages in dmesg.

[ 1829.201263] usb 3-1.3: new low-speed USB device number 10 using xhci_hcd
[ 1829.291719] usb 3-1.3: New USB device found, idVendor=16d0, idProduct=0753
[ 1829.291726] usb 3-1.3: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[ 1831.328892] usb 3-1.3: USB disconnect, device number 10
[ 1831.558550] usb 3-1.3: new low-speed USB device number 11 using xhci_hcd
[ 1831.639708] usb 3-1.3: New USB device found, idVendor=0403, idProduct=c631
[ 1831.639716] usb 3-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 1831.639720] usb 3-1.3: Product: i2c-tiny-usb
[ 1831.639724] usb 3-1.3: Manufacturer: Till Harbaum
[ 1831.639728] usb 3-1.3: SerialNumber: 0215
[ 1831.640173] i2c-tiny-usb 3-1.3:1.0: version 2.01 found at bus 003 address 011
[ 1831.641538]  (null): failure reading functionality
[ 1831.641575] i2c i2c-4: failure reading functionality
[ 1831.641678] i2c i2c-4: connected i2c-tiny-usb device

The device shows up as a "dummy bus"

i2c-4	dummy     	i2c-tiny-usb at bus 003 device 011	Dummy bus

I tried it both with 10K resisters and internal resisters. Same error.
IMG_0960

No precompiled binaries present

Hello,

The readme mentions "If in doubt use the pre-compiled firmware.hex file distributed with the source code". However, I cannot find it. Is it not there or am I overlooking something? If it is not there, would it be possible to include it?

Kind regards,
Roy

Writing a device tree overlay for a i2c device attached to i2c-tiny-usb

Has anybody managed to write a device tree overlay to use a i2c device kernel driver?

I'm trying to connect a touch screen via a i2c-tiny-usb adapter on a raspberry pi (the normal i2c bus is disabled because I'm using a DPI screen).

I've managed to get the interrupt details setup but it looks like the overlay is getting attached to the disabled built in i2c bus and I need to work out how to write an overlay to add the extra i2c bus.

/dts-v1/;
/plugin/;

/ {
	compatible = "brcm,bcm2837", "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";

	fragment@0 {
		target = <&i2c>;

		__overlay__ {
			status = "okay";
		};
	};

	fragment@1 {
               target = <&gpio>;
                __overlay__ {
                        st16xx_pins: st16xx_pins {
                                brcm,pins = <27>; /* GPIO */
                                brcm,function = <0>; /* in */
                                brcm,pull = <2>; /* up */
                        };
                };
	};

	fragment@2 {
		target = <&i2c>;
		__overlay__ {
			#address-cells = <1>;
			#size-cells = <0>;
			st16xx: st16xx@38 {
				compatible = "sitronix,st16xx-ts", "sitronix,st16xx";
				reg = <0x38>;
				pinctrl-names = "default";
				interupt-parent = <&gpio>;
				interrupts = <27 0x8>;
			};
		};
	};

	__overrides__ {
                addr = <&st16xx>, "reg:0";
        };

};

If I've understood the problem is with the target = <&i2c> lines which point to the existing bus. I think I need to create a overlay named i2c3 to match the new bus.

(also asked on rPi Stack Overflow site here: https://raspberrypi.stackexchange.com/q/101823/37180)

Read errors with large size data

Hello.
I am seeing read errors (121 EREMOTEIO) with i2c-tiny-usb + digispark.
Host is Linux, and I am doing something like read(fd, buf, 210) on
/dev/i2c-7 (where my i2c-tiny-usb appears).

I am reading from an I2C device, which can respond relatevely large
size data, say, upto 1,000 bytes.
But I am beginning to see 121 errors around 204 bytes.
(Smaller number of bytes are OK. read() call fails with larger than this.)

  1. If I read one byte at a time like below, I do not get this 121 error.
    (But it is very very slow.)

i2c_smbus_read_byte_data(addr, reg)
i2c_smbus_read_byte(addr) x 210 times.

  1. I debugged for a while, and I can see if I modify a line in
    main.c:usbFunctionRead() like this, I no longer see this error, even
    if I do read(fd, buf, 210).

*data = i2c_get_u08(expected == 0)
->
//*data = i2c_get_u08(expected == 0)
*data = 0;

i.e. if I do not call i2c_get_u08() in usbFunctinoRead(), I do not get
this 121 error.

I think if I take long time in usbFunctionRead(), it may cause
something wrong and the read request fails.
(Timeout somewhere related to USB polling loop?)

For 204 bytes, usbFunctionRead() is getting called 26 times
(i2c_get_u08 is called 204 times)

I wonder if there is a way to avoid this within i2c-tiny-usb layer.

Tiny-USB hangs on host reboot

Hi,
i2c-tiny-usb (main.hex on digispark) is fine with debian host.

But if the host is rebooting, the tiny doesn´t respond to the usb registering process. After a system reboot just pulling and replugging the hardware module re-enables the module again.

Any advice for fixing? I am not familiar with the USB state machines...

Atmega8 firmware variant doesn't work

Checked USBTiny and AVRUSB variants with custom pcb and noname prototype board, both failed. Besides, other projects (like https://github.com/gblargg/vusb-joystick) works nice with my HW.
I connected D+ and D- to D2 and D3 accordingly:

#define	USB_CFG_IOPORTNAME		D
#define	USB_CFG_DMINUS_BIT		3
#define	USB_CFG_DPLUS_BIT		2

but after programming everything I can see in dmesg is

[413259.524068] usb 1-1.3: new low-speed USB device number 32 using ehci-pci
[413259.608062] usb 1-1.3: device descriptor read/64, error -32

Linux GPIOs with I2C-GPIO expanders (PCF8574)

Hi,

I have flashed a Digispark with the i2c-tiny-usb firmware, connected a PCF8574, and under linux, it seems you can obtain those 8 GPIOs exported in /sys/class/gpio.

However, I cannot manage to see them there.

Do I need those 10K resistors somewhere? I have the impression the PCF does not receive 5V on its VCC pin, so I suspect this might be the reason. Do you have a better picture or a schema where to place those 10K resistors?

That would be great to document the usage of those, as GPIOs over USB are pretty hard to get (out-of-tree driver, etc...):

http://www.zoobab.com/ch341-usb-spi-i2c-uart-isp-dongle#toc15

Driver hangs on i2cdetect if nothing connected (digispark)

I downloaded the firmware for the Digispark variant and it works fine, at least on initial testing - for example I can plug the Digispark into my Linux laptop, connect to an MCP23017 and ensure it has pullup 10K resistors, and it can detect the device (i2cdetect -y 6 in my case works fine)

However if I just plug in the digispark and let it initialise, then run i2cdetect -y the driver stops working altogether. Now, to be fair, I'm not expecting a meaningful result here. If you are running open collector, connecting to nothing, not even terminators, it's unreasonable to expect any data. But it seems bad to let the USB driver crash, because the only way to recover seems to be to power cycle the digispark by removing it from the USB and reinserting it.

Is this expected behaviour and is there any way to make the device at least self-heal without requiring manual power cycling? Maybe for example having a watchdog timer to force a reset if the usb polling loop breaks?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.