2

I have programmed an ATtiny1627 as I2C slave to answer to the read_i2c_block_data() function. Basically it receives the command indicating which variable to return and answers with 4 bytes representing a float. A Raspberry Pi 4 is the I2C master and has to read the data every 500ms, however the following code does not work:

main.py

import time
from smbus import SMBus
from struct import unpack

i2c = SMBus(1)

for i in range(10):
#address: 0x0A, command: 0x54, get 4bytes
    bytes = i2c.read_i2c_block_data(0x0A, 0x54, 4)
    [result] = unpack('f', bytearray(bytes))
    print(result)
    time.sleep(.5)

running main.py results in:

>sudo python3 main.py
100
100
nan
nan
nan
nan
nan
nan
nan
nan

Strangely, if the code is as follows it works perfectly:

test.py

from smbus import SMBus
from struct import unpack

i2c = SMBus(1)

bytes = i2c.read_i2c_block_data(0x0A, 0x54, 4)
[result] = unpack('f', bytearray(bytes))
print(result)

and main2.py

import os, time

for i in range(10):
    os.system('sudo python3 test.py')
    time.sleep(.5)

running main2.py:

>sudo python3 main2.py
100
100
100
100
100
100
100
100
100
100

This is not optimal as I cannot transfer easily the data from test.py to main2.py in order to process it. I have tried other combinations with unsatisfactory results:

  • Defining a method in test.py and importing it to main2.py does not work.
  • Using multiprocessing and creating a new process for each loop does not work.
  • Using with SMBus(1) as i2c: raises AtributeError: __enter__ as the class misses this methods.

I think it has something to do with from smbus import SMBus as it is the only command that is re-executed when calling sudo python3 test.py but not re-executed when importing the method into main2.py.

Am I missing something like read_i2c_block_data() not sending the Start signal after x seconds or similar?

Octavian
  • 21
  • 2
  • 1
    Not sure if this is relevant https://raspberrypi.stackexchange.com/a/7142 but if it’s the same bug with the RPi’s I2C chip still, then try something like `for i in range(10):` \n `with SMBus(1) as i2c:`\n`bytes = i2c.read_i2c_block_data(…….)` – Rich L May 18 '21 at 17:43

1 Answers1

1

I would recommend not using bytes as variable name as it's built into python.

But it's not evident from your code what the issue is. You should not need to reinitialize the i2c bus every time like in your second example.

Have you tried reading at a faster rate than 500ms but only returning non-null values? ie:

import time
from smbus import SMBus
from struct import unpack

i2c = SMBus(1)

current_vals = 0

while current_vals <= 10:
    raw = i2c.read_i2c_block_data(0x0A, 0x54, 4)
    [result] = unpack('f', bytearray(raw))
    if result != "nan":
        current_vals += 1
        print(result)
    time.sleep(.1)
Teejay Bruno
  • 1,716
  • 1
  • 4
  • 11
  • Thank you for the recommendation about the name of the variable. The problem is not there, reducing the sampling period does not work, it simply gets more values but after approximately 1s it starts getting nan, ie. period: 500ms gets 2 samples, period:200ms gets 4 samples. – Octavian May 19 '21 at 10:46