GPIO接続のLCDへ表示する(MCP23017の入力割り込み その2)


前回はIOエクスパンダ(MCP23017)を使って、 wiringPiISR()での割り込み処理を確認しましたが、うまく動きませんでした。
そこで、改めてIOエクスパンダ(MCP23017)での割り込み処理を紹介します。
回路図は以下のようになります。
MCP23017のポートAとポートBの動きを確認するために、ボタンは4つに増やしています。
紫のラインが割り込み入力用のラインです。



コードを書くにあたり、以下のページを参考にしました。
http://www.gammon.com.au/forum/?id=10945
Arduino用のコードをRaspberry用に書き直しただけです。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>

// MCP23017 registers (everything except direction defaults to 0)

#define IODIRA   0x00   // IO direction  (0 = output, 1 = input (Default))
#define IODIRB   0x01
#define IPOLA    0x02   // IO polarity   (0 = normal, 1 = inverse)
#define IPOLB    0x03
#define GPINTENA 0x04   // Interrupt on change (0 = disable, 1 = enable)
#define GPINTENB 0x05
#define DEFVALA  0x06   // Default comparison for interrupt on change (interrupts on opposite)
#define DEFVALB  0x07
#define INTCONA  0x08   // Interrupt control (0 = interrupt on change from previous, 1 = interrupt on change from DEFVAL)
#define INTCONB  0x09
#define IOCONA   0x0A   // IO Configuration: bank/mirror/seqop/disslw/haen/odr/intpol/notimp
#define IOCONB   0x0B
#define GPPUA    0x0C   // Pull-up resistor (0 = disabled, 1 = enabled)
#define GPPUB    0x0D
#define INTFA    0x0E   // Interrupt flag (read only) : (0 = no interrupt, 1 = pin caused interrupt)
#define INTFB    0x0F
#define INTCAPA  0x10   // Interrupt capture (read only) : value of GPIO at time of last interrupt
#define INTCAPB  0x11
#define GPIOA    0x12   // Port value. Write to change, read to obtain value
#define GPIOB    0x13
#define OLLATA   0x14   // Output latch. Write to latch output.
#define OLLATB   0x15

#define I2C_ADDR 0x20   // MCP23017 is on I2C port 0x20
#define PIE_PIN  11     // Raspberry Interrupt Pin Number

#define ON       0
#define OFF      1

int keyPressed;

void signal(void){
    printf("Signal\n");
    keyPressed = ON;
}

void handleKeypress (int fd) {
    unsigned int keyValue;
    int ret,ret2;
    int button;

    delay (100);  // de-bounce before we re-enable interrupts

    keyPressed = OFF;  // ready for next time through the interrupt service routine

// Read port values, as required. Note that this re-arms the interrupts.
    ret = wiringPiI2CReadReg8(fd,INTFA);
    if (ret != 0) {
        ret2 = wiringPiI2CReadReg8(fd,INTCAPA);
        keyValue = ret;    // read value at time of interrupt
    }
    ret = wiringPiI2CReadReg8(fd,INTFB);
    if (ret != 0) {
        ret2 = wiringPiI2CReadReg8(fd,INTCAPB);
        keyValue = ret*256; // port B is in low-order byte
    }

// display which buttons were down at the time of the interrupt
    for (button = 0; button < 16; button++) {
    // this key down?
        if (keyValue & (1 << button)) {
            printf("Button %0d now down\n",button+1);
        }  // end of if this bit changed
    }
}


int main(void){
    int fd,ret;

// I2C Setup
    fd = wiringPiI2CSetup(I2C_ADDR);
    if (fd == -1) {
        printf("wiringPiI2CSetup Error\n");
        return 1;
    }

// GPIO Setup
    if (wiringPiSetup() == -1) {
        printf("wiringPiSetup Error\n");
        return 1;
    }

// expander configuration register
// mirror interrupts, disable sequential mode
    if((wiringPiI2CWriteReg8(fd,IOCONA,0x60))<0){
        printf("write error register ICONA");
    }
    if((wiringPiI2CWriteReg8(fd,IOCONB,0x60))<0){
        printf("write error register ICONB");
    }

// enable pull-up on switches
// pull-up resistor for switch - both ports
    if((wiringPiI2CWriteReg8(fd,GPPUA,0xFF))<0){
        printf("write error register GPPUA");
    }
    if((wiringPiI2CWriteReg8(fd,GPPUB,0xFF))<0){
        printf("write error register GPPUB");
    }

// invert polarity
// invert polarity of signal - both ports
    if((wiringPiI2CWriteReg8(fd,IPOLA,0xFF))<0){
        printf("write error register IPOLA");
    }
    if((wiringPiI2CWriteReg8(fd,IPOLB,0xFF))<0){
        printf("write error register IPOLB");
    }

// enable all interrupts
// enable interrupts - both ports
    if((wiringPiI2CWriteReg8(fd,GPINTENA,0xFF))<0){
        printf("write error register GPINTENA");
    }
    if((wiringPiI2CWriteReg8(fd,GPINTENB,0xFF))<0){
        printf("write error register GPINTENB");
    }

// read from interrupt capture ports to clear them
    ret = wiringPiI2CReadReg8(fd,INTCAPA);
    ret = wiringPiI2CReadReg8(fd,INTCAPB);

    wiringPiISR( PIE_PIN, INT_EDGE_FALLING, signal );

    keyPressed=OFF;
    while(1){
        sleep(1);
        if (keyPressed == ON) handleKeypress (fd);
    }

    return 0;
}

ボタン1、2、3、4が押されたら(正確には上記赤字の部分で、INT_EDGE_FALLINGを指定しているのでボタンが ON→OFFになったら)
signal関数への割り込みが発生し、そこでkeyPressed変数をONにします。
keyPressed変数がONになったら、handleKeypress関数を使って割り込みを発生させたポートを調べて画面に文字を表示しま す。

MCP32017の場合

今回はあくまでも割り込みの確認なので、ループの中でsleep()を使いましたが、
セマフォと組み合わせればもっときれいなコードになると思い ます。