Figure 6-1 shows the code flow for this example.
USB to I2C direction:
- TinyUSB invokes tud_cdc_rx_cb()
each time the USB host sends data. The callback calls usb2i2c_pushTask(), which
reads up to 64 bytes from the USB CDC interface and queues them as a task in
gUSB2I2CTask.
- In the main loop, when
gUSB2I2CTask.fifoCount > 0, usb2i2c_popTask() configures DMA channel CH1 with
the task buffer address and length, then starts the I²C write transfer to the
target device.
- The TX DMA done interrupt fires
when DMA finishes loading the I²C TX FIFO. The handler clears the STOP interrupt
status flag and enables the STOP interrupt. The STOP interrupt fires when the
I²C STOP condition appears on the bus. The handler calls fifoCompleteRead() to
release the task and clears i2cInProgress.
I2C to USB direction:
- The I2C target device asserts the
data-ready GPIO pin (rising edge). The GPIO interrupt handler sets
i2ctargetDataReady
- In the main loop, when
i2ctargetDataReady is set and i2cInProgress is false, i2c2usb_pushTask()
configures DMA channel CH0 for the receive buffer, starts the I2C read transfer
for 64 bytes, and sets i2cInProgress. The data length is always fixed to 64
bytes.
- The RX DMA done interrupt fires
when all 64 bytes have been received. The handler calls fifoCompleteWrite() to
mark the task ready for USB transmission, clears i2ctargetDataReady, and clears
i2cInProgress.
- In the main loop, when
gI2C2USBTask.fifoCount > 0, i2c2usb_popTask() checks that the TinyUSB CDC TX
FIFO has sufficient space, writes the buffered data, flushes it to the host, and
calls fifoCompleteRead() to release the task.