Problem using utime.tick_ms()

Have been trying to get this code working

import pyb
import utime

import micropython
micropython.alloc_emergency_exception_buf(500)

# Global constants
buttonShortPressTime = 20    # milliseconds

# Ring buffer implementation
ringTail = 0
ringHead = 0
ringSize = 10000
ringFull = False
msRingBuffer = None
trRingBuffer = None

# Global variables
buttonPin = None
extInt = None
lowButtonTime = None

# button pressed flag
buttonPressed = False

# button transition ISR
def buttonTransitionISR(line):
    global buttonPin
    global trRingBuffer
    global msRingBuffer
    global ringHead
    global ringFull

    if ringFull == False:
        trRingBuffer[ringHead] = buttonPin.value()
        msRingBuffer[ringHead] = utime.ticks_ms()
        localRingHead = (ringHead + 1) % ringSize
        if localRingHead == ringTail:
            ringFull = True
        else:
            ringHead = localRingHead
    # else: do nothing

def initialiseInterrupts():
    global buttonPin
    global buttonClock
    global extInt
    global trRingBuffer
    global msRingBuffer

    # Initialise ring buffer
    trRingBuffer = bytearray(ringSize)
    msRingBuffer = bytearray()
    # Have to do this as we do not know what utime.ticks_ms() returns
    for index in range(0,ringSize):
        msRingBuffer.append(utime.ticks_ms())

    # experimental button pin
    buttonPin = pyb.Pin('P0', pyb.Pin.IN)

    # set up ISR for button press
    extInt = pyb.ExtInt(buttonPin, pyb.ExtInt.IRQ_RISING_FALLING, pyb.Pin.PULL_UP, buttonTransitionISR)

# check for button pressed condition
def buttonPressedCheck():
    global trRingBuffer
    global msRingBuffer
    global lowButtonTime
    global buttonPressed
    global ringHead
    global ringTail

    # Reset button pressed indication
    # Calling functions will only see it set the once
    buttonPressed = False;

    while(True):
        # Start peeling stuff out of the ring buffer
        if ringHead == ringTail:
            # head == tail implies buffer empty
            break

        # Will only see button pressed indication if the ring is empty
        # If we are to slow calling this function then intermediate button
        # presses will be discarded
        buttonPressed = False;

        if lowButtonTime == None:
            # Initialisation requires that we see a low pin first
            if trRingBuffer[ringTail] == 0:
                lowButtonTime = msRingBuffer[ringTail]
                print ("initialising lowButtonTime = ", lowButtonTime)
        elif trRingBuffer[ringTail] == 0:
            # Get ms value for low button
            lowButtonTime = msRingBuffer[ringTail]
            print ("lowButtonTime = ", lowButtonTime)
        else:
            # Got ms value for high button
            thisButtonTime = msRingBuffer[ringTail]
            buttonPressedTime = utime.ticks_diff(thisButtonTime, lowButtonTime)
            print ("thisButtonTime = ", thisButtonTime, " lowButtonTime = ", lowButtonTime, " buttonPressedTime = ", buttonPressedTime)
            if buttonPressedTime >= buttonShortPressTime:
                buttonPressed = True

        # Increment tail
        ringTail = (ringTail + 1) % ringSize

        # end of while(True)

# Initialise interrupt handlers
initialiseInterrupts()

green_led = pyb.LED(2)

# start with LED off
green_led.off()

while(True):
    buttonPressedCheck()
    if buttonPressed == True:
        green_led.toggle()

and get the following results

initialising lowButtonTime = 231
thisButtonTime = 141 lowButtonTime = 231 buttonPressedTime = -90
thisButtonTime = 141 lowButtonTime = 231 buttonPressedTime = -90
lowButtonTime = 141
thisButtonTime = 142 lowButtonTime = 141 buttonPressedTime = 1
lowButtonTime = 142
lowButtonTime = 142
thisButtonTime = 142 lowButtonTime = 142 buttonPressedTime = 0
lowButtonTime = 142
thisButtonTime = 143 lowButtonTime = 142 buttonPressedTime = 1
lowButtonTime = 143
thisButtonTime = 143 lowButtonTime = 143 buttonPressedTime = 0
lowButtonTime = 144
thisButtonTime = 144 lowButtonTime = 144 buttonPressedTime = 0
lowButtonTime = 145
thisButtonTime = 145 lowButtonTime = 145 buttonPressedTime = 0
lowButtonTime = 145
thisButtonTime = 146 lowButtonTime = 145 buttonPressedTime = 1
lowButtonTime = 146
thisButtonTime = 146 lowButtonTime = 146 buttonPressedTime = 0
lowButtonTime = 146
thisButtonTime = 102 lowButtonTime = 146 buttonPressedTime = -44
lowButtonTime = 103
lowButtonTime = 103
lowButtonTime = 103
lowButtonTime = 103
lowButtonTime = 103
lowButtonTime = 103
thisButtonTime = 103 lowButtonTime = 103 buttonPressedTime = 0
lowButtonTime = 103
thisButtonTime = 103 lowButtonTime = 103 buttonPressedTime = 0
lowButtonTime = 54
lowButtonTime = 54
thisButtonTime = 72 lowButtonTime = 54 buttonPressedTime = 18
lowButtonTime = 165
lowButtonTime = 165
thisButtonTime = 215 lowButtonTime = 165 buttonPressedTime = 50
thisButtonTime = 157 lowButtonTime = 165 buttonPressedTime = -8
thisButtonTime = 157 lowButtonTime = 165 buttonPressedTime = -8
thisButtonTime = 157 lowButtonTime = 165 buttonPressedTime = -8
lowButtonTime = 157
thisButtonTime = 157 lowButtonTime = 157 buttonPressedTime = 0
thisButtonTime = 158 lowButtonTime = 157 buttonPressedTime = 1
lowButtonTime = 158
lowButtonTime = 158
lowButtonTime = 158
thisButtonTime = 158 lowButtonTime = 158 buttonPressedTime = 0
lowButtonTime = 158
lowButtonTime = 158
thisButtonTime = 158 lowButtonTime = 158 buttonPressedTime = 0
lowButtonTime = 158
lowButtonTime = 159
thisButtonTime = 159 lowButtonTime = 159 buttonPressedTime = 0
lowButtonTime = 159
lowButtonTime = 160
thisButtonTime = 226 lowButtonTime = 160 buttonPressedTime = 66
lowButtonTime = 50
thisButtonTime = 50 lowButtonTime = 50 buttonPressedTime = 0
lowButtonTime = 51
lowButtonTime = 108
lowButtonTime = 109
lowButtonTime = 132
lowButtonTime = 132
lowButtonTime = 134
lowButtonTime = 134
lowButtonTime = 137
lowButtonTime = 99
thisButtonTime = 99 lowButtonTime = 99 buttonPressedTime = 0
lowButtonTime = 99
lowButtonTime = 99
lowButtonTime = 99
thisButtonTime = 100 lowButtonTime = 99 buttonPressedTime = 1
lowButtonTime = 100
lowButtonTime = 100
lowButtonTime = 100
thisButtonTime = 100 lowButtonTime = 100 buttonPressedTime = 0
lowButtonTime = 100
thisButtonTime = 100 lowButtonTime = 100 buttonPressedTime = 0
lowButtonTime = 100
thisButtonTime = 101 lowButtonTime = 100 buttonPressedTime = 1
lowButtonTime = 60
lowButtonTime = 60
lowButtonTime = 131
lowButtonTime = 131
thisButtonTime = 131 lowButtonTime = 131 buttonPressedTime = 0
lowButtonTime = 35
lowButtonTime = 35
lowButtonTime = 35
thisButtonTime = 35 lowButtonTime = 35 buttonPressedTime = 0
lowButtonTime = 35
thisButtonTime = 234 lowButtonTime = 35 buttonPressedTime = 199
thisButtonTime = 234 lowButtonTime = 35 buttonPressedTime = 199
lowButtonTime = 186
thisButtonTime = 186 lowButtonTime = 186 buttonPressedTime = 0
lowButtonTime = 186
lowButtonTime = 186
lowButtonTime = 186
lowButtonTime = 187
lowButtonTime = 187
lowButtonTime = 187
lowButtonTime = 187
lowButtonTime = 187
lowButtonTime = 187
thisButtonTime = 124 lowButtonTime = 187 buttonPressedTime = -63
lowButtonTime = 50
lowButtonTime = 50
lowButtonTime = 50
thisButtonTime = 50 lowButtonTime = 50 buttonPressedTime = 0
lowButtonTime = 50
lowButtonTime = 50
lowButtonTime = 50
lowButtonTime = 50
lowButtonTime = 50
lowButtonTime = 50
thisButtonTime = 204 lowButtonTime = 50 buttonPressedTime = 154
lowButtonTime = 95
lowButtonTime = 95
lowButtonTime = 95
lowButtonTime = 95
lowButtonTime = 95
lowButtonTime = 96
lowButtonTime = 96
lowButtonTime = 96
lowButtonTime = 96
lowButtonTime = 49
thisButtonTime = 49 lowButtonTime = 49 buttonPressedTime = 0
lowButtonTime = 5
thisButtonTime = 33 lowButtonTime = 5 buttonPressedTime = 28
thisButtonTime = 33 lowButtonTime = 5 buttonPressedTime = 28
lowButtonTime = 37
thisButtonTime = 37 lowButtonTime = 37 buttonPressedTime = 0
lowButtonTime = 37
lowButtonTime = 37
lowButtonTime = 37
lowButtonTime = 37
thisButtonTime = 37 lowButtonTime = 37 buttonPressedTime = 0
thisButtonTime = 37 lowButtonTime = 37 buttonPressedTime = 0
lowButtonTime = 37
thisButtonTime = 37 lowButtonTime = 37 buttonPressedTime = 0
lowButtonTime = 37
thisButtonTime = 37 lowButtonTime = 37 buttonPressedTime = 0
lowButtonTime = 37
thisButtonTime = 37 lowButtonTime = 37 buttonPressedTime = 0
thisButtonTime = 37 lowButtonTime = 37 buttonPressedTime = 0
thisButtonTime = 37 lowButtonTime = 37 buttonPressedTime = 0
thisButtonTime = 37 lowButtonTime = 37 buttonPressedTime = 0
lowButtonTime = 37
lowButtonTime = 37
lowButtonTime = 37
thisButtonTime = 37 lowButtonTime = 37 buttonPressedTime = 0
thisButtonTime = 37 lowButtonTime = 37 buttonPressedTime = 0
thisButtonTime = 37 lowButtonTime = 37 buttonPressedTime = 0
lowButtonTime = 37
thisButtonTime = 38 lowButtonTime = 37 buttonPressedTime = 1
thisButtonTime = 40 lowButtonTime = 37 buttonPressedTime = 3
thisButtonTime = 40 lowButtonTime = 37 buttonPressedTime = 3
lowButtonTime = 40
lowButtonTime = 40
thisButtonTime = 40 lowButtonTime = 40 buttonPressedTime = 0
lowButtonTime = 40
thisButtonTime = 40 lowButtonTime = 40 buttonPressedTime = 0
thisButtonTime = 40 lowButtonTime = 40 buttonPressedTime = 0
lowButtonTime = 40
lowButtonTime = 40
lowButtonTime = 40
thisButtonTime = 40 lowButtonTime = 40 buttonPressedTime = 0
lowButtonTime = 40
lowButtonTime = 40
lowButtonTime = 40
thisButtonTime = 40 lowButtonTime = 40 buttonPressedTime = 0
thisButtonTime = 40 lowButtonTime = 40 buttonPressedTime = 0
thisButtonTime = 40 lowButtonTime = 40 buttonPressedTime = 0
thisButtonTime = 40 lowButtonTime = 40 buttonPressedTime = 0
lowButtonTime = 42
lowButtonTime = 42
thisButtonTime = 42 lowButtonTime = 42 buttonPressedTime = 0
thisButtonTime = 42 lowButtonTime = 42 buttonPressedTime = 0
lowButtonTime = 43
lowButtonTime = 43
thisButtonTime = 43 lowButtonTime = 43 buttonPressedTime = 0
lowButtonTime = 43
lowButtonTime = 43
lowButtonTime = 43
lowButtonTime = 43
lowButtonTime = 43
lowButtonTime = 43
lowButtonTime = 43
lowButtonTime = 43
lowButtonTime = 43
lowButtonTime = 43
lowButtonTime = 43
thisButtonTime = 43 lowButtonTime = 43 buttonPressedTime = 0
lowButtonTime = 43
lowButtonTime = 43
lowButtonTime = 43
lowButtonTime = 43
thisButtonTime = 43 lowButtonTime = 43 buttonPressedTime = 0
lowButtonTime = 43
thisButtonTime = 43 lowButtonTime = 43 buttonPressedTime = 0
lowButtonTime = 43
lowButtonTime = 44
thisButtonTime = 44 lowButtonTime = 44 buttonPressedTime = 0
lowButtonTime = 47
thisButtonTime = 47 lowButtonTime = 47 buttonPressedTime = 0
thisButtonTime = 47 lowButtonTime = 47 buttonPressedTime = 0
lowButtonTime = 47
lowButtonTime = 47
thisButtonTime = 47 lowButtonTime = 47 buttonPressedTime = 0
lowButtonTime = 47
lowButtonTime = 47
lowButtonTime = 49
lowButtonTime = 50
lowButtonTime = 50
lowButtonTime = 50
lowButtonTime = 50
thisButtonTime = 50 lowButtonTime = 50 buttonPressedTime = 0
thisButtonTime = 50 lowButtonTime = 50 buttonPressedTime = 0
lowButtonTime = 50
lowButtonTime = 50
thisButtonTime = 51 lowButtonTime = 50 buttonPressedTime = 1
lowButtonTime = 51
lowButtonTime = 52
lowButtonTime = 52
lowButtonTime = 52
lowButtonTime = 52
lowButtonTime = 53
lowButtonTime = 53
thisButtonTime = 54 lowButtonTime = 53 buttonPressedTime = 1
lowButtonTime = 54
thisButtonTime = 63 lowButtonTime = 54 buttonPressedTime = 9
lowButtonTime = 64
lowButtonTime = 64
lowButtonTime = 64
lowButtonTime = 64
lowButtonTime = 64
lowButtonTime = 64
lowButtonTime = 64
lowButtonTime = 64
lowButtonTime = 64
lowButtonTime = 64
lowButtonTime = 64
lowButtonTime = 64
lowButtonTime = 64
lowButtonTime = 64
lowButtonTime = 64
lowButtonTime = 64
lowButtonTime = 70
lowButtonTime = 70
lowButtonTime = 71
lowButtonTime = 71
lowButtonTime = 71
lowButtonTime = 71
lowButtonTime = 71
lowButtonTime = 71
lowButtonTime = 71
lowButtonTime = 71
lowButtonTime = 71
lowButtonTime = 71
lowButtonTime = 71
lowButtonTime = 71
lowButtonTime = 71
lowButtonTime = 71
lowButtonTime = 72
lowButtonTime = 72
lowButtonTime = 72
lowButtonTime = 73
thisButtonTime = 73 lowButtonTime = 73 buttonPressedTime = 0
lowButtonTime = 73
lowButtonTime = 112
thisButtonTime = 112 lowButtonTime = 112 buttonPressedTime = 0
thisButtonTime = 112 lowButtonTime = 112 buttonPressedTime = 0
thisButtonTime = 112 lowButtonTime = 112 buttonPressedTime = 0
lowButtonTime = 112
thisButtonTime = 112 lowButtonTime = 112 buttonPressedTime = 0
lowButtonTime = 232
lowButtonTime = 232
lowButtonTime = 232
lowButtonTime = 232
thisButtonTime = 232 lowButtonTime = 232 buttonPressedTime = 0
lowButtonTime = 232
thisButtonTime = 232 lowButtonTime = 232 buttonPressedTime = 0
thisButtonTime = 232 lowButtonTime = 232 buttonPressedTime = 0
lowButtonTime = 232
thisButtonTime = 232 lowButtonTime = 232 buttonPressedTime = 0
lowButtonTime = 233
thisButtonTime = 233 lowButtonTime = 233 buttonPressedTime = 0
lowButtonTime = 233
thisButtonTime = 233 lowButtonTime = 233 buttonPressedTime = 0
thisButtonTime = 233 lowButtonTime = 233 buttonPressedTime = 0
thisButtonTime = 233 lowButtonTime = 233 buttonPressedTime = 0
thisButtonTime = 233 lowButtonTime = 233 buttonPressedTime = 0
lowButtonTime = 233
lowButtonTime = 233
lowButtonTime = 234
lowButtonTime = 234
lowButtonTime = 234
thisButtonTime = 74 lowButtonTime = 234 buttonPressedTime = -160

I seem to get a lot of low values without any intervening high values i.e. falling edges without any intervening rising edges. I assume that the ISR is not fast enough to catch the rising edges?
Also I get negative values from utime.tick_diff() which I assumed would take into account roll over of values?
Finally can you tell me how long a period utime.tick_ms will give me before rolloing over?

By the way I am touching P0 to ground with a wire so I would expect this t be a worse case scenario for debouncing. Also the green led does toggles sometimes but not what I would call reliably.

To answer my own question. Using array.array((‘B’) and array.array{‘L’) instead of bytearray for buffer allocations seems to cure my immediate problems.
I used pyb.millis() instead of utime.tick_ms() but it is not immediately clear whether this helped.
At least the documentation tells me what the return type for pyb.millis() is.
Now I have to cope with consecutive trailing falling edge interrupts after the single rising edge interrupt on button release.
I would not recommend this implementation for switch debouncing.

Hi, traveling for thanksgiving. Hard for me to answer quickly. Glad to hear you worked it out.

So the following is my best endeavours to date. If anyone has any ideas for improvements please let me know.

import pyb
import array

import micropython
micropython.alloc_emergency_exception_buf(200)


class ButtonMonitor():
    __ringTail = 0
    __ringHead = 0
    __ringOverflow = False
    __msRingBuffer = None
    __trRingBuffer = None
    __buttonPin = None
    __extInt = None
    __lowButtonTime = None

    __RING_SIZE = 100
    __BUTTON_SHORT_PRESS_TIME = 20    # milliseconds
    __BUTTON_LONG_PRESS_TIME = 1500    # milliseconds
    # Basically an enum
    __NO_PRESS = 0
    __SHORT_PRESS = 1
    __LONG_PRESS = 2

    # button transition ISR
    def buttonTransitionISR(self, line):
        if self.__ringOverflow == False:
            self.__trRingBuffer[self.__ringHead] = self.__buttonPin.value()
            self.__msRingBuffer[self.__ringHead] = pyb.millis()
            localRingHead = (self.__ringHead + 1) % self.__RING_SIZE
            if localRingHead == self.__ringTail:
                self__ringOverflow = True
            else:
                self.__ringHead = localRingHead
        # else: do nothing for now

    # Constructor
    def __init__(self, port):
        # Initialise ring buffer
        self.__trRingBuffer = array.array('B')
        self.__msRingBuffer = array.array('l')
        # Size the byte arrays according to there expected content
        for index in range(0,self.__RING_SIZE):
            self.__trRingBuffer.append(False)
            self.__msRingBuffer.append(pyb.millis())

        # experimental button pin
        self.__buttonPin = pyb.Pin(port, pyb.Pin.IN)

        # set up ISR for button press
        self.__extInt = pyb.ExtInt(   self.__buttonPin,
                                    pyb.ExtInt.IRQ_RISING_FALLING,
                                    pyb.Pin.PULL_UP,
                                    self.buttonTransitionISR)

    # check for button pressed condition
    def buttonPressedCheck(self):
        # Reset button pressed indication
        # Calling functions will only see it set the once
        self.buttonPressed = self.__NO_PRESS;

        while(True):
            # Start peeling stuff out of the ring buffer
            if self.__ringHead == self.__ringTail:
                # head == tail implies buffer empty
                break

            if self.__lowButtonTime == None:
                # Initialisation requires that we see a low pin first
                if self.__trRingBuffer[self.__ringTail] == 0:
                    self.__lowButtonTime = self.__msRingBuffer[self.__ringTail]
            elif self.__trRingBuffer[self.__ringTail] == 0:
                # Get ms value for low button
                self.__lowButtonTime = self.__msRingBuffer[self.__ringTail]
            else:
                # Got ms value for high button
                thisButtonTime = self.__msRingBuffer[self.__ringTail]
                buttonPressedTime = thisButtonTime - self.__lowButtonTime
                if buttonPressedTime >= self.__BUTTON_SHORT_PRESS_TIME:
                    if buttonPressedTime >= self.__BUTTON_LONG_PRESS_TIME:
                        self.buttonPressed = self.__LONG_PRESS
                    else:
                        self.buttonPressed = self.__SHORT_PRESS

            # Increment tail
            self.__ringTail = (self.__ringTail + 1) % self.__RING_SIZE

            # end of while(True)

    # diagnostic function
    def dumpQueue(self):
        while(True):
            # Start peeling stuff out of the ring buffer
            if self.__ringHead == self.__ringTail:
                # head == tail implies buffer empty
                break

            print (self.__trRingBuffer[self.__ringTail], " ", self.__msRingBuffer[self.__ringTail])

            # Increment tail
            self.__ringTail = (self.__ringTail + 1) % self.__RING_SIZE

# Initialise button monitors
P0Monitor = ButtonMonitor('P0')

red_led = pyb.LED(1)
green_led = pyb.LED(2)

# start with LEDs off
green_led.off()
red_led.off()

while(True):
    P0Monitor.buttonPressedCheck()
    if P0Monitor.buttonPressed == P0Monitor.__SHORT_PRESS:
        print("Short press")
        red_led.off()
        green_led.toggle()
    if P0Monitor.buttonPressed == P0Monitor.__LONG_PRESS:
        print("Long press")
        green_led.off()
        red_led.toggle()