BLueTooth interrupt

Discussion and questions about boards that can run MicroPython but don't have a dedicated forum.
Target audience: Everyone interested in running MicroPython on other hardware.
Post Reply
NicoleN
Posts: 10
Joined: Wed Oct 07, 2015 2:59 am

BLueTooth interrupt

Post by NicoleN » Fri Dec 04, 2015 2:23 pm

I am getting MemoryError when trying to control my car's speed via Bluetooth :cry:

Code: Select all

pulses = pyb.Timer(2, freq=1000)
pulses.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.PA2, pulse_width_percent=100)
pulses.channel(4, pyb.Timer.PWM, pin=pyb.Pin.board.PA3, pulse_width_percent=100)

def speed_adj(R_mot_percent,L_mot_percent):
    pulses.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.PA2, pulse_width_percent=R_mot_percent)
    pulses.channel(4, pyb.Timer.PWM, pin=pyb.Pin.board.PA3, pulse_width_percent=L_mot_percent)
speed_adj(Right_motor,Left_motor) is working properly from repl. Trying to send a command from my bluetooth which involves the speed_adj() i get:
MemoryError: memory allocation failed, heap is locked

p.ex. when i send the "2" command from bluetooth, will get error at speed_adj(50,50):

Code: Select all

def speed_test():
    speed_adj(50,50)

commands = [idle,manual,speed_test]

def command(id):
    commands[id]()
    
def BTread(BTcheck):
    if BT.any() == True:
        command(BT.readchar())

BTcheck = pyb.Timer(1)
BTcheck.init(freq=100)
BTcheck.callback(BTread)

User avatar
dhylands
Posts: 3454
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: BLueTooth interrupt

Post by dhylands » Fri Dec 04, 2015 6:46 pm

You're not allowed to allocate memory during an interrupt (the timer callback is an interrupt).

@pythoncoder has some preliminary documentation about this: http://hinch.me.uk/html/reference/isr_rules.html which will get merged into the main documentation, but in the meantime, I highly recommend having a read.

NicoleN
Posts: 10
Joined: Wed Oct 07, 2015 2:59 am

Re: BLueTooth interrupt

Post by NicoleN » Wed May 18, 2016 5:07 am

Well, i have read the documentation and tried to fix this in many different ways (using bytearray / readinto() ) but it still doesn't work :cry:

Code: Select all

from pyb import UART

BT = UART(4, 9600)
BT.init(9600, bits=8, parity=None, stop=1)

def speed(speed_percent):
    pulses.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.PA2, pulse_width_percent=speed_percent)
    pulses.channel(4, pyb.Timer.PWM, pin=pyb.Pin.board.PA3, pulse_width_percent=speed_percent)

def BTread():
    if BT.any() == True:
        speed(BT.readchar())

BTtimer = pyb.Timer(4)
BTtimer.init(freq=100)
BTtimer.callback(lambda t:BTread())
Any idea will be helpful. I just want when i send a number from my mobile, to run speed(number), using an interrupt.

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

Re: BLueTooth interrupt

Post by pythoncoder » Wed May 18, 2016 4:53 pm

The UART's any() method returns the number of characters pending which will only equate to True if exactly one character is pending. So the code should read:

Code: Select all

if BT.any() > 0:
There was an error in the docs indicating any() returned a boolean, corrected recently.
Peter Hinch

User avatar
deshipu
Posts: 1374
Joined: Thu May 28, 2015 5:54 pm

Re: BLueTooth interrupt

Post by deshipu » Wed May 18, 2016 7:36 pm

Code: Select all

if BT.any():
    ...
would have worked too. I can't understand why people write "== True" in their boolean expressions. It's meaningless.

User avatar
dhylands
Posts: 3454
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: BLueTooth interrupt

Post by dhylands » Thu May 19, 2016 2:02 am

There are still a few things wrong with your program (in addition to what's already been mentioned).

Whenever you're dealing with interrupts, I HIGHLY recommend that you add the following 2 lines:

Code: Select all

import micropython
micropython.alloc_emergency_exception_buf(100)
This will pinpoint errors in interrupt handlers, rather than getting a generic MemoryError for everything.

Calling pulses.channel will allocate memory. You should do that once in your main code doing something like:

Code: Select all

pulses = pyb.Timer(2, freq=1000)
ch3 = pulses.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width_percent=0)
ch4 = pulses.channel(4, pyb.Timer.PWM, pin=pyb.Pin.board.X4, pulse_width_percent=0)

def speed(speed_percent):
    ch3.pulse_width_percent(speed_percent)
    ch4.pulse_width_percent(speed_percent)
While trying to test your code, I also ran into the error that there is no pin named pyb.Pin.board.PA2. There is pyb.Pin.board.X3, and pyb.Pin.cpu.A2.

I was able to get the following code to work:

Code: Select all

import pyb
from pyb import UART

import micropython
micropython.alloc_emergency_exception_buf(100)

BT = UART(4, 9600)
BT.init(9600, bits=8, parity=None, stop=1)

pulses = pyb.Timer(2, freq=1000)
ch3 = pulses.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width_percent=0)
ch4 = pulses.channel(4, pyb.Timer.PWM, pin=pyb.Pin.board.X4, pulse_width_percent=0)

def speed(speed_percent):
    ch3.pulse_width_percent(speed_percent)
    ch4.pulse_width_percent(speed_percent)

def BTread(tim):
    if BT.any():
        speed(BT.readchar())

BTtimer = pyb.Timer(4)
BTtimer.init(freq=100)
BTtimer.callback(BTread)

NicoleN
Posts: 10
Joined: Wed Oct 07, 2015 2:59 am

Re: BLueTooth interrupt

Post by NicoleN » Sun May 22, 2016 7:13 am

pythoncoder wrote:There was an error in the docs indicating any() returned a boolean, corrected recently.
dhylands wrote:I also ran into the error that there is no pin named pyb.Pin.board.PA2
I use a 2015/10 firmware version. I have recently tried to update but i had problems with pin names etc, so i downgraded again. In my board, UART's .any() returns Boolean, no matter how many characters are waiting.
dhylands wrote:Calling pulses.channel will allocate memory

Code: Select all

ch3 = 
ch4 =
You are the best! Thanks!

User avatar
dhylands
Posts: 3454
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: BLueTooth interrupt

Post by dhylands » Sun May 22, 2016 7:28 am

NicoleN wrote:In my board, UART's .any() returns Boolean, no matter how many characters are waiting.
If you use the form:

Code: Select all

    if uart.any():
then it will work regarless of whether any returns a boolean or an integer.

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

Re: BLueTooth interrupt

Post by pythoncoder » Mon May 23, 2016 4:54 am

@NicoleN If I remember correctly the behaviour of any() was changed last year, with the docs lagging behind. Current firmware returns an integer. In general it's a good idea to use current firmware: I'm puzzled about the problem you have with current firmware and pin names. What board are you using? Perhaps you could elaborate?
Peter Hinch

Post Reply