# USB-I2C bridge (ATmega8U2 + TCA9539) USB CDC-ACM (virtual COM port) to I2C master. No LUFA, no interrupts: ~2.5 KB flash. * Windows 10/11: binds inbox `usbser.sys` automatically (no driver/INF). Windows 7/8 need a stock CDC INF. * Linux: `cdc_acm` -> `/dev/ttyACMx`. Add the udev rule below so ModemManager does not probe it. * I2C is bit-banged (the 8U2 has no TWI): SCL=PD3, SDA=PD2, open drain. **External pull-ups (2.2-4.7 k to 5 V) are required.** Default ~400 kHz (`set_delay(4)`), `set_delay(0)` is ~1 MHz (TCA9539 supports Fm+ if your pull-ups/capacitance allow). * Clock stretching supported; stuck-SDA bus recovery runs automatically before a transaction. ## Build / flash (USBasp) ``` cd firmware make make fuses # once: external crystal, CKDIV8 off (lfuse FF hfuse D9 efuse F4 - same as Arduino Uno 8U2) make flash ``` Without the crystal fuse the chip runs from the 8 MHz/8 RC and USB will not enumerate. Flashing over ISP overwrites any DFU bootloader. Use `make VBUS=1` if PB6 carries a VBUS sense (attach to USB only while PB6 high); not needed for a bus-powered board. ## Protocol (binary, 0xA5-framed; frames may be concatenated) | Request | Reply | |---|---| | `A5 01 addr wlen rlen wdata..` (I2C xfer, 7-bit addr, <=32 B per phase; wlen&rlen>0 = repeated START; both 0 = probe) | `status [rdata]` | | `A5 02 n` set SCL delay | `status` | | `A5 03` ping | `00 proto maxlen` | | `A5 04` bus recovery | `status` | Status: 0 OK, 1 NACK addr, 2 NACK data, 3 bus error, 0x10 bad op, 0x11 bad length. Bytes outside a frame are ignored and a stalled frame is dropped after ~100 ms. **Speed:** a USB bulk round trip is ~1 ms, so unbatched transactions are ~1000/s. Pipeline many frames in one write (`Bridge.batch`): the device answers a whole 64-byte OUT packet with one IN packet. ## Host ``` pip install pyserial python host/usbi2c.py COM5 # or /dev/ttyACM0 : scan, blink port 0, benchmark ``` ```python from usbi2c import Bridge, TCA9539 io = TCA9539(Bridge("COM5"), 0x74) # A1/A0 select 0x74..0x77 io.set_direction(0xFF00); io.write(0x00AA); print(hex(io.read())) ``` Linux udev (`/etc/udev/rules.d/99-usbi2c.rules`): ``` SUBSYSTEM=="tty", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="0001", ENV{ID_MM_DEVICE_IGNORE}="1", MODE="0666" ``` VID/PID 1209:0001 is the pid.codes test pair; change it in `usb.c` for anything shipped.