keeping REPL alive

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
Beau
Posts: 13
Joined: Sun Oct 26, 2014 1:04 pm

keeping REPL alive

Post by Beau » Tue Oct 28, 2014 4:07 pm

Hi,

I have a main while True loop which looks like this:

Code: Select all

sw = pyb.Switch()
sw_state = 1
def toggle():
    global sw_state
    if sw_state == 0:
        sw_state = 1
    else:
        sw_state = 0
sw.callback(toggle)

def main():
    while sw_state:
       #main code....
        pyb.delay(100)

main()
This allows me to stop the loop to get back to the REPL. Does anyone have a more elegant solution to this problem? I would use an interrupt timer, but my code updates an lcd which requires mem alloc for the string.

Which brings me to my following problem. I'm trying to display the state of a rotary encoder which uses two ExtInts:

Code: Select all

        self.Bint = pyb.ExtInt(self.B,pyb.ExtInt.IRQ_RISING_FALLING,pyb.Pin.PULL_UP,self.callback)
        self.Aint = pyb.ExtInt(self.A,pyb.ExtInt.IRQ_RISING_FALLING,pyb.Pin.PULL_UP,self.callback)


This works fine, until I add the toggle callback! As soon as I do that, the rotary fails to get the necessary interrupts and doesn't update properly.

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

Re: keeping REPL alive

Post by dhylands » Tue Oct 28, 2014 4:41 pm

Do you have a complete code sample?

The ExtInt has a weird restriction.

When you look at the CPU Port/Pin designators (i.e. X1 maps to cpu pin A0) you can only register an ExtInt handler once for a given line.

The SW (which maps to cpu pin B3) uses ExtInt internally.

For a given CPU pin, (for example B3), the line is equal to the pin number (3 in for B3). So this means that if you're using ExtInt for SW, then you can't use ExtInt with any other CPU pins with a 3 in the pin number portion (A3 for example, which is on X4).

I'm not sure if that's a problem or not (since I don't know what pins you're trying to use).

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

Re: keeping REPL alive

Post by dhylands » Tue Oct 28, 2014 4:43 pm

You can also use Control-C to break out f your program (at least the main loop).

The interrupt handlers will continue to fire.

Beau
Posts: 13
Joined: Sun Oct 26, 2014 1:04 pm

Re: keeping REPL alive

Post by Beau » Tue Oct 28, 2014 5:27 pm

This is the full rotary code (no experience with these things, so it's probably far from ideal)

Code: Select all

import pyb

class rotary():
    def __init__(self,Apin='X21',Bpin='X22'):
        self.B = pyb.Pin(Bpin)
        self.A = pyb.Pin(Apin)

        self.prevA = self.A.value()
        self.prevB = self.B.value()

        self.CWcount = 0
        self.CCWcount = 0

        self.position = 0

        self.Bint = pyb.ExtInt(self.B,pyb.ExtInt.IRQ_RISING_FALLING,pyb.Pin.PULL_UP,self.callback)
        self.Aint = pyb.ExtInt(self.A,pyb.ExtInt.IRQ_RISING_FALLING,pyb.Pin.PULL_UP,self.callback)


    def callback(self,line):
        #     self.Bint.disable()
        #     self.Aint.disable()

        A = self.A.value()
        B = self.B.value()

        #previous state 11
        if   self.prevA==1 and self.prevB==1:
            if A==1 and B==0:
                #print( "CCW 11 to 10")
                self.CCWcount += 1
                self.prevA = A
                self.prevB = B

            elif A==0 and B==0:
                #print ("CW 11 to 00")
                self.CWcount += 1
                self.prevA = A
                self.prevB = B

        #previous state 10
        elif self.prevA==1 and self.prevB==0:
            if A==1 and B==1:
                #print ("CW 10 to 11")
                self.CWcount += 1
                self.prevA = A
                self.prevB = B

            elif A==0 and B==0:
                #print ("CCW 10 to 00")
                self.CCWcount += 1
                self.prevA = A
                self.prevB = B

        #previous state 00
        elif self.prevA==0 and self.prevB==0:
            if A==1 and B==1:
                #print ("CCW 00 to 11")
                self.CCWcount += 1
                self.prevA = A
                self.prevB = B

            elif A==1 and B==0:
                #print ("CW 00 to 10")
                self.CWcount+=1
                self.prevA = A
                self.prevB = B

        #     self.Bint.enable()
        #     self.Aint.enable()

        if A==1 and B==1:
            if self.CWcount>=3 and self.CWcount>self.CCWcount:
                self.position+=1
                print (self.position)
            if self.CCWcount>=3 and self.CCWcount>self.CWcount:
                self.position-=1
                print(self.position)
            self.CCWcount = 0
            self.CWcount  = 0

I also had a problem with enabling/disabling the interrupts. I can't uncomment those lines in the code, because when I register the first callback it seems to get called immediately (not sure why though?) and so the second variable isn't initialised yet.

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

Re: keeping REPL alive

Post by dhylands » Tue Oct 28, 2014 7:34 pm

The cpu pin for X22 is C3, and the cpu pin for SW is B3.

You can't have ExtInt enabled for both at the same time (they both use line 3).

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

Re: keeping REPL alive

Post by pythoncoder » Wed Oct 29, 2014 12:00 pm

You might be interested in this code which works fine on the MicroPython board

Code: Select all

class Encoder(object):
    def __init__(self, pin_x, pin_y, reverse, scale):
        self.reverse = reverse
        self.scale = scale
        self.forward = True
        self.pin_x = pin_x
        self.pin_y = pin_y
        self._pos = 0
        self.x_interrupt = pyb.ExtInt(pin_x, pyb.ExtInt.IRQ_RISING_FALLING, pyb.Pin.PULL_NONE, self.x_callback)
        self.y_interrupt = pyb.ExtInt(pin_y, pyb.ExtInt.IRQ_RISING_FALLING, pyb.Pin.PULL_NONE, self.y_callback)

    def x_callback(self, line):
        self.forward = self.pin_x.value() ^ self.pin_y.value() ^ self.reverse
        self._pos += 1 if self.forward else -1

    def y_callback(self, line):
        self.forward = self.pin_x.value() ^ self.pin_y.value() ^ self.reverse ^ 1
        self._pos += 1 if self.forward else -1

    @property
    def position(self):
        return self._pos*self.scale
The reverse argument allows for the case where wheels need to turn in opposite directions to achieve forward motion, and the scale argument allows me to retrieve linear position.

Regards, Pete
Peter Hinch
Index to my micropython libraries.

Beau
Posts: 13
Joined: Sun Oct 26, 2014 1:04 pm

Re: keeping REPL alive

Post by Beau » Wed Oct 29, 2014 8:14 pm

Thanks for the feedback and the code. Looks interesting and much cleaner than my attempt.

Post Reply