chili-chips-ba / openeye-CamSI

A truly opensource camera serial interface. No frills. No backdoors that compromise security. Outstanding signal integrity. Hi-rez video pipeline with remote connectivity. For Sony, Series7 & open FPGA makers on limited budget. Augments openXC7 CI/CD, challenging its timing-savvy. Promotes the lesser-known EU boards.
https://nlnet.nl/project/TISG
BSD 3-Clause "New" or "Revised" License
22 stars 5 forks source link

issue#2 - Testbench for I2C subsystem #14

Open Juninho99 opened 4 months ago

Juninho99 commented 4 months ago

Writing Testbench for I2C Part of Our Camera

We need to write a testbench for the I2C part of our camera. For this purpose, we have utilized the cocotbext-i2c library. Specifically, we used only the I2CDevice.py module from this library, which emulates the slave device. The master part, however, was implemented directly in RTL.

Challenges Encountered:

  1. SDA/SCL Bidirectional Signals:

    • The primary challenge was handling the bidirectional (inout) nature of the SDA and SCL lines.
    • To resolve this, we had to define these lines as follows in our RTL code:
      inout tri1 i2c_sda,
      inout tri1 i2c_scl,
    • This specific declaration was necessary for cocotb to properly drive these signals.
  2. Simulator Selection:

    • Another significant issue was choosing the appropriate simulator.
    • Verilator, which is commonly used, does not support 'Z (high impedance) and 'X (unknown) values, supporting only log0 and log1.
    • This limitation made it unsuitable for our testbench, requiring us to explore alternative simulators that can handle these signal states.
Juninho99 commented 4 months ago

Regardless of how we attempted to assign values through cocotb simulation to the variables i2c_sda_di, i2c_scl_di, i2c_sda_do, or i2c_scl_do, which are connected to the IOBUF module, the value remained as determined by the RTL.

Various approaches such as Force, immediatevalue, and others were tried, but none were successful. Ultimately, we created an empty IOBUF module, which allowed setting values only on the I (input) ports, while the O (output) ports did not allow this.

All of these attempts were made using Verilator.

In the end, we switched to Icarus, which supports not only 0 and 1 but also 'X and 'Z, and there were absolutely no issues with the original IOBUF module or the I2C simulation.

Juninho99 commented 4 months ago

We used the cocotbext-i2c library for simulating the slave device. In the Python script I2CDevice.py, it was necessary to add the following to the constructor:

#....before
def __init__(self, sda=None, sda_o=None, scl=None, scl_o=None, *args, **kwargs):
    self.log = logging.getLogger(f"cocotb.{sda._path}")
    self.sda = sda
    #......
#....after
def __init__(self, addr=None, sda=None, sda_o=None, scl=None, scl_o=None, *args, **kwargs):
    self.log = logging.getLogger(f"cocotb.{sda._path}")
    self.sda = sda
    self.addr = addr
    #.....

These changes were necessary for it to work properly. After making these modifications and running the cocotb simulation with the Icarus simulator, everything worked as expected. A testament to this is the successful write of 65 registers in the slave device.

image

chili-chips-ba commented 4 months ago

do we still need this?:

`ifdef COCOTB_SIM
   inout  tri1   i2c_sda,
   inout  tri1   i2c_scl,
`else
   inout  wire   i2c_sda,
   inout  wire   i2c_scl,
`endif //COCOTB_SIM

If cocoTB+Verilator cannot override O port of the dummy IOBUF, try doing this in the dummy IOBUF:

logic  O_from_coco;
assign O = O_from_coco;

then override O_from_coco, which is now an input.

chili-chips-ba commented 4 months ago

Also, look for all instances of COCOTB_SIM macro in RTL and try to remove them. Only if absolutely not possible, replace them withSIM_ONLY. The goal is to rationalize the use of macros, as they have global scope.

chili-chips-ba commented 2 weeks ago

@Juninho99 is this dev item now ripe for closure?