Page 1 of 1

BLueTooth interrupt

Posted: Fri Dec 04, 2015 2:23 pm
by NicoleN
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)

Re: BLueTooth interrupt

Posted: Fri Dec 04, 2015 6:46 pm
by dhylands
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.

Re: BLueTooth interrupt

Posted: Wed May 18, 2016 5:07 am
by NicoleN
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.

Re: BLueTooth interrupt

Posted: Wed May 18, 2016 4:53 pm
by pythoncoder
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.

Re: BLueTooth interrupt

Posted: Wed May 18, 2016 7:36 pm
by deshipu

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.

Re: BLueTooth interrupt

Posted: Thu May 19, 2016 2:02 am
by dhylands
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)

Re: BLueTooth interrupt

Posted: Sun May 22, 2016 7:13 am
by NicoleN
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!

Re: BLueTooth interrupt

Posted: Sun May 22, 2016 7:28 am
by dhylands
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.

Re: BLueTooth interrupt

Posted: Mon May 23, 2016 4:54 am
by pythoncoder
@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?