How to access PS IIC / I2C in PYNQ

I want to read/write the I2C bus from the zynq core directly, no PL involved, no axi_iic IP instantiated. I hope that I can use either the python in jupyter notebook (using smbus2 python module) or from terminal use the standard linux i2c library (i2cdetect, i2cget, i2cset…) to access the bus.

It seems the PYNQ software had loaded some driver for the I2C bus, but I didn’t find how to use it and/or unload it.

  • PYNQ version & Board name & Tool Version
    PYNQ 3.0.0
    ZCU216 board
  • Full details of the error message you see, or a detailed description of the problem you experience.
i2cget  0 0x20 0 b 
Error: Could not set address to 0x20: Device or resource busy
  • Steps to reproduce the problem, and if needed: source code and bitstream or any relevant files

For a simplest, bare minimal PS setup as below, just the PS only


And the only enabled IO is the I2C:

  • Debug steps that you have taken to resolve the problem

If I ssh to the board, in the terminal, I can see run the

i2cdetect -l
i2c-0	i2c       	Cadence I2C at ff020000         	I2C adapter
i2c-1	i2c       	Cadence I2C at ff030000         	I2C adapter
i2c-2	i2c       	i2c-0-mux (chan_id 0)           	I2C adapter
i2c-3	i2c       	i2c-0-mux (chan_id 1)           	I2C adapter
i2c-4	i2c       	i2c-0-mux (chan_id 2)           	I2C adapter
i2c-5	i2c       	i2c-0-mux (chan_id 3)           	I2C adapter
i2c-6	i2c       	i2c-1-mux (chan_id 0)           	I2C adapter
i2c-7	i2c       	i2c-1-mux (chan_id 1)           	I2C adapter
i2c-8	i2c       	i2c-1-mux (chan_id 2)           	I2C adapter
i2c-9	i2c       	i2c-1-mux (chan_id 3)           	I2C adapter
i2c-10	i2c       	i2c-1-mux (chan_id 4)           	I2C adapter
i2c-11	i2c       	i2c-1-mux (chan_id 5)           	I2C adapter
i2c-12	i2c       	i2c-1-mux (chan_id 6)           	I2C adapter
i2c-13	i2c       	i2c-1-mux (chan_id 7)           	I2C adapter
i2c-14	i2c       	i2c-1-mux (chan_id 0)           	I2C adapter
i2c-15	i2c       	i2c-1-mux (chan_id 1)           	I2C adapter
i2c-16	i2c       	i2c-1-mux (chan_id 2)           	I2C adapter
i2c-17	i2c       	i2c-1-mux (chan_id 3)           	I2C adapter
i2c-18	i2c       	i2c-1-mux (chan_id 4)           	I2C adapter
i2c-19	i2c       	i2c-1-mux (chan_id 5)           	I2C adapter
i2c-20	i2c       	i2c-1-mux (chan_id 6)           	I2C adapter
i2c-21	i2c       	i2c-1-mux (chan_id 7)           	I2C adapter

And if I try to read

i2cget 0 0x20 7 b 
Error: Could not set address to 0x20: Device or resource busy

But if I really force it

i2cget -f -y 0 0x20 7 b 
0xff

I feel this readout value is correct by changeing the data address 0,1,2,3,4,5,6,7, the value changes and compare with the datasheet, they all make sense.

The same thing can be repeated in python using the smbus2 in pynq jupyter notebook if I force the read:

It seems some driver was loaded for the I2C bus. Then go back to the terminal:

lsmod
Module                  Size  Used by
zocl                  167936  0
uio_pdrv_genirq        16384  0

sudo modprobe -r zocl
[sudo] password for xilinx: 

lsmod
Module                  Size  Used by
uio_pdrv_genirq        16384  0

sudo modprobe -r uio_pdrv_genirq
lsmod
Module                  Size  Used by

sudo i2cget 0 0x20 0 b
Error: Could not set address to 0x20: Device or resource busy

I can see two modules were loaded, so I try to remove them using the modprobe -r.
Even after both modules removed, I still do not have access to the device

I have read the discussion in other thread

Where he is using the pynq.lib.iic.AxiIIC, where got me confused, because there seems have an axi_iic_ps2 in the overlay. But after I load the overlay, in the overlay, I do not have that axi_iic_ps2 or something similar:

In another post discussing about how to use the AxiIIC How to use pynq.lib.iic.AxiIIC? - #2 by marioruiz, it is suggested there should have something in the ol.ip_dict, but my ip_dict only have one key for the ps,
image

And inside the dict, the device the

{'type': 'xilinx.com:ip:zynq_ultra_ps_e:3.4',
 'gpio': {},
 'interrupts': {},
 'parameters': {'C_DP_USE_AUDIO': '0',
  'C_DP_USE_VIDEO': '0',
  'C_MAXIGP0_DATA_WIDTH': '128',
  'C_MAXIGP1_DATA_WIDTH': '128',
  'C_MAXIGP2_DATA_WIDTH': '32',
  'C_SAXIGP0_DATA_WIDTH': '128',
  'C_SAXIGP1_DATA_WIDTH': '128',
  'C_SAXIGP2_DATA_WIDTH': '128',
  'C_SAXIGP3_DATA_WIDTH': '128',
  'C_SAXIGP4_DATA_WIDTH': '128',
  'C_SAXIGP5_DATA_WIDTH': '128',
  'C_SAXIGP6_DATA_WIDTH': '128',
  'C_USE_DIFF_RW_CLK_GP0': '0',
  'C_USE_DIFF_RW_CLK_GP1': '0',
  'C_USE_DIFF_RW_CLK_GP2': '0',
  'C_USE_DIFF_RW_CLK_GP3': '0',
  'C_USE_DIFF_RW_CLK_GP4': '0',
  'C_USE_DIFF_RW_CLK_GP5': '0',
  'C_USE_DIFF_RW_CLK_GP6': '0',
  'C_EN_FIFO_ENET0': '0',
  'C_EN_FIFO_ENET1': '0',
  'C_EN_FIFO_ENET2': '0',
  'C_EN_FIFO_ENET3': '0',
  'C_PL_CLK0_BUF': 'FALSE',
  'C_PL_CLK1_BUF': 'FALSE',
  'C_PL_CLK2_BUF': 'FALSE',
  'C_PL_CLK3_BUF': 'FALSE',
  'C_TRACE_PIPELINE_WIDTH': '8',
  'C_EN_EMIO_TRACE': '0',
  'C_TRACE_DATA_WIDTH': '32',
  'C_USE_DEBUG_TEST': '0',
  'C_SD0_INTERNAL_BUS_WIDTH': '5',
  'C_SD1_INTERNAL_BUS_WIDTH': '5',
  'C_NUM_F2P_0_INTR_INPUTS': '1',
  'C_NUM_F2P_1_INTR_INPUTS': '1',
  'C_EMIO_GPIO_WIDTH': '96',
  'C_NUM_FABRIC_RESETS': '0',
  'PSU_VALUE_SILVERSION': '3',
  'PSU__USE__DDR_INTF_REQUESTED': '0',
  'PSU__EN_AXI_STATUS_PORTS': '0',
  'PSU__PSS_REF_CLK__FREQMHZ': '33.333',
  'PSU__PSS_ALT_REF_CLK__FREQMHZ': '33.333',
  'PSU__VIDEO_REF_CLK__FREQMHZ': '33.333',
  'PSU__AUX_REF_CLK__FREQMHZ': '33.333',
  'PSU__GT_REF_CLK__FREQMHZ': '33.333',
  'PSU__VIDEO_REF_CLK__ENABLE': '0',
  'PSU__VIDEO_REF_CLK__IO': '<Select>',
  'PSU__PSS_ALT_REF_CLK__ENABLE': '0',
  'PSU__PSS_ALT_REF_CLK__IO': '<Select>',
  'PSU__CAN0__PERIPHERAL__ENABLE': '0',
  'PSU__CAN0__PERIPHERAL__IO': '<Select>',
  'PSU__CAN0__GRP_CLK__ENABLE': '0',
  'PSU__CAN0__GRP_CLK__IO': '<Select>',
  'PSU__CAN1__PERIPHERAL__ENABLE': '0',
  'PSU__CAN1__PERIPHERAL__IO': '<Select>',
  'PSU__CAN1__GRP_CLK__ENABLE': '0',
  'PSU__CAN1__GRP_CLK__IO': '<Select>',
  'PSU__CAN0_LOOP_CAN1__ENABLE': '0',
  'PSU__DPAUX__PERIPHERAL__ENABLE': '0',
  'PSU__DPAUX__PERIPHERAL__IO': '<Select>',
  'PSU__ENET0__GRP_MDIO__ENABLE': '0',
  'PSU__ACT_DDR_FREQ_MHZ': '799.992004',
  'PSU__ENET0__GRP_MDIO__IO': '<Select>',
  'PSU__GEM__TSU__ENABLE': '0',
  'PSU__GEM__TSU__IO': '<Select>',
  'PSU__ENET0__PERIPHERAL__ENABLE': '0',
  'PSU__ENET0__FIFO__ENABLE': '0',
  'PSU__ENET0__PTP__ENABLE': '0',
  'PSU__ENET0__PERIPHERAL__IO': '<Select>',
  'PSU__ENET1__PERIPHERAL__ENABLE': '0',
  'PSU__ENET1__FIFO__ENABLE': '0',
  'PSU__ENET1__PTP__ENABLE': '0',
  'PSU__ENET1__PERIPHERAL__IO': '<Select>',
  'PSU__ENET1__GRP_MDIO__ENABLE': '0',
  'PSU__FPGA_PL0_ENABLE': '0',
  'PSU__FPGA_PL1_ENABLE': '0',
  'PSU__FPGA_PL2_ENABLE': '0',
  'PSU__FPGA_PL3_ENABLE': '0',
  'PSU__ENET1__GRP_MDIO__IO': '<Select>',
  'PSU__ENET2__PERIPHERAL__ENABLE': '0',
  'PSU__ENET2__FIFO__ENABLE': '0',
  'PSU__ENET2__PTP__ENABLE': '0',
  'PSU__ENET2__PERIPHERAL__IO': '<Select>',
  'PSU__ENET2__GRP_MDIO__ENABLE': '0',
  'PSU__ENET2__GRP_MDIO__IO': '<Select>',
  'PSU__ENET3__PERIPHERAL__ENABLE': '0',
  'PSU__ENET3__FIFO__ENABLE': '0',
  'PSU__ENET3__PTP__ENABLE': '0',
  'PSU__ENET3__PERIPHERAL__IO': '<Select>',
  'PSU__ENET3__GRP_MDIO__ENABLE': '0',
  'PSU__ENET3__GRP_MDIO__IO': '<Select>',
  'PSU__GPIO_EMIO__PERIPHERAL__ENABLE': '1',
  'PSU__GPIO_EMIO__PERIPHERAL__IO': '96',
  'PSU__GPIO0_MIO__PERIPHERAL__ENABLE': '0',
  'PSU__GPIO0_MIO__IO': '<Select>',
  'PSU__GPIO1_MIO__PERIPHERAL__ENABLE': '1',
  'PSU__GPIO1_MIO__IO': 'MIO 26 .. 51',
  'PSU__GPIO2_MIO__PERIPHERAL__ENABLE': '1',
  'PSU__GPIO2_MIO__IO': 'MIO 52 .. 77',
  'PSU__I2C0__PERIPHERAL__ENABLE': '1',
  'PSU__I2C0__PERIPHERAL__IO': 'MIO 14 .. 15',
  'PSU__I2C0__GRP_INT__ENABLE': '0',
  'PSU__I2C0__GRP_INT__IO': '<Select>',
  'PSU__I2C1__PERIPHERAL__ENABLE': '1',
  'PSU__I2C1__PERIPHERAL__IO': 'MIO 16 .. 17',
  'PSU__I2C1__GRP_INT__ENABLE': '0',
  'PSU__I2C1__GRP_INT__IO': '<Select>',
  'PSU__I2C0_LOOP_I2C1__ENABLE': '0',
  'PSU__TESTSCAN__PERIPHERAL__ENABLE': '0',
......
,
  'PSU__OVERRIDE_HPX_QOS': '0',
  'PSU__FP__POWER__ON': '1',
  'PSU__PL__POWER__ON': '1',
  'PSU__OCM_BANK0__POWER__ON': '1',
  'PSU__OCM_BANK1__POWER__ON': '1',
  'PSU__OCM_BANK2__POWER__ON': '1',
  'PSU__OCM_BANK3__POWER__ON': '1',
  'PSU__TCM0A__POWER__ON': '1',
  'PSU__TCM0B__POWER__ON': '1',
  'PSU__TCM1A__POWER__ON': '1',
  'PSU__TCM1B__POWER__ON': '1',
  'PSU__RPU__POWER__ON': '1',
  'PSU__L2_BANK0__POWER__ON': '1',
  'PSU__GPU_PP0__POWER__ON': '0',
  'PSU__GPU_PP1__POWER__ON': '0',
  'PSU__ACPU0__POWER__ON': '1',
  'PSU__ACPU1__POWER__ON': '1',
  'PSU__ACPU2__POWER__ON': '1',
  'PSU__ACPU3__POWER__ON': '1',
  'PSU__UART0__PERIPHERAL__ENABLE': '0',
  'PSU__UART0__PERIPHERAL__IO': '<Select>',
  'PSU__UART0__MODEM__ENABLE': '0',
  'PSU__UART1__PERIPHERAL__ENABLE': '0',
  'PSU__UART1__PERIPHERAL__IO': '<Select>',
  'PSU__UART1__MODEM__ENABLE': '0',
  'PSU__UART0_LOOP_UART1__ENABLE': '0',
  'PSU__USB0__PERIPHERAL__ENABLE': '0',
  'PSU__USB0__PERIPHERAL__IO': '<Select>',
  'PSU__USB0__RESET__ENABLE': '0',
  'PSU__USB0__RESET__IO': '<Select>',
  'PSU__USB__RESET__MODE': '<Select>',
  'PSU__USB__RESET__POLARITY': '<Select>',
  'PSU__USB1__PERIPHERAL__ENABLE': '0',
  'PSU__USB1__PERIPHERAL__IO': '<Select>',
  'PSU__USB1__RESET__ENABLE': '0',
  'PSU__USB1__RESET__IO': '<Select>',
  'PSU__USB3_0__PERIPHERAL__ENABLE': '0',
  'PSU__USB3_0__PERIPHERAL__IO': '<Select>',
  'PSU__USB3_1__PERIPHERAL__ENABLE': '0',
  'PSU__USB3_1__PERIPHERAL__IO': '<Select>',
  'PSU__USB3_0__EMIO__ENABLE': '0',
  'PSU__USB2_0__EMIO__ENABLE': '0',
  'PSU__USB3_1__EMIO__ENABLE': '0',
  'PSU__USB2_1__EMIO__ENABLE': '0',
  'PSU__USE__USB3_0_HUB': '0',
  'PSU__USE__USB3_1_HUB': '0',
  'PSU__USE__ADMA': '0',
  'PSU__USE__M_AXI_GP0': '0',
  'PSU__M_AXI_GP0_SUPPORTS_NARROW_BURST': '1',
  'PSU__MAXIGP0__DATA_WIDTH': '128',
  'PSU__USE__M_AXI_GP1': '0',
  'PSU__M_AXI_GP1_SUPPORTS_NARROW_BURST': '1',
  'PSU__MAXIGP1__DATA_WIDTH': '128',
  'PSU__USE__M_AXI_GP2': '0',
  'PSU__M_AXI_GP2_SUPPORTS_NARROW_BURST': '1',
  'PSU__MAXIGP2__DATA_WIDTH': '32',
  'PSU__USE__S_AXI_ACP': '0',
  'PSU__USE__S_AXI_GP0': '0',
  'PSU__USE_DIFF_RW_CLK_GP0': '0',
  'PSU__SAXIGP0__DATA_WIDTH': '128',
  'PSU__USE__S_AXI_GP1': '0',
  'PSU__USE_DIFF_RW_CLK_GP1': '0',
  'PSU__SAXIGP1__DATA_WIDTH': '128',
  'PSU__USE__S_AXI_GP2': '0',
  'PSU__USE_DIFF_RW_CLK_GP2': '0',
  'PSU__SAXIGP2__DATA_WIDTH': '128',
  'PSU__USE__S_AXI_GP3': '0',
  'PSU__USE_DIFF_RW_CLK_GP3': '0',
  'PSU__SAXIGP3__DATA_WIDTH': '128',
  'PSU__USE__S_AXI_GP4': '0',
  'PSU__USE_DIFF_RW_CLK_GP4': '0',
  'PSU__SAXIGP4__DATA_WIDTH': '128',
  'PSU__USE__S_AXI_GP5': '0',
  'PSU__USE_DIFF_RW_CLK_GP5': '0',
  'PSU__SAXIGP5__DATA_WIDTH': '128',
  'PSU__USE__S_AXI_GP6': '0',
  'PSU__USE_DIFF_RW_CLK_GP6': '0',
  'PSU__SAXIGP6__DATA_WIDTH': '128',
  'PSU__USE__S_AXI_ACE': '0',
  'PSU__TRACE_PIPELINE_WIDTH': '8',
  'PSU__EN_EMIO_TRACE': '0',
  'PSU__USE__AUDIO': '0',
  'PSU__USE__VIDEO': '0',
  'PSU__USE__PROC_EVENT_BUS': '0',
  'PSU__USE__FTM': '0',
  'PSU__USE__CROSS_TRIGGER': '0',
  'PSU__FTM__CTI_IN_0': '0',
  'PSU__FTM__CTI_IN_1': '0',
  'PSU__FTM__CTI_IN_2': '0',
  'PSU__FTM__CTI_IN_3': '0',
  'PSU__FTM__CTI_OUT_0': '0',
  'PSU__FTM__CTI_OUT_1': '0',
  'PSU__FTM__CTI_OUT_2': '0',
  'PSU__FTM__CTI_OUT_3': '0',
  'PSU__FTM__GPO': '0',
  'PSU__FTM__GPI': '0',
  'PSU__USE__GDMA': '0',
  'PSU__USE__IRQ': '0',
  'PSU__USE__IRQ0': '0',
  'PSU__USE__IRQ1': '0',
  'PSU__USE__CLK0': '0',
  'PSU__USE__CLK1': '0',
  'PSU__USE__CLK2': '0',
  'PSU__USE__CLK3': '0',
  'PSU__USE__RST0': '0',
  'PSU__USE__RST1': '0',
  'PSU__USE__RST2': '0',
  'PSU__USE__RST3': '0',
  'PSU__USE__FABRIC__RST': '0',
  'PSU__USE__RTC': '0',
  'PSU__PRESET_APPLIED': '0',
  'PSU__USE__EVENT_RPU': '0',
  'PSU__USE__APU_LEGACY_INTERRUPT': '0',
  'PSU__USE__RPU_LEGACY_INTERRUPT': '0',
  'PSU__USE__STM': '0',
  'PSU__USE__DEBUG__TEST': '0',
  'PSU__HIGH_ADDRESS__ENABLE': '0',
  'PSU__DDR_HIGH_ADDRESS_GUI_ENABLE': '0',
  'PSU__EXPAND__LOWER_LPS_SLAVES': '0',
  'PSU__EXPAND__CORESIGHT': '0',
  'PSU__EXPAND__GIC': '0',
  'PSU__EXPAND__FPD_SLAVES': '0',
  'PSU__EXPAND__UPPER_LPS_SLAVES': '0',
........
  'PSU_MIO_14_PULLUPDOWN': 'pullup',
  'PSU_MIO_14_DRIVE_STRENGTH': '12',
  'PSU_MIO_14_POLARITY': 'Default',
  'PSU_MIO_14_INPUT_TYPE': 'cmos',
  'PSU_MIO_14_SLEW': 'slow',
  'PSU_MIO_14_DIRECTION': 'inout',
  'PSU_MIO_15_PULLUPDOWN': 'pullup',
  'PSU_MIO_15_DRIVE_STRENGTH': '12',
  'PSU_MIO_15_POLARITY': 'Default',
  'PSU_MIO_15_INPUT_TYPE': 'cmos',
  'PSU_MIO_15_SLEW': 'slow',
  'PSU_MIO_15_DIRECTION': 'inout',
  'PSU_MIO_16_PULLUPDOWN': 'pullup',
  'PSU_MIO_16_DRIVE_STRENGTH': '12',
  'PSU_MIO_16_POLARITY': 'Default',
  'PSU_MIO_16_INPUT_TYPE': 'cmos',
  'PSU_MIO_16_SLEW': 'slow',
  'PSU_MIO_16_DIRECTION': 'inout',
  'PSU_MIO_17_PULLUPDOWN': 'pullup',
  'PSU_MIO_17_DRIVE_STRENGTH': '12',
  'PSU_MIO_17_POLARITY': 'Default',
  'PSU_MIO_17_INPUT_TYPE': 'cmos',
  'PSU_MIO_17_SLEW': 'slow',
  'PSU_MIO_17_DIRECTION': 'inout',
........
  ...},
 'driver': pynq.overlay.DefaultIP,
 'device': <pynq.pl_server.embedded_device.EmbeddedDevice at 0xffff7d1ef190>}

Hi @Gang,

pynq.lib.iic.AxiIIC is a driver for the I2C in the PL, so this does not apply in your case.

Can you elaborate what would you like to achieve by using the IIC? What would you like to communicate with?

Mario

I understand the pynq.lib.iic.AxiIIC is for the PL AXI IIC IP.

I’d like to have general solution to talk to the I2C, and even to further expand the I2C tree and access them via PS.

For me, the IIC is already on the linux side, as I show above, the i2cget works if I force it. But some pynq/petalinux… driver is loaded so I can not talk without force it.
So that is my question here for the PYNQ community/team, how to get access PS IIC in PYNQ.

@marioruiz

I got it one step forward:
After checking the driver in

/sys/bus/i2c/drivers/pca953x

I saw the 0-0020 is there, (I don’t know why, because this is not the right chip)
from root terminal:

echo -n "0-0020" > unbind

to unbind the driver.
And then if I do the same

i2cget 0 0x20 7 b 

Or even more

for i in `seq 0 7`; do echo $i; i2cget -y 0 0x20 $i b; done
0
0x6f
1
0xa9
2
0xff
3
0xff
4
0x00
5
0x00
6
0xff
7
0xff

In the

cat /sys/bus/i2c/devices/0-0020/of_node
ti,tca6416

It give the right chip of the TI TCA6416.
The TCA6416 is pretty similar to the PCA9535, maybe they are considered to be compatible.

Now the question is

  1. How to talk to the driver in the user space if I do not manually unbind the driver?

Have you tried identifying what is using the driver? lsof or fuser