Python I2C... Almost all working, but

So thanks to a few people on here ( especially hanahKobain ) for pointing me in helpful directions… I built an image including “pinpong” and was able to actually create a python app, that runs upon boot and displays IP addresses (and time) on an SSD1306 display.
BUT… there seems to be a problem with using i2c.scan() under pinpong.
Not sure why, but it does NOT show all available i2c devices on bus1.
Yet if I do, “i2cdetect -r 1 -y” from terminal, it shows all available i2c devices.
i2c.scan seems to have a limited range of devices it looks for.
Anyone know HOW to make i2c.scan() look at ALL i2c addresses?

Also, when I change the bus from 1 to 2 (there is a valid i2cdev-2 on my boards as I can see devices on it when I do i2cdetect -r 2 -y.), it gives me an error saying I can only use 0,1,2 busses???

Here is the output from an example app supplied with pinpong (with a little modification where I attempted to detect devices by looping thru addresses and attempting i2c.read_byte(device)…

[root@milkv-duo]~# python i2c_scan2.py
milkv-duo


| ____ _ ____ |
| / __ ()__ / __ ____ ____ ____ _ |
| / // / / __ / // / __ / __ / __ `/ |
| / / / / / / / // / / / / // / |
|/
/ /
/
/ /
/
/ _
// //_, / |
| v0.5.2 Designed by DFRobot /
/ |
|
_______________________________________|

<pinpong.board.Board object at 0x3fc2a40fd0>

I2C Devices:

00: – – – – – – – – – – – – – – – –
10: – – – – – – – – – – – – – – – –
20: – – – – – – – – – – – – – – – –
30: – – – – – – – – – – – – – – – –
40: – – – – – – – – – – – – – – – –
50: – – – – – – – – – – – – – – – –
60: – – – – – – – – – – – – – – – –
70: – – – – – – – – – – – – – – –
Done

[ 9461.515397] i2c i2c-1: adapter quirk: no zero length (addr 0x003d, size 0, write)
[ 9461.524653] i2c i2c-1: adapter quirk: no zero length (addr 0x003e, size 0, write)
[ 9461.533619] i2c i2c-1: adapter quirk: no zero length (addr 0x003f, size 0, write)
[ 9461.542900] i2c i2c-1: adapter quirk: no zero length (addr 0x0040, size 0, write)
[ 9461.551585] i2c i2c-1: adapter quirk: no zero length (addr 0x0041, size 0, write)
[ 9461.561077] i2c i2c-1: adapter quirk: no zero length (addr 0x0042, size 0, write)
[ 9461.569747] i2c i2c-1: adapter quirk: no zero length (addr 0x0043, size 0, write)
[ 9461.578991] i2c i2c-1: adapter quirk: no zero length (addr 0x0044, size 0, write)
[ 9461.587663] i2c i2c-1: adapter quirk: no zero length (addr 0x0045, size 0, write)
[ 9461.597157] i2c i2c-1: adapter quirk: no zero length (addr 0x0046, size 0, write)
i2c list:
0x3C

==========================

here is the output from “i2cdetect -r 1 -y”,

==========================
[root@milkv-duo]~# i2cdetect -r 1 -y
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: – – – – – – – – – – – – –
10: – – – – – – – – – – – – – – – –
20: – – – – – – – – – – – – – – – –
30: – – – – – – – – – – – – 3c – – –
40: – – – – – – – – 48 – – – – – – –
50: – – – – – – – – – – – – – – – –
60: – – – – – – – – 68 – – – – – – –
70: – – – – – – – –

==========================

1 Like

I’m sure this is because some argument of that scan method disables scanning extra range by default.

How does I²C scanning usually work? You scan all 127 addresses on the bus and see what echoes back; but I guess this scanning either doesn’t scan the whole range, or it doesn’t actually scan it.

Also, is it Duo 256M? It must be one. Judging by your other thread, at least.

Yeah, it’s a 256M.
Interestingly, I can scan I2C devices if I use SMBus, but not thru pinpong.

Yeah, the way you do it is to enumerate thru a range of device addresses and within a try…except block you attempt a write_byte(addr, 0x00) to the device address.
If no device responds… you get the except and there is no device.
If no except, there is a device.

Fairly simple.
Just don’t understand WHY i2c.scan() isn’t getting all the devices, just 0x3C.

1 Like

Here the code using SMBus.

import time
from smbus import SMBus

#--------------------------

def i2cdetect():
global bus

i2clist = []
for i in range(0x03, 0x77)  :
    try:
        bus.write_byte(i, 0x00)
        i2clist.append(i)
    except:
        pass

return i2clist

#----------------

bus = SMBus(1)

#----------------

i2clist = i2cdetect()

print(‘\nI2C Devices Found:’)
for addr in i2clist:
print(‘0x%02X’ % addr)

1 Like

I’m actually trying to find out where it is located in the source files, the pinpong lib, the heck.

duo-buildroot-sdk-v1/buildroot-2021.05/package/python-pinpong/pinpong/board.py:

class I2C:
  def __init__(self, board=None, bus_num=0):
    if isinstance(board, int):
      bus_num = board
      board = gboard
    elif board == None:
      board = gboard
    self.board = board
    if self.board.i2c[bus_num] == None:
      self.bus_num = bus_num
    
    if bus_num not in board.res["i2c"]["busnum"]:
      raise ValueError("i2c does not support this device%d"%bus_num, "Supports the i2c device list",board.res["i2c"]["busnum"])
    self.board.i2c[bus_num] = eval(self.board.res["i2c"]["class"] + "(board, bus_num)")
    self.obj = self.board.i2c[bus_num]
    
  def scan(self):
    return self.obj.scan()

And for Milk-V Duo boards this spawns a number of LinuxI2C instances:

class LinuxI2C:
  def __init__(self, board, bus_num=1):
    self.bus_num = bus_num
    self.i2c = I2CTrans(bus_num)

  def scan(self):
    plist=[]
    ack=[1]
    for i in range(1,127):
      try:
        ack = self.i2c.transfer(writing(i, ack))
        plist.append(i)
      except:
        pass
    return plist

And yeah, it seems that the SMBus driver does this job a little different.
AFAIK, SMBus is an I²C extension, although it looks weird that you can detect something similar via I²C using a trashduino µC, yet this board doesn’t allow you that via I²C.

Oh, and I recall when I saw it mentioning it works like that on Duo:

Usage: i2cdetect -l | -F I2CBUS | [-ya] [-q|-r] I2CBUS [FIRST LAST]

Detect I2C chips

	-l	List installed buses
	-F BUS#	List functionalities on this bus
	-y	Disable interactive mode
	-a	Force scanning of non-regular addresses
	-q	Use smbus quick write commands for probing (**default**)
	-r	Use smbus read byte commands for probing
	FIRST and LAST limit probing range

That is, i2cdetect will detect them only using SMBus read for probing.

OK… now THAT is interesting. If I just do ‘i2cdetect 1 -y’, I don’t get ANY devices (on i2cdev-1). But if I add the ‘-r’ option… it uses SMBus to do a write to the device… and gives me all my devices.
So, guess I say… SCREW using i2c.scan() and stick with my own i2cdetect scan implemented using SMBus.
I never tried the ‘-a’ option. I wonder what that will do… Just tried it. Didn’t do squat.

I’ve used SMBus before, with Raspberry Pi, when I was working on a project (at Honeywell Security) involving Apple (HomeKit (sic)). We were trying to implement their authentication chip into an alarm panel (running linux)… so I tested my concepts out on a Pi and I did it with SMBus.

Thanks for looking deeper, then I cared too. :wink:

1 Like