willhey / mcp23017chip

Node-red mcp23017chip
MIT License
6 stars 7 forks source link

Interrupts #10

Open geoffreydemaagd opened 3 years ago

geoffreydemaagd commented 3 years ago

Hi im currently using the node for inputs and outputs . For input the responding time is too slow, even when setting the polling at 5ms. Approx half of the inputs do not arrive when at that time the polling does not happen, if clicking a bit faster on a pushbutton. Should interrupts fix that problem? I find it strange that it is missing that much inputs when increasig a bit the speed of clicking

Marooned-MB commented 3 years ago

@geoffreydemaagd maybe just try your setup with interrupt and see if it would fix your problems? I don't have JS code but you could run this Python script I wrote a while ago. Just install python-smbus and RPi.GPIO (well, I assume you run it on RPi) modules and then run this (sorry for messy code and some comments, it's just copy-paste from my testing):

#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
import smbus
import RPi.GPIO as GPIO
import time

previousState = 0
mcpAddress = 0x20

#setup MCP23017
bus = smbus.SMBus(1)
#REGISTER 1-1: IODIR – I/O DIRECTION REGISTER (ADDR 0x00/01) -> 0: output; 1: input
bus.write_byte_data(mcpAddress, 0x00, 0xff) #A0-A7 as input
bus.write_byte_data(mcpAddress, 0x01, 0xff) #B0-B7 as input
#REGISTER 1-2: IPOL – INPUT POLARITY PORT REGISTER (ADDR 0x02/03) -> invert 0: normal; 1: inverted
bus.write_byte_data(mcpAddress, 0x02, 0x00) #A0-A7 active==1
bus.write_byte_data(mcpAddress, 0x03, 0x00) #B0-B7 active==1
#REGISTER 1-3: GPINTEN – INTERRUPT-ON-CHANGE PINS (ADDR 0x04/05) -> interrupt 0: disabled; 1: enabled
bus.write_byte_data(mcpAddress, 0x04, 0xff) #A0-A7 causes INT
bus.write_byte_data(mcpAddress, 0x05, 0xff) #B0-B7 causes INT
#REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER (ADDR 0x08/09) -> compare with 0: previous; 1: default
#REGISTER 1-6: IOCON – I/O EXPANDER CONFIGURATION REGISTER (ADDR 0x0a/0b) -> 7: bank; 6: mirror; 5: seqop; 4: disslw; 3: haen; 2: odr; 1: intpol; 0: n/c
IOCON = bus.read_byte_data(mcpAddress, 0x0a)
IOCON |= 0b01100100 #mirror | byte mode | odr (open drain interrupt)
bus.write_byte_data(mcpAddress, 0x0a, IOCON)
#REGISTER 1-7: GPPU – GPIO PULL-UP RESISTOR REGISTER (ADDR 0x0c/0d) -> pull-up 0: disabled; 1: enabled
bus.write_byte_data(mcpAddress, 0x0c, 0xff) #A0-A7 pull-up
bus.write_byte_data(mcpAddress, 0x0d, 0xff) #B0-B7 pull-up
#REGISTER 1-8: INTF – INTERRUPT FLAG REGISTER (ADDR 0x0e/0f) -> which pin caused INT (read-only)
#REGISTER 1-9: INTCAP – INTERRUPT CAPTURED VALUE FOR PORT REGISTER (ADDR 0x10/11) -> snapshot of GPIO at the time of INT (cleared by reading it or GPIO)
#REGISTER 1-10: GPIO – GENERAL PURPOSE I/O PORT REGISTER (ADDR 0x12/13) -> GPIO

#setup RPi
GPIO.setmode(GPIO.BCM)

# GPIO 23 set up as input. It is pulled up to stop false signals
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# callback for interrupt
def mcpInterrupt(channel):
    global previousState
    print "----------------\ninterrupt detected", channel#, "rising" if GPIO.input(23) else "falling"

    INTFA = bus.read_byte_data(mcpAddress, 0x0e)
    INTFB = bus.read_byte_data(mcpAddress, 0x0f)

    INTCAPA = bus.read_byte_data(mcpAddress, 0x10)
#   GPIOA = bus.read_byte_data(mcpAddress, 0x12)
    INTCAPB = bus.read_byte_data(mcpAddress, 0x11)
#   GPIOB = bus.read_byte_data(mcpAddress, 0x13)

#   print format(INTFA, '#010b'), "- INTFA\n", format(INTFB, '#010b'), "- INTFB"
#   print format(INTCAPA, '#010b'), "- INTCAPA\n", format(INTCAPB, '#010b'), "- INTCAPB"
#   print format(GPIOA, '#010b'), "- GPIOA\n", format(GPIOB, '#010b'), "- GPIOB"

    pinsInt = INTFB << 8 | INTFA
    pins = INTCAPB << 8 | INTCAPA
    pinsPrev = previousState
    previousState = pins
    print "original: int:{0:016b}  state:{1:016b}".format(pinsInt, pins)
    bitNo = 0
    while pinsInt:
        if pinsInt & 1 and pins & 1 != pinsPrev & 1:
            print bitNo, "open" if pins & 1 else "closed"

        bitNo+=1
        pinsInt >>= 1
        pins >>= 1
        pinsPrev >>= 1
#   mcpGPIO = bus.read_byte_data(mcpAddress, 0x12)
#   print format(mcpGPIO, '#010b'), "- INT mcpGPIO [before]"
#   mcpGPIO ^= 0x80
#   print format(mcpGPIO, '#010b'), "- INT mcpGPIO [after]"
#   bus.write_byte_data(mcpAddress, 0x12, mcpGPIO)

#   print format(bus.read_byte_data(mcpAddress, 0x13), '#010b'), "- mcpGPIO B"

#bus.write_byte_data(mcpAddress, 0x12, 0xff)
print "Waiting for falling edge on port 23"
GPIO.add_event_detect(23, GPIO.FALLING, callback=mcpInterrupt)#, bouncetime=200)

#read both GPIO to reset any pending interrupts
GPIOA = bus.read_byte_data(mcpAddress, 0x12)
GPIOB = bus.read_byte_data(mcpAddress, 0x13)

watchdog = 0
try:
    while True:
        time.sleep(2)

        #watchdog - clear interrupts
        if bus.read_byte_data(mcpAddress, 0x0e) > 0: #INTFA
            time.sleep(0.5) #int pending? give a chance to run handler - if int won't clear, we are stuck - clear manually
            if bus.read_byte_data(mcpAddress, 0x0e) > 0: #INTFA
                print "INT A stuck, claring"
                bus.read_byte_data(mcpAddress, 0x12) ;#GPIOA
        if bus.read_byte_data(mcpAddress, 0x0f) > 0: #INTFB
            time.sleep(0.5)
            if bus.read_byte_data(mcpAddress, 0x0f) > 0: #INTFB
                print "INT B stuck, claring"
                bus.read_byte_data(mcpAddress, 0x13) ;#GPIOB

except KeyboardInterrupt:
    print "CTRL+C exit"
    GPIO.cleanup()       # clean up GPIO on CTRL+C exit

Here is my example output:

pi@raspberrypi:~ $ ./mcp_int.py
Waiting for falling edge on port 23
----------------
interrupt detected 23
original: int:0000000000001000  state:1000000000001111
3 open
----------------
interrupt detected 23
original: int:0000000000001000  state:1000000000000111
3 closed
----------------
interrupt detected 23
original: int:0000000000010000  state:1000000000010111
4 open
----------------
interrupt detected 23
original: int:0000000000010000  state:1000000000000111
4 closed
^CCTRL+C exit