ExtInt not working properly

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
nikhiledutech
Posts: 118
Joined: Wed Dec 27, 2017 8:52 am

ExtInt not working properly

Post by nikhiledutech » Tue Jan 23, 2018 12:01 pm

Hello,

So i am currently configuring interrupt on Gpio pin, but i am facing problem with it.
Below is my code:
import pyb
import pyb,micropython
from pyb import LED, Pin, ExtInt
micropython.alloc_emergency_exception_buf(100)


vibra_value = pyb.Pin('PE7',Pin.IN,Pin.PULL_UP)
def callback():
pyb.LED(1).toggle()
pyb.LED(2).toggle()
pyb.LED(3).toggle()
pyb.LED(4).toggle()

ext = pyb.ExtInt('PE7', pyb.ExtInt.IRQ_RISING, pyb.Pin.PULL_UP, callback)


while True:
if vibra_value() == True:
print("Detected")
pyb.delay(100)

I get the following error:
Uncaught exception in ExtInt interrupt handler line 7
TypeError: function takes 0 positional arguments but 1 were given
So in code my handler calls callback function, when "PE7" goes from 0 to 1, but callback isnt getting executed, while "Detected" gets print on terminal. Reason i don't know ?
Any suggestions.

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

Re: ExtInt not working properly

Post by pythoncoder » Tue Jan 23, 2018 5:49 pm

Your callback needs to accept a single argument (which you can discard). See the docs which state "The callback function must accept exactly 1 argument, which is the line that triggered the interrupt."

Code: Select all

def callback(_):  # _ is a convention for a "don't care" variable
    pyb.LED(1).toggle()
    pyb.LED(2).toggle()
    pyb.LED(3).toggle()
    pyb.LED(4).toggle()
Peter Hinch
Index to my micropython libraries.

nikhiledutech
Posts: 118
Joined: Wed Dec 27, 2017 8:52 am

Re: ExtInt not working properly

Post by nikhiledutech » Wed Jan 24, 2018 5:19 am

Okay. thank you sir.

But now I have new issue. Whenever i try to write to LCD using Interrupt service routine, it give me an Memory error saying heap locked.

Below is my code:
import pyb
import pyb,micropython
from pyb import LED, Pin, ExtInt
import uasyncio as asyncio
import utime as time
from alcd import LCD, PINLIST
micropython.alloc_emergency_exception_buf(100)

lcd = LCD(PINLIST, cols = 16)
vibra_value = pyb.Pin('PE7',Pin.IN,Pin.PULL_DOWN)


async def sensor():
lcd[0] = "Vibration Detected"
await asyncio.sleep(1)

def callback(_):
pyb.LED(4).toggle()
loop = asyncio.get_event_loop()
loop.run_until_complete(sensor())


ext = pyb.ExtInt('PE7', pyb.ExtInt.IRQ_RISING, pyb.Pin.PULL_UP, callback)

async def vibra_sensor():
while True:
pass

while True:
loop = asyncio.get_event_loop()
loop.run_until_complete(vibra_sensor())
It gives me follwing error : MemoryError: memory allocation failed, heap is locked

So can you guide me how to use async method to write to LCD in ISR.

Thanks

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

Re: ExtInt not working properly

Post by pythoncoder » Wed Jan 24, 2018 7:11 am

There are a couple of issues here.

Code: Select all

async def vibra_sensor():
    while True:
        pass
This is presumably a placeholder for a routine which will eventually do something, but as written it will stop the scheduler from working. All async def routines must yield to the scheduler periodically. So pass should be replaced with await asyncio.sleep(0) (or a longer period).

Secondly, as you have discovered, the LCD driver can't be called in an interrupt context. So your interrupt handler needs to signal to another coroutine which updates the LCD. The best way to do this is using an Event instance (see docs) but as an introduction let's just use a global:

Code: Select all

vib_detected = False
async def update_lcd():
    while True:
        lcd[0] = 'Vibration detected' if vib_detected else ''
        await asyncio.sleep(1)

def callback(_):
    global vib_detected
    vib_detected = True
    pyb.LED(4).toggle()
However you do this you need to consider how the absence of vibration is handled: there presumably needs to be a way of turning off the indication. There are a number of approaches but you might like to consider the software equivalent of a retriggerable monostable described here. This could be triggered by the ISR and the update_lcd routine could show a message depending on its running state.

Code: Select all

import aswitch
delay = aswitch.Delay_ms()
async def update_lcd():
    while True:
        lcd[0] = 'Vibration detected' if delay.running() else ''
        await asyncio.sleep(1)

def callback(_):
    delay.trigger(1000)  # If vibration stops for > 1s display will clear
    pyb.LED(4).toggle()
Peter Hinch
Index to my micropython libraries.

nikhiledutech
Posts: 118
Joined: Wed Dec 27, 2017 8:52 am

Re: ExtInt not working properly

Post by nikhiledutech » Wed Jan 24, 2018 10:09 am

When i implement the above mentioned changes, i get the following error.

Here is my code:
import pyb,micropython, aswitch
from pyb import LED, Pin, ExtInt
import uasyncio as asyncio
import utime as time
from alcd import LCD, PINLIST
micropython.alloc_emergency_exception_buf(100)
#vib_detected = False
delay = aswitch.Delay_ms()
lcd = LCD(PINLIST, cols = 16)
vibra_value = pyb.Pin('PE7',Pin.IN,Pin.PULL_DOWN)


async def lcd_update():
lcd[0] = 'Vibration Detected' if delay.running() else ' '
await asyncio.sleep(1)

def callback(_):
delay.trigger(1000)
pyb.LED(4).toggle()
time.sleep_ms(500)




ext = pyb.ExtInt('PE7', pyb.ExtInt.IRQ_RISING, pyb.Pin.PULL_UP, callback)

async def vibra_sensor():
while True:
await asyncio.sleep(2)
And here is the result :
File "aswitch.py", line 54, in trigger
MemoryError: memory allocation failed, heap is locked


Any solutions ?

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

Re: ExtInt not working properly

Post by pythoncoder » Thu Jan 25, 2018 6:55 am

I think the way to approach this is first to remove all redundant code, prove that a minimal example is working, then add code as required. With that in mind, this stripped down version does not produce any error message when run on a Pyboard (I changed only the pin name). Note that I didn't have an LCD connected so this was hardly a proper test, but it is perhaps a starting point. Note that a delay in an ISR is a bad idea and I removed it. ISR's should run to completion as quickly as possible.

Code: Select all

import pyb,micropython, aswitch
from pyb import LED, Pin, ExtInt
import uasyncio as asyncio
import utime as time
from alcd import LCD, PINLIST
micropython.alloc_emergency_exception_buf(100)

delay = aswitch.Delay_ms()
lcd = LCD(PINLIST, cols = 16)

async def lcd_update():
    while True:
        lcd[0] = 'Vibration Detected' if delay.running() else ' '
        await asyncio.sleep(1)

def callback(_):
    delay.trigger(1000)
    pyb.LED(4).toggle()

ext = pyb.ExtInt('PE7', pyb.ExtInt.IRQ_RISING, pyb.Pin.PULL_UP, callback)

loop = asyncio.get_event_loop()
loop.create_task(lcd_update())
loop.run_forever()
If the purpose of the delay in the ISR was to pulse the LED, the way to do this is to create a coroutine to do it and have the ISR launch the coro with loop.create_task(pulse_led()).
Peter Hinch
Index to my micropython libraries.

nikhiledutech
Posts: 118
Joined: Wed Dec 27, 2017 8:52 am

Re: ExtInt not working properly

Post by nikhiledutech » Thu Jan 25, 2018 7:37 am

Okay sir. Thankyou. I will try it and inform the progress.

nikhiledutech
Posts: 118
Joined: Wed Dec 27, 2017 8:52 am

Re: ExtInt not working properly

Post by nikhiledutech » Thu Jan 25, 2018 9:50 am

Hello Sir,
So i have implemented code given by you now. I removed delay.trigger(1000) from ISR as it was causing problem in blinking of LED. When i used delay.trigger(1000) it gave me ""MemoryError: memory allocation failed, heap is locked"" this error.

So i just wanted to check wether led are blinking so i moved delay.trigger(1000) after the LED toggling, so as expected LED got toggled on vibrations but still the LCD_update func. didnt work. It gave the same error " MemoryError: memory allocation failed, heap is locked "



Here is my code:
import pyb,micropython, aswitch
from pyb import LED, Pin, ExtInt
import uasyncio as asyncio
import utime as time
from alcd import LCD, PINLIST
micropython.alloc_emergency_exception_buf(100)

delay = aswitch.Delay_ms()
lcd = LCD(PINLIST, cols = 16)

async def lcd_update():
while True:
lcd[0] = 'Vibration Detected' if delay.running() else ' '
await asyncio.sleep(1)

def callback(_):
# delay.trigger(1000) It was creating error so just for checking wether LED Blink i used this instruction below
pyb.LED(4).toggle()
delay.trigger(1000)


ext = pyb.ExtInt('PE7', pyb.ExtInt.IRQ_RISING, pyb.Pin.PULL_UP, callback)

loop = asyncio.get_event_loop()
loop.create_task(lcd_update())
loop.run_forever()


ERROR: Memory Error: memory allocation failed, heap is locked


So i don't know where the problem lies now.

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

Re: ExtInt not working properly

Post by pythoncoder » Thu Jan 25, 2018 6:45 pm

The only circumstance I can see in which this error will occur is if the interrupt is occurring and the callback is running before the event loop is instantiated. Try this:

Code: Select all

import pyb,micropython, aswitch
from pyb import LED, Pin, ExtInt
import uasyncio as asyncio
import utime as time
from alcd import LCD, PINLIST
micropython.alloc_emergency_exception_buf(100)

delay = aswitch.Delay_ms()
lcd = LCD(PINLIST, cols = 16)

async def lcd_update():
    await asyncio.sleep(1)
    ext = pyb.ExtInt('PE7', pyb.ExtInt.IRQ_RISING, pyb.Pin.PULL_UP, callback)
    while True:
        lcd[0] = 'Vibration Detected' if delay.running() else ' '
        await asyncio.sleep(1)

def callback(_):
    delay.trigger(1000)
    pyb.LED(4).toggle()

loop = asyncio.get_event_loop()
loop.create_task(lcd_update())
loop.run_forever()
Peter Hinch
Index to my micropython libraries.

nikhiledutech
Posts: 118
Joined: Wed Dec 27, 2017 8:52 am

Re: ExtInt not working properly

Post by nikhiledutech » Sat Jan 27, 2018 4:37 am

Still the same error Sir, "MemoryError: memory allocation failed, heap is locked".
Here is the code:
import pyb,micropython, aswitch
from pyb import LED, Pin, ExtInt
import uasyncio as asyncio
import utime as time
from alcd import LCD, PINLIST
micropython.alloc_emergency_exception_buf(100)

delay = aswitch.Delay_ms()
lcd = LCD(PINLIST, cols = 16)

async def lcd_update():
await asyncio.sleep(1)
ext = pyb.ExtInt('PE7', pyb.ExtInt.IRQ_RISING, pyb.Pin.PULL_UP, callback)
while True:
lcd[0] = 'Vibration Detected' if delay.running() else ' '
await asyncio.sleep(1)

def callback(_):
delay.trigger(1000)
pyb.LED(4).toggle()

loop = asyncio.get_event_loop()
loop.create_task(lcd_update())
loop.run_forever()

So now i tried with a different method, i declared a global variable and whenever ISR is executed, global variable will be set. Depending on this global variable we will be printing on LCD. But for some reason it also didnt work. Below is my code:
#Write a program to interface vibra Sensor board.
import pyb
import pyb,micropython
from pyb import LED, Pin, ExtInt
import uasyncio as asyncio
import utime as time
from alcd import LCD, PINLIST
micropython.alloc_emergency_exception_buf(100)
data = False

lcd = LCD(PINLIST, cols = 16)
vibra_value = pyb.Pin('PE7',Pin.IN,Pin.PULL_DOWN)

def callback(_):
global data
pyb.LED(4).toggle()
pyb.LED(3).toggle()
pyb.LED(2).toggle()
pyb.LED(1).toggle()
data = True

ext = pyb.ExtInt('PE7', pyb.ExtInt.IRQ_RISING, pyb.Pin.PULL_UP, callback)

async def lcd_update():
global data
if data == True:
lcd[0] = "Vibration Detected"
await asyncio.sleep(1)
elif data == False:
lcd[0] = " "
await asyncio.sleep(1)
data = False


while True:
loop = asyncio.get_event_loop()
loop.run_until_complete(lcd_update())

So here my global variable is data =0, so as ISR is serviced, data should become 1. As soon as data becomes high, the LCD should print but its not working as data value is not geting updated or Any reason ? or can you improve the above code.

Thank You
Last edited by nikhiledutech on Sat Jan 27, 2018 6:10 am, edited 1 time in total.

Post Reply