Reading ADC stopps IRQ

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
jedie
Posts: 26
Joined: Fri Jan 29, 2016 12:32 pm

Reading ADC stopps IRQ

Post by jedie » Wed Oct 03, 2018 9:45 am

I try to read the crossbar buttons on my Odroid GO with this test script:

Code: Select all

from machine import ADC, Pin
from micropython import const

BUTTON_JOY_X = const(34)
BUTTON_JOY_Y = const(35)

def irq_handler(pin):
    print("PIN %s value: %r" % (pin, pin()))
    adc = ADC(pin)
    adc.width(ADC.WIDTH_9BIT)
    adc.atten(ADC.ATTN_11DB)
    print("ADC value: %r" % adc.read())

pin = Pin(BUTTON_JOY_X , mode=Pin.IN, pull=Pin.PULL_UP)
pin.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=irq_handler)

pin = Pin(BUTTON_JOY_Y , mode=Pin.IN, pull=Pin.PULL_UP)
pin.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=irq_handler)
It works only one time. After one irq_handler() call it stops working. Neither a soft nor a hard reset is enough to fix it. I must power off the Odroid GO and then it works again, but only once.

Any idea?

User avatar
pythoncoder
Posts: 2980
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Reading ADC stopps IRQ

Post by pythoncoder » Wed Oct 03, 2018 12:41 pm

The most likely cause is a memory allocation in the interrupt handler. I suggest you read this doc, especially the introductory sections.
Peter Hinch

jedie
Posts: 26
Joined: Fri Jan 29, 2016 12:32 pm

Re: Reading ADC stopps IRQ

Post by jedie » Thu Oct 04, 2018 6:32 am

Thanks for the hint. I changed the code and use micropython.schedule for the adc reading, but it also stopped after a few call:

Code: Select all

from machine import ADC, Pin
import micropython

BUTTON_JOY_X = micropython.const(34)
BUTTON_JOY_Y = micropython.const(35)

def print_adc(pin):
    adc = ADC(pin)
    adc.width(ADC.WIDTH_9BIT)
    adc.atten(ADC.ATTN_11DB)
    print("ADC value: %r" % adc.read())

def irq_handler(pin):
    print("PIN %s value: %r" % (pin, pin()))
    micropython.schedule(print_adc, pin)

pin = Pin(BUTTON_JOY_X , mode=Pin.IN, pull=Pin.PULL_UP)
pin.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=irq_handler)

pin = Pin(BUTTON_JOY_Y , mode=Pin.IN, pull=Pin.PULL_UP)
pin.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=irq_handler)
Example output:

Code: Select all

>>> PIN Pin(34) value: 0
ADC value: 236
PIN Pin(35) value: 1
ADC value: 511
PIN Pin(35) value: 0
ADC value: 511

User avatar
pythoncoder
Posts: 2980
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Reading ADC stopps IRQ

Post by pythoncoder » Fri Oct 05, 2018 11:08 am

I would move the print statement to print_adc() as I think that may cause an allocation. Are you using the official port or the Loboris one?

There are a few things which can be improved in your code. Instantiating the ADC in the interrupt handler is, at best, inefficient. Also I don't think you can use any pin for the ADC. I don't have your hardware but the following worked for me on an ESP32 board:

Code: Select all

from machine import ADC, Pin
import micropython

micropython.alloc_emergency_exception_buf(100)

adc = ADC(Pin(34))  # A valid ADC pin
adc.width(ADC.WIDTH_9BIT)
adc.atten(ADC.ATTN_11DB)

def print_adc(pin):
    print("PIN %s value: %r" % (pin, pin()))
    print("ADC value: %r" % adc.read())

def irq_handler(pin):
    micropython.schedule(print_adc, pin)

pin = Pin(23, mode=Pin.IN, pull=Pin.PULL_UP)
pin.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=irq_handler)
Lastly, unless your platform has hardware debouncing, for anything other than a quick hack you need to debounce the digital I/O pins. There are many solutions to this, but if you understand (or are prepared to learn) asynchronous programming one way may be found in this repo. Otherwise solutions using timers may be found in this forum.
Peter Hinch

jedie
Posts: 26
Joined: Fri Jan 29, 2016 12:32 pm

Re: Reading ADC stopps IRQ

Post by jedie » Fri Oct 05, 2018 3:18 pm

Thanks.

I've been proibing again.

Thinks it's not about interrupt handler and memory allocation...

Because i can do this:
  • only trigger IRQ and do print("PIN %s value: %r" % (pin, pin()))
  • don't trigger IRQ and only read ADC in a loop
This works, also after soft/hard reset...

But if i do both: trigger IRQ and read ADC it will result in the error. And a soft/hard reset will not recover. I have to "power off/on" ...

It's about the Odroid Go. And https://github.com/joshua-yang/ODROID-G ... _consts.py figured out that's the crossbar is pin 34 and 35 ...

So in the end i can only poll the crossbar?

jedie
Posts: 26
Joined: Fri Jan 29, 2016 12:32 pm

Re: Reading ADC stopps IRQ

Post by jedie » Fri Oct 05, 2018 4:44 pm

I now have made a simple polling solution: https://github.com/jedie/PyOdroidGo/blo ... rossbar.py

In this case it works good. I now use it in the menu...

But a IRQ based solution is also interesting...

User avatar
pythoncoder
Posts: 2980
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Reading ADC stopps IRQ

Post by pythoncoder » Sat Oct 06, 2018 6:20 am

OK, I think I now see what you're trying to do. It looks like you want an interrupt to occur when the voltage on an ADC pin goes outside certain bounds. As far as I know this is unsupported. You could emulate it by polling the ADC's in a timer callback.
Peter Hinch

Post Reply