Portexpander MCP23017

Über den Beitrag

In meinem Beitrag über die Porterweiterung am ESP-01 hatte ich den MCP23017 schon einmal kurz beschrieben, hier möchte ich nun im Detail auf seine vielfältigen Möglichkeiten eingehen. Im ersten Teil des Beitrages möchte ich euch zeigen wie man den MCP23017 mit Hilfe einer Bibliothek einsetzt. Der zweite Teil ist ein Blick hinter die Kulissen für diejenigen, die etwas tiefer einsteigen wollen. Dabei gehe ich auf die zahlreichen Register des MCP23017 ein. 

MCP23017 – eine Kurzbeschreibung

Der MCP23017 ist ein 16-Bit I/O Portexpander, der über komfortable Interruptfunktionen verfügt. Die 16 I/O Pins sind in zwei Ports (A und B) organisiert, die separat (Byte Mode) oder zusammen (Sequential Mode) angesprochen werden. Die Versorgungsspannung sollte zwischen 1.8 und 5.5 Volt liegen. Der maximale Strom an den I/O Pins beträgt 25 mA in beide Richtungen. In Summe soll der Eingangsstrom an VDD 125 mA nicht überschreiten und über VSS (GND) sollen nicht mehr als 150 mA abfließen. Die Kommunikation erfolgt über I2C. Ein Datenblatt für den MCP23017 gibt es z.B. hier.

Der MCP23017 ist hinsichtlich seiner Flexibilität das Schweizer Taschenmesser unter den gängigen Portexpandern, wenn man ihn z.B. mit dem 74HC595 Schieberegister oder dem PCF8574 vergleicht. 

Pinout des MCP23017

Pinout des MCP23017
Pinout des MCP23017

Die 16 I/O Pins werden den beiden Ports entsprechend als GPA0 bis GPA7 bzw. GPB0 bis GPB7 benannt. Die Stromversorgung erfolgt über VDD und VSS. Die Beschaltung der Pins A0, A1 und A2 legt die I2C Adresse nach dem folgenden Schema fest:

1 0 0 A2 A1 A0 

Sind A0 bis A2 beispielsweise auf LOW, dann ist die Adresse 100000 (binär) = 32 (dezimal) = 0x20 (hexadezimal). SDA und SCL sind die beiden I2C Pins. Der Resetpin ist low-aktiv. INTA und INTB sind die Interruptpins für die beiden Ports. Die Polarität der Interruptpins könnt ihr einstellen. Ebenso könnt ihr beide Interruptpins zusammenschalten (Mirror Funktion). 

Ansteuerung mit der Bibliothek

Ich habe eine Bibliothek geschrieben, die ihr hier auf Github findet und herunterladen könnt. Die Bibliothek ist so konzipiert, dass die beiden Ports A und B im Byte Mode, also getrennt angesprochen werden. Vielleicht werde ich die Bibliothek irgendwann nochmal um den Sequential Mode erweitern.  

Einfache Input-/Output Anwendungen

Die Funktionalität der I/O Pins ist mit der Funktionalität der Arduino I/O Pins vergleichbar. So können die Pins als Input oder Output eingesetzt werden, sie werden HIGH oder LOW geschaltet und sie können sowohl als Stromlieferant wie auch als Stromsenke fungieren. Wenn sie als  Input geschaltet werden, dann können die Pins als Interruptpins dienen. Aber im ersten Beispiel werden zunächst einfach nur 16 LEDs gesteuert.     

Schaltplan zum Steuern von 16 LEDs mit dem MC23017
Schaltplan zum Steuern von 16 LEDs

Die Adresspins liegen in meiner Beispielschaltung auf LOW, somit ist die I2C Adresse 0x20. Der Resetpin ist mit dem Arduino Pin 5 verbunden. Die Pins von Port A und B steuern jeweils acht LEDs einer LED Leiste. Die I2C Leitungen SDA und SCL bekommen Pull-Ups mit 4.7 kOhm Widerständen. Ohne die Pull-Ups hat es bei mir allerdings auch gut funktioniert.

In diesem Beispiel werden die folgenden Funktionen verwendet (das MCP23017 Objekt heißt hier myMCP):

  • myMCP.Init(); initialisiert das Objekt mit einigen Voreinstellungen
  • myMCP.setPinMode( pin,port,direction ); entspricht der Arduino pinMode Funktion, wobei hier noch der Port als Parameter hinzukommt. 
    • zulässige Angaben für direction sind: INPUT/OUTPUT, OFF/ON oder 0/1
    • „0“= INPUT, „1“ =OUTPUT
  • myMCP.setPortMode( value,port ); pinMode für einen ganzen Port; value gibt man sinnvollerweise als Binärzahl an
  • myMCP.setPin( pin,port,level ); entspricht der digitalWrite Funktion;
    •  zulässige Angaben für level sind: 0/1, OFF/ON, LOW/HIGH
  • myMCP.setPort( value,port ); digitalWrite für ganzen Port; value gibt man wieder sinnvollerweise als Binärzahl an
  • myMCP.togglePin( pin,port ); wechselt einen Pin von LOW auf HIGH bzw. von HIGH auf LOW
  • myMCP.setPinX( pin,port,direction,level ); „extended version“ der setPin Funktion bzw. Kombination aus setPinMode und setPin
  • myMCP.setPortModeX( direction,value,port ); „extended version“ der setPort Funktion
  • myMCP.setAllPins( port,level ); setzt alle Pins eines Ports auf LOW oder HIGH

Beispielsketch für einfache Input/Output Anwendungen

Hier ein Sketch, der mit diesen Funktionen spielt und sie verdeutlicht:

#define MCP_ADDRESS 0x20 // (A2/A1/A0 = LOW) 
#include <Wire.h>
#include <MCP23017.h> 
MCP23017 myMCP(MCP_ADDRESS,5); 
int wT = 1000; // wT = waiting time

void setup(){ 
  Wire.begin();
  myMCP.Init();  
  myMCP.setPortMode(B11111101, A);  // Port A: alles auf OUTPUT bis auf PIN 1
  myMCP.setPortMode(B11111111, B);  // Port B: alles auf OUTPUT
  delay(wT);
  myMCP.setAllPins(A, ON); // alle LEDs an Port A leuchten bis auf Pin 1
  delay(wT);
  myMCP.setPinX(1, A, OUTPUT, HIGH); // Port A, Pin 1 geht an
  delay(wT); 
  myMCP.setPort(B11110000, B); // B4 - B7 leuchten
  delay(wT);
  myMCP.setPort(B01011110, A); // A0,A5,A7 gehen aus
  delay(wT);
  myMCP.setPinX(0,B,OUTPUT,HIGH); // B0 geht an
  delay(wT);
  myMCP.setPinX(4,B,OUTPUT,LOW); // B4 geht aus
  delay(wT);
  myMCP.setAllPins(A, HIGH); // A0 - A7 gehen an
  delay(wT);
  myMCP.setPin(3, A, LOW); // A3 geht aus
  delay(wT);
  myMCP.setPortX(B11110000, B01101111,B); // an B leuchten nur B5,B6
  delay(wT);
  myMCP.setPinMode(0,B,OUTPUT); // B0 auf OUTPUT
  for(int i=0; i<5; i++){  // B0 blinkt
    myMCP.togglePin(0,B); 
    delay(200);
    myMCP.togglePin(0,B);
    delay(200);
  }
  for(int i=0; i<5; i++){ // B7 blinkt
    myMCP.togglePin(7,B);
    delay(200);
    myMCP.togglePin(7,B);
    delay(200);
  }
}

void loop(){ 
} 

 

In meinem Beispiel fließt der Strom (technische Stromrichtung Plus -> Minus) vom MCP23017 durch die LEDs nach GND. Stattdessen könnte man den MCP23017 natürlich auch als Stromsenke einsetzen. Dann würde eine LED leuchten, wenn der zugehörige Pin OUTPUT und LOW ist und eine geeignete Spannung anliegt, also genau wie am Arduino. 

Pinstatus auslesen

Um den Pinstatus im GPIO Register auszulesen werden folgende Funktionen verwendet:

  • myMCP.getPin( pin,port ); liefert den Level eines Pins (als bool)
  • myMCP.getPort( port ); liefert den Status eines ganzen Ports (als byte), sprich den Inhalt des GPIO Registers

Ihr könnt dieselbe Schaltung wie oben verwenden und in Verbindung mit dem folgenden Sketch ein bisschen mit diesen Funktionen herumspielen. Setzt Ihr an einen LOW geschalteten Ausgang eine externe Spannung in der Höhe des HIGH Levels, dann werdet Ihr sehen, dass im GPIO Register ein HIGH steht. Im GPIO Register steht also der tatsächliche logische Level und nicht der vorgegebene. 

#define MCP_ADDRESS 0x20 // (A2/A1/A0 = LOW) 
#include <Wire.h>
#include <MCP23017.h> 
MCP23017 myMCP(MCP_ADDRESS,5); 
int wT = 1000; // wT = waiting time
byte portStatus;
bool pinStatus;

void setup(){ 
  Serial.begin(9600);
  Wire.begin();
  myMCP.Init();  
  myMCP.setPortMode(B11111111, A);  // Port A: alles auf OUTPUT
  myMCP.setPortMode(B11111111, B);  // Port B: alles auf OUTPUT
  myMCP.setPort(B10010011,A);
}

void loop(){ 
  portStatus = myMCP.getPort(A);
  Serial.print("Status GPIO A: ");
  Serial.println(portStatus, BIN);
  pinStatus = myMCP.getPin(7, A);
  Serial.print("Status Port A, Pin 7: ");
  Serial.println(pinStatus, BIN);
  portStatus = myMCP.getPort(B);
  Serial.print("Status GPIO B: ");
  Serial.println(portStatus, BIN);
  pinStatus = myMCP.getPin(0, B);
  Serial.print("Status Port B, Pin 0: ");
  Serial.println(pinStatus, BIN);
  Serial.println("-------------------------------------");
  delay(5000);
} 

Als INPUT konfigurierte I/Os können einen internen Pull-Up bekommen: 

  • myMCP.setPinPullUp( pin,port,level ); setzt einen Pull-Up mit einem 100 kOhm Widerstand
  • myMCP.setPortPullUp( value,port ); ist das Pendant für einen ganzen Port

Das könnt ihr ja noch im obigen Sketch mit einbauen und ausprobieren. 

Interrupt-on-Change

Alle 16 I/O Pins lassen sich als Interruptpins konfigurieren. Dabei gibt es zwei Modi, nämlich den Interrupt-on-Change und den Interrupt-on-Defval-Deviation. Ich beginne mit der Interrupt-on-Change Funktion, bei der jeder LOW-HIGH oder HIGH-LOW Wechsel einen Interrupt auslöst. Der Interrupt führt zu einem Polaritätswechsel an dem jeweiligen Interruptausgang INTA oder INTB. Alternativ könnt ihr INTA und INTB zusammenlegen. Außerdem könnt ihr die Polarität der Interruptausgänge einstellen. 

Nur als INPUT eingestellte Pins können als Interruptpins fungieren, aber diese Einstellung übernimmt die Bibliothek.

Folgende Funktionen habe ich für Interrupt-on-Change implementiert:

  • myMCP.setInterruptOnChangePin( pin,port ); richtet einen einzelnen Pin als Interrupt-on-Change Pin ein
  • myMCP.setInterruptOnChangePort( value,port ); richtet mehrere oder alle Pins eines Ports als Interrupt-on-Change Pin ein 
  • myMCP.setInterruptPinPol( level ); legt den Level des aktiven Interruptausgangs fest
    •  level = HIGH –> active-high, level = LOW –> active-low (Voreinstellung) 
    •  ich habe nur eine Einstellung für beide Ausgänge implementiert, also beide active-high oder beide active-low 
  • myMCP.setIntOdr( value ); value = 1 oder ON –> Interruptausgänge gehen in den Open Drain Zustand, die Interruptpin Polarität wird überschrieben; value = 0 oder OFF –> active-low oder active-high (beide)
  • myMCP.deleteAllInterruptsOnPort( port ); macht die Einrichtung der Interruptpins rückgängig
  • myMCP.setIntMirror ( value ); value = 1 oder ON –> INTA / INTB werden gespiegelt, value = 2 oder OFF –> INTA / INTB sind separat für ihre Ports zuständig (Voreinstellung)
  • myMCP.getIntFlag( port ); liefert den Wert des Interrupt Flag Registers als byte zurück. Im Interrupt Flag Register ist das Bit gesetzt welches den für den letzten Interrupt verantwortlichen Pin repräsentiert
  • myMCPgetIntCap( port ); liefert den Wert des Interrupt Capture Registers zurück. Es enthält den Wert des GPIO Registers zum Zeitpunkt des Interrupts. 

Zum Testen habe ich die folgende Schaltung aufgebaut:

Schaltplan zum Testen der Interrupt on Change Funktion mit dem MCP23017
Schaltplan zum Testen der Interrupt-on-Pin-Change Funktion

Die Pins an Port B werden als Interruptpins eingerichtet und bekommen über die Taster HIGH-Signale. Die LEDs an Port A sollen anzeigen an welchem Pin der Interrupt aufgetreten ist. 

Beispielsketch für Interrupt-on-Change

#define MCP_ADDRESS 0x20 // (A2/A1/A0 = LOW) 
#include <Wire.h>
#include <MCP23017.h> 
int interruptPin = 3;
volatile bool event; 
byte intCapReg; 

MCP23017 myMCP(MCP_ADDRESS,5); // 5 = ResetPin

void setup(){ 
  pinMode(interruptPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(interruptPin), eventHappened, RISING);
  Serial.begin(9600);
  Wire.begin();
  myMCP.Init(); 
  myMCP.setPortMode(B11111111,A);
  myMCP.setPort(B11111111, A); // kurzer LED Test
  delay(1000); 
  myMCP.setAllPins(A, OFF);
  delay(1000);
  myMCP.setInterruptPinPol(HIGH);
  delay(10);
  myMCP.setInterruptOnChangePort(B11111111, B);
  event=false;
}  

void loop(){ 
  intCapReg = myMCP.getIntCap(B); 
  if(event){
    delay(200);
    byte intFlagReg, eventPin; 
    intFlagReg = myMCP.getIntFlag(B);
    eventPin = log(intFlagReg)/log(2);
    intCapReg = myMCP.getIntCap(B);
    Serial.println("Interrupt!");
    Serial.print("Interrupt Flag Register: ");
    Serial.println(intFlagReg,BIN); 
    Serial.print("Interrupt Capture Register: ");
    Serial.println(intCapReg,BIN); 
    Serial.print("Pin No.");
    Serial.print(eventPin);
    Serial.print(" went ");
    if((intFlagReg&intCapReg) == 0){
      Serial.println("LOW");
    }
    else{
      Serial.println("HIGH");
    }
    myMCP.setPort(intFlagReg, A);
    //delay(1000);
    event = false; 
  }
}

void eventHappened(){
  event = true;
}

 


Ausgabe des Interrupt-on-Pin-Change Sketches
Ausgabe des Interrupt-on-Pin-Change Sketches

Hinweis 1: Bei schnellem Drücken des Tasters wird der HIGH-LOW Interrupt „verschluckt“. 

Hinweis 2: der Interrupt bleibt so lange aktiv bis eine getIntCap oder getPort Abfrage erfolgt. Wenn es dumm läuft und man fragt zum falschen Zeitpunkt ab oder es kommt zum falschen Zeitpunkt der nächste Interrupt, bleibt der Interrupt ungewollt bestehen. Deswegen habe ich in Zeile 30 die zusätzliche Abfrage eingefügt, die auf den ersten Blick überflüssig erscheint. Dadurch ist sichergestellt, dass der MCP23017 bereit ist für den nächsten Interrupt. Besonders relevant wird die Problematik bei den Interrupts-on-DefVal-Deviation. 

Interrupt-on-DefVal-Deviation

Hier wird die Polarität der Interruptpins mit der Vorgabe im sogenannten DEFVAL Register verglichen. Eine Abweichung (Deviation) führt zu einem Interrupt. Wenn ihr das Interrupt Capture oder das GPIO Register auslest, löscht ihr dadurch den Interrupt. Wenn allerdings die Interruptbedingung zu diesem Zeitpunkt immer noch erfüllt ist, dann wird sofort der nächste Interrupt ausgelöst.

Für diese Interruptmethode habe ich die folgenden zusätzlichen Funktionen implementiert:

  • myMCP.setInterruptOnDefValDevPin( intpin,port,defvalstate ); intpin ist der Interruptpin, defvalstate ist das Vorgabelevel und eine Abweichung davon führt zum Interrupt
  • myMCP.setInterruptOnDefValDevPort( intpins,Port,defvalstate );
    • intpins sind die Interruptpins, z.B. würde B10000001 die Pins 0 und 7 zum Interruptpin machen
    • defvalstate ist die Vorgabe für das DEFVAL Register; eine Abweichung führt zum Interrupt 

Als Beispiel habe ich die folgende Schaltung gewäht:

Schaltplan zum Testen der Interrupt-on-DefVal-Deviation Funktion am MCP23017
Schaltplan zum Testen der Interrupt-on-DefVal-Deviation Funktion

Die Port B Pins werden als Interruptpins definiert. B0 bis B3 werden mit internen Pull-Ups auf HIGH gelegt, hingegen bekommen B4 bis B7 Pull-Down Widerstände. Durch Tasterdruck wird die Polarität am jeweiligen Pin umgedreht. Port A dient wie im letzten Beispiel wieder der Anzeige des für den Interrupt verantwortlichen Pin. 

Beispielsketch für Interrupt-on-Defval-Deviation

#define MCP_ADDRESS 0x20 // (A2/A1/A0 = LOW) 
#include <Wire.h>
#include <MCP23017.h> 
int interruptPin = 3;
volatile bool event = false;
byte intCapReg; 

MCP23017 myMCP(MCP_ADDRESS,5); // 5 = ResetPin

void setup(){ 
  pinMode(interruptPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(interruptPin), eventHappened, RISING);
  Serial.begin(9600);
  Wire.begin();
  myMCP.Init();
  myMCP.setPortMode(B11111111, A);
  myMCP.setPort(B11111111, A); // kurzer LED Test
  delay(1000); 
  myMCP.setAllPins(A, OFF);
  delay(1000);
  myMCP.setInterruptPinPol(HIGH);
  delay(10);
  myMCP.setInterruptOnDefValDevPort(B11111111, B, B00001111); // IntPins, Port, DEFVAL
  myMCP.setPortPullUp(B00001111, B);
  event=false;
}  

void loop(){ 
  intCapReg = myMCP.getIntCap(B);
  if(event){
    delay(200);
    byte intFlagReg, eventPin; 
    intFlagReg = myMCP.getIntFlag(B);
    eventPin = log(intFlagReg)/log(2);
    intCapReg = myMCP.getIntCap(B);
    Serial.println("Interrupt!");
    Serial.print("Interrupt Flag Register: ");
    Serial.println(intFlagReg,BIN); 
    Serial.print("Interrupt Capture Register: ");
    Serial.println(intCapReg,BIN); 
    Serial.print("Pin No.");
    Serial.print(eventPin);
    Serial.print(" went ");
    if((intFlagReg&intCapReg) == 0){
      Serial.println("LOW");
    }
    else{
      Serial.println("HIGH");
    }
    myMCP.setPort(intFlagReg, A);
    delay(1000);
    event = false;
  }
}

void eventHappened(){
  event = true;
}

 

Der entscheidende Unterschied zum Interrupt-On-Change ist, dass bei dieser Methode der Polaritätswechsel nur in eine Richtung zum Interrupt führt. Entsprechend sieht die Ausgabe aus:

Ausgabe des Interrupt-on-DefVal-Dev Sketches
Ausgabe des Interrupt-on-DefVal-Dev Sketches

MCP23017 intern

Hier dann noch wie angekündigt ein paar zusätzliche Detailinformationen über den MCP23017 für die, die noch Lust haben. 

DerMCP23017 ist nur ein Vertreter der größeren MCP23XXX Familie, die sich untereinander durch die Anzahl der I/O Pins, die Ansteuerung (I2C vs SPI) und die externe Beschaltung unterscheiden. Der MCP23017 ist wohl der populärste Vertreter. Eine gute Übersicht über die MCP23XXX Familie findet Ihr hier

Die Register des MCP23017

Zunächst einmal muss man sich entscheiden, wie man die Register adressieren möchte. Dafür gibt es das BANK bit im IOCON Register. Ist dieses auf  1 gesetzt, dann befinden sich die Portregister in zwei getrennten Banks. Ist es hingegen auf 0 gesetzt, befinden sich die Register in derselben Bank und die Adressen sind sequentiell. Ich habe mich für letzteres entschieden und die Alternative auch nicht als Option implementiert. Die Register sind damit wie folgt definiert:

Registerübersicht des MCP23017 für IOCON.BANK = 0
Registerübersicht des MCP23017 wenn IOCON.BANK = 0

IODIR – I/O Direction Register

Im IODIR Register wird festgelegt, ob die Pins INPUT oder OUTPUT Pins sind. Es ist das einzige Register mit dem Start- bzw. Resetwert 0bx11111111. „1“ bedeutet INPUT, „0“ bedeutet OUTPUT, was für mich unlogisch klingt, aber vielleicht ist es auch nur die Gewohnheit aus der Arduinowelt. Weil mich das aber irritiert, habe ich die Werte in meiner Bibliothek entsprechend umgedreht. Mit myMCP.setPortMode() und myMCP.setPinMode() wird das IODIR Register direkt angesprochen. So bedeutet myMCP.setPortMode(B11111111, A) beispielsweise, dass alle Pins des Port A OUTPUT Pins sind. 

IPOL – Input Polarity Register

Wenn man die Bits in diesem Register setzt, dann wird im entsprechenden GPIO Register der invertierte Level der Pins gespeichert. Weil mir nicht einfiel wozu ich das gebrauchen könnte,  habe ich in meiner Bibliothek keinen Zugriff auf dieses Register vorgesehen. 

GPINTEN – Interrupt-on-Change Control Register

In diesem Register wird kontrolliert, welche Pins als Interrupt Pins verwendet werden. 0 = Disable, 1 = Enable. Will man nur Interrupt-on-Change implementieren, sind keine weiteren Einstellungen notwendig. Für den Fall aber, dass man Interrupt-on-Defval-Deviation implementieren möchte, muss man zusätzliche Einstellungen in den Registern DEFVAL und INTCON vornehmen. Auf das GPINTEN Register wird in meiner Bibliothek indirekt über die setInterruptOnChangePin() und setInterruptOnDefValDevPin() Funktionen bzw. deren Pendants für ganze Ports zugegriffen. 

DEFVAL – Default Value Register

Dieses Register wird für die Einstellung von Interrupts-on-Defval-Deviation benötigt. Weicht ein Wert im GPIO Register vom DEFVAL Register ab, wird ein Interrupt ausgelöst, sofern die entsprechenden Einstellungen im GPINTEN und INTCON Register vorgenommen wurden. 

INTCON – Interrupt Control Register

In diesem Register wird festgelegt, unter welchen Bedingungen Interrupts ausgelöst werden:

  • „0“: Vergleich mit vorherigem Pinstatus (Interrupt-on-Change)
  • „1“: Vergleich mit DEFVAL (Interrupt-on-DefVal-Deviation)

Allerdings sind die Einstellungen nur an den Pins wirksam, für die die entsprechenden Bits in GPINTEN gesetzt wurden. 

IOCON – I/O Expander Configuration Register

In diesem Register können einige Sondereinstellungen für den MCP23017 vorgenommen werden.

  • BANK – Adressierungsmethode für die Register
    • „1“: Register befinden sich in separaten Banks 
    • „0“: Register befinden in derselben Bank
    • einen Wechsel der Einstellung habe ich in meiner Bibliothek nicht vorgesehen
  • MIRROR – ist in meiner Bibliothek über setIntMirror() einstellbar
    • „1“: INTA und INTB sind verbunden (gespiegelt)
    • „0“: INTA und INTB sind separat für Port A bzw. B zuständig
  • SEQOP – sequentielle Adressierung
    • „1“: Disabled – der Adresszeiger wird nicht inkrementiert
    • „0“: Enabled – der Adresszeiger wird automatisch inkrementiert 
    • einen Wechsel der Einstellung habe ich in meiner Bibliothek nicht vorgesehen
  • DISSLW – Einstellung der Flankensteilheit des SDA Outputs
    • „1“: Disabled
    • „0“: Enabled
    • einen Wechsel der Einstellung habe ich nicht vorgesehen
  • HAEN – nicht relevant für den MCP23017
  • ODR – Open Drain für die Interruptpins INTA und INTB
    • „1“: Open Drain ist aktiv – überschreibt die INTPOL Einstellung
    • „0“: Disabled – Polarität des Interruptsignals wird durch INTPOL bestimmt
    • Einstellung erfolgt über setIntODR(); nur eine gemeinsame Einstellung für beide Pins ist in meiner Bibliothek vorgesehen (entweder beide 0 oder beide 1)
  • INTPOL – Polarität der Interruptpins
    • „1“: active-high
    • „0“: active-low
    • in meiner Bibliothek ist nur eine gemeinsame Einstellung beider Pins vorgesehen
  • GPPU – GPIO Pull-Up Register
    • „1“: Pull-Up mit 100 kOhm Widerstand
    • „0“: kein Pull-Up
    • in meiner Bibliothek implementiert durch setPinPullUp() oder setPortPullUp()
    • wirkt nur auf als Input konfigurierte Pins

INTF – Interrupt Flag Register (read-only)

In diesem Register wird festgehalten an welchem Pin der letzte Interrupt verursacht wurde. Das gesetzte Bit verrät den „Schuldigen“. In meiner Bibliothek fragt getIntFlag() den Inhalt ab. 

INTCAP – Interrupt Capture Value Register (read-only)

Dieses Register hält den Inhalt des GPIO Registers zum Zeitpunkt des letzten Interrupts vor. Ich habe die Abfrage durch die Funktion getIntCap() implementiert. 

GPIO – General Purpose I/O Port Register

Enthält den Pinstatus (HIGH/LOW). Ein Schreiben in das Register verändert auch das OLAT (Output Latch) Register. Der Schreibzugriff ist bei mir nur indirekt über verschiedene Funktionen implementiert. Der Lesezugriff erfolgt in meiner Bibliothek über getPin() oder getPort().

OLAT – Output Latch Register

Der Lesezugriff gibt den Zustand des Registers wieder und nicht den des Ports (das würde über den GPIO Read erfolgen). D.h. zum Beispiel, dass ein als LOW eingestellter Pin, an dem ein externes HIGH anliegt, hier als LOW gelesen würde, wohingegen im GPIO Register HIGH angezeigt würde. 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.