eclipse / mraa

Linux Library for low speed IO Communication in C with bindings for C++, Python, Node.js & Java. Supports generic io platforms, as well as Intel Edison, Intel Joule, Raspberry Pi and many more.
http://mraa.io
MIT License
1.37k stars 613 forks source link

Python3 use with Gpio.isr question #814

Open ukBaz opened 7 years ago

ukBaz commented 7 years ago

I am finding it difficult to use the isr functionality with the Python bindings so I thought I would post a question here to see if I am structuring this correctly.

I have a Dragonboard 410c with an ST LIS2DS12 accelerometer attached. The main communication is via I2C which is working fine. In addition to the I2C there is also a GPIO pin on the ST accelerometer that is pulled low when new data is available to read.

My simple experiment is to print the value for the orientation when there is a change indicated by the int1 signal. This seems to work in a while loop with the following code:

from time import sleep
import mraa

print(mraa.getVersion())
print(mraa.getPlatformName())

class Tilt:
    def __init__(self, bus=1, i2c_addr=0x1d, int1_pin=23):
        self._CTRL1 = 0x20
        self._CTRL3 = 0x22
        self._CTRL4 = 0x23
        self._TAP_6D_THS = 0x31
        self._6D_SRC = 0x39
        # Pin for interrupt signal
        self._int1 = mraa.Gpio(int1_pin)
        self._int1.dir(mraa.DIR_IN)
        self._int1.edge(mraa.EDGE_FALLING)
        # i2c bus to read orientation
        self.device = mraa.I2c(bus)
        self.device.address(i2c_addr)
        self.device.writeReg(self._CTRL1, 0b01100000)
        self.device.writeReg(self._TAP_6D_THS, 0b01000000)
        self.device.writeReg(self._CTRL4, 0b00000100)
        # Use latched interrupt (reset by reading _6D_SRC)
        self.device.writeReg(self._CTRL3, 0b00000110)

    @property
    def int1(self):
        return not self._int1.read()

    @property
    def orientation(self):
        return '{:08b}'.format(self.device.readReg(self._6D_SRC))

# Tilt test
accel = Tilt()

while True:
    if accel.int1:
        print(accel.orientation)
        sleep(0.25)

This gives the expected result of printing a new line when the tilt of the sensor is changed and the int1 signal is reset by the data being read.

root@linaro-alip:/home/linaro/python/python-micromez# python3 tests/simple_isr.py 
v1.7.0
DB410C
01000001
01100000
01000010
01100000
01001000
01100000

Now if I try to do this using the Gpio.isr functionality then it does not seem to work as expected. The code is modified as follows:

from signal import pause
from time import sleep
import mraa

print(mraa.getVersion())
print(mraa.getPlatformName())

class Tilt:
    def __init__(self, bus=1, i2c_addr=0x1d, int1_pin=23):
        self._CTRL1 = 0x20
        self._CTRL3 = 0x22
        self._CTRL4 = 0x23
        self._TAP_6D_THS = 0x31
        self._6D_SRC = 0x39
        # Pin for interrupt signal
        self._int1 = mraa.Gpio(int1_pin)
        self._int1.dir(mraa.DIR_IN)
        self._int1.edge(mraa.EDGE_FALLING)
        # i2c bus to read orientation
        self.device = mraa.I2c(bus)
        self.device.address(i2c_addr)
        self.device.writeReg(self._CTRL1, 0b01100000)
        self.device.writeReg(self._TAP_6D_THS, 0b01000000)
        self.device.writeReg(self._CTRL4, 0b00000100)
        # Use Pulse for interrupt
        self.device.writeReg(self._CTRL3, 0b00000010)

    @property
    def int1(self):
        return not self._int1.read()

    @property
    def orientation(self):
        return '{:08b}'.format(self.device.readReg(self._6D_SRC))

    def on_new_data(self, fn, *args):
        self._int1.isr(mraa.EDGE_FALLING, fn, args[0])

# Tilt test
accel = Tilt()
accel.on_new_data(print, accel.orientation)

pause()

Now when I tilt the sensor a new line is printed out but it never changes value. I have also had to change the 'int1' signal to be 'pulse' rather than 'latched' because the value is never being read.

root@linaro-alip:/# python3 tests/simple_isr.py 
v1.7.0
DB410C
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

Any suggestions on what is the correct structure to get this to work?

Mani-Sadhasivam commented 7 years ago

@ukBaz

It looks like you are defining isr in a wrong way. I've just restructured your code a bit and got isr triggered for low state change in pin 25

https://pastebin.ubuntu.com/25521348/

Hope this helps!

ukBaz commented 7 years ago

I think your testcase is subtly different.

The issue I was trying to demonstrate is that the value of accel.orientation did not change on each triggering of the interrupt.

Let me see if I can come up with a better testcase

Propanu commented 7 years ago

@ukBaz have you tried using the UPM driver for the lis2ds12? Most of what you're trying to achieve here along with various ISR config options are already wrapped by it. See more here: https://iotdk.intel.com/docs/master/upm/python/pyupm_lis2ds12.html

ukBaz commented 7 years ago

Thanks @Propanu , that does look interesting. However there is something a little fishy about the isr that would be good to resolve.

I have had a go at trying to simplify the test cases so it should be easier for other people to run them:

from signal import pause
from random import randint
import mraa

print(mraa.getVersion())
print(mraa.getPlatformName())

class BingoMachine:
    def __init__(self, data_rdy_pin=33):
        # Pin for interrupt signal
        self._int1 = mraa.Gpio(data_rdy_pin)
        self._int1.dir(mraa.DIR_IN)
        self._int1.edge(mraa.EDGE_FALLING)

    @property
    def int1(self):
        return not self._int1.read()

    @property
    def new_number(self):
        return randint(0, 90)

    def on_button_press(self, fn, *args):
        self._int1.isr(mraa.EDGE_FALLING, fn, args[0])

machine = BingoMachine()

machine.on_button_press(print, machine.new_number)

pause()

This gives a constant output such as:

root@linaro-alip:/home/linaro# python3 examples/mraa_isr_814_constant.py 
v1.7.0
DB410C
20
20
20

As I think @Mani-Sadhasivam was trying to show you can get it to give the correct answer with a bit of modification such as:

from signal import pause
from random import randint
import mraa

print(mraa.getVersion())
print(mraa.getPlatformName())

def caller(machine_obj):
    print(machine_obj.new_number)

class BingoMachine:
    def __init__(self, data_rdy_pin=33):
        # Pin for interrupt signal
        self._int1 = mraa.Gpio(data_rdy_pin)
        self._int1.dir(mraa.DIR_IN)
        self._int1.edge(mraa.EDGE_FALLING)

    @property
    def int1(self):
        return not self._int1.read()

    @property
    def new_number(self):
        return randint(0, 90)

    def on_button_press(self, fn, *args):
        self._int1.isr(mraa.EDGE_FALLING, fn, args[0])

machine = BingoMachine()

machine.on_button_press(caller, machine)

pause()

The output is:

root@linaro-alip:/home/linaro# python3 examples/mraa_isr_814_work.py 
v1.7.0
DB410C
22
90
46
52

A bit untidy but it can be done to get it working. The problem is that often it would be helpful if the function passed to the isr is down inside another class. If you do this then you get a segmentation fault:

from signal import pause
from random import randint
import mraa

print(mraa.getVersion())
print(mraa.getPlatformName())

class BingoCaller:
    def __init__(self):
        self.numbers_called = []
        print('Setup some fancy GUI')

    def caller(self, machine_obj):
        self.numbers_called.append(machine_obj.new_number)
        print(machine_obj.new_number)

class BingoMachine:
    def __init__(self, data_rdy_pin=33):
        # Pin for interrupt signal
        self._int1 = mraa.Gpio(data_rdy_pin)
        self._int1.dir(mraa.DIR_IN)
        self._int1.edge(mraa.EDGE_FALLING)

    @property
    def int1(self):
        return not self._int1.read()

    @property
    def new_number(self):
        return randint(0, 90)

    def on_button_press(self, fn, *args):
        self._int1.isr(mraa.EDGE_FALLING, fn, args[0])

dave = BingoCaller()
machine = BingoMachine()

machine.on_button_press(dave.caller, machine)

pause()

This gives the output:

root@linaro-alip:/home/linaro# python3 examples/mraa_isr_814_seg_fault.py 
v1.7.0
DB410C
Setup some fancy GUI
Segmentation fault

I can't work out how to workaround this one.

alext-mkrs commented 7 years ago

This sounds like #599, at least partially. There's no solution there, but you can check workarounds/known issues.