PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Fehler im Code oder Hardware



FlyingEaglE
28.02.2015, 00:48
Hallo,

ich hatte die Tage schon mal wegen Interruptproblemen beim MCP23017 gefragt, aber keine antworten erhalten, daher habe ich mich nochmal hingesetzt und den code auf das m.e. wesentliche reduziert:


#include <Wire.h>

#define Mcp_Reg_IODIRA 0x00 // IO direction (0 = output, 1 = input (Default))
#define Mcp_Reg_IODIRB 0x01
#define Mcp_Reg_IOPOLA 0x02 // IO polarity (0 = normal, 1 = inverse)
#define Mcp_Reg_IOPOLB 0x03
#define Mcp_Reg_GPINTENA 0x04 // Interrupt on change (0 = disable, 1 = enable)
#define Mcp_Reg_GPINTENB 0x05
#define Mcp_Reg_DEFVALA 0x06 // Default comparison for interrupt on change (interrupts on opposite)
#define Mcp_Reg_DEFVALB 0x07
#define Mcp_Reg_INTCONA 0x08 // Interrupt control (0 = interrupt on change from previous, 1 = interrupt on change from DEFVAL)
#define Mcp_Reg_INTCONB 0x09
#define Mcp_Reg_IOCON 0x0A // IO Configuration: bank/mirror/seqop/disslw/haen/odr/intpol/notimp
//#define Mcp_Reg_IOCON 0x0B // same as 0x0A
#define Mcp_Reg_GPPUA 0x0C // Pull-up resistor (0 = disabled, 1 = enabled)
#define Mcp_Reg_GPPUB 0x0D
#define Mcp_Reg_INFTFA 0x0E // Interrupt flag (read only) : (0 = no interrupt, 1 = pin caused interrupt)
#define Mcp_Reg_INFTFB 0x0F
#define Mcp_Reg_INTCAPA 0x10 // Interrupt capture (read only) : value of GPIO at time of last interrupt
#define Mcp_Reg_INTCAPB 0x11
#define Mcp_Reg_GPIOA 0x12 // Port value. Write to change, read to obtain value
#define Mcp_Reg_GPIOB 0x13
#define Mcp_Reg_OLLATA 0x14 // Output latch. Write to latch output.
#define Mcp_Reg_OLLATB 0x15

#define mcp 0x21

#define MCPResetPin 4 // hier hängt der MCP mit seinem Reset-Pin dran
#define MCPInterruptA 0 // hier hängt der MCP mit seinem Interrupt-Pin 19 dran
#define MCPInterruptB 1 // hier hängt der MCP mit seinem Interrupt-Pin 19 dran
#define LEDOnBoard 13 // pin 13, LED aufm Arduino-Board

byte WireTransmitResult = 0;
boolean SwitchPressed = false;
boolean isInInit = false;
byte inputStateA = 0;
byte inputStateB = 0;


void setup()
{
Serial.begin(9600);
Serial.println("Start");
Wire.begin();
initiic();
pinMode (LEDOnBoard, OUTPUT);
digitalWrite (LEDOnBoard, LOW);
attachInterrupt(MCPInterruptA, ISRSwitchPressed, FALLING);
// attachInterrupt(MCPInterruptB, ISRSwitchPressed, FALLING);
Serial.println("Bereit");
}



void loop()
{
if (SwitchPressed)
{
inputStateA = readiicbyte(mcp, Mcp_Reg_INTCAPA);
inputStateB = readiicbyte(mcp, Mcp_Reg_INTCAPB);

Serial.print("LOOP inputStateA: ");
Serial.println(inputStateA, BIN);
Serial.print("LOOP inputStateB: ");
Serial.println(inputStateB, BIN);

digitalWrite (LEDOnBoard, LOW);
SwitchPressed = false;
}
}



void ISRSwitchPressed ()
{
Serial.println("ISRSwitchPressed");
digitalWrite (LEDOnBoard, HIGH);

inputStateA = readiicbyte(mcp, Mcp_Reg_INTCAPA);
inputStateB = readiicbyte(mcp, Mcp_Reg_INTCAPB);

Serial.print("ISR inputStateA: ");
Serial.println(inputStateA, BIN);
Serial.print("ISR inputStateB: ");
Serial.println(inputStateB, BIN);

if (SwitchPressed || isInInit)
{
/*
Serial.println(inputState, BIN);
Serial.print("ISR SP: ");
Serial.println((String)isInInit);
Serial.print("ISR iI: ");
Serial.println((String)SwitchPressed);
Serial.println("ISR returned");
*/
digitalWrite (LEDOnBoard, LOW);
}
else
{
SwitchPressed = true;
}
}



void writeiic(uint8_t adr, uint8_t port, byte value)
{
Wire.beginTransmission( adr );
Wire.write( port );
Wire.write( value );
WireTransmitResult = Wire.endTransmission();

// String t = "writeiic: ";
// t += " Adr: " + String(adr) + " Port: " + String(port) + " Value: " + String(value);
// Serial.println(t);
}



byte readiicbyte(uint8_t adr, uint8_t port)
{
Serial.println("IIC Lesen");
byte returnword = 0x00;

Wire.beginTransmission(adr);
Wire.write(port);
Wire.endTransmission();
Wire.requestFrom((int)adr, 1);

int c = 0;

if (Wire.available())
{
returnword = Wire.read();
}
return returnword;
}



void initiic()
{
Serial.println("Init Wire");
isInInit = true;
SwitchPressed = false;

pinMode(MCPResetPin, OUTPUT);
digitalWrite(MCPResetPin, LOW);
delay(5);
digitalWrite(MCPResetPin, HIGH);

writeiic(mcp, Mcp_Reg_IODIRA, 0x00); // Alles auf Output setzen
writeiic(mcp, Mcp_Reg_GPIOA, 0x00); // Alle Pins auf 0 setzen
writeiic(mcp, Mcp_Reg_IODIRB, 0x00); // Alles auf Output setzen
writeiic(mcp, Mcp_Reg_GPIOB, 0x00); // alle Pins auf 0 setzen

byte inputMaskA = 0xFF;
byte inputMaskB = 0xFF;
byte polA = 0xFF;
byte polB = 0xFF;

writeiic(mcp, Mcp_Reg_IODIRA, inputMaskA); // Richtung (Ein-/Ausgang) einstellen
writeiic(mcp, Mcp_Reg_IODIRB, inputMaskB); // Richtung (Ein-/Ausgang) einstellen

writeiic(mcp, Mcp_Reg_GPPUA, inputMaskA); // Pull-Up Widerstände einrichten
writeiic(mcp, Mcp_Reg_GPPUB, inputMaskB); // Pull-Up Widerstände einrichten

writeiic(mcp, Mcp_Reg_IOPOLA, polA); // Polarität einstellen (für Eingänge 0 oder 1)
writeiic(mcp, Mcp_Reg_IOPOLB, polB); // Polarität einstellen (für Eingänge 0 oder 1)

writeiic(mcp, Mcp_Reg_GPINTENA, inputMaskA); // Interrupt aktivieren
writeiic(mcp, Mcp_Reg_GPINTENB, inputMaskB); // Interrupt aktivieren

writeiic(mcp, Mcp_Reg_DEFVALA, inputMaskA); // Interrupt Default-Wert festlegen
writeiic(mcp, Mcp_Reg_DEFVALB, inputMaskB); // Interrupt Default-Wert festlegen

writeiic(mcp, Mcp_Reg_INTCONA, inputMaskA); // Interrupt Vergleich einstellen, 0 = Änderung zum Vorgänger, 1 = Änderung zum DEFVAL-Wert
writeiic(mcp, Mcp_Reg_INTCONB, inputMaskB); // Interrupt Vergleich einstellen, 0 = Änderung zum Vorgänger, 1 = Änderung zum DEFVAL-Wert

readiicbyte(mcp, Mcp_Reg_INTCAPA); // Interrupts lesen und dadurch löschen
readiicbyte(mcp, Mcp_Reg_INTCAPB); // Interrupts lesen und dadurch löschen

Serial.println("Init Fertig");
isInInit = false;
}

Leider tuts das nicht, alle Serial-angaben sind nur zu debugzwecken drin!

Schon beim Start gehts los, es kommt gerade noch das "I" von "Init fertig" und dann passiert nix mehr.

Lasse ich die Zeile: attachInterrupt(MCPInterruptA, ISRSwitchPressed, FALLING); weg startet er wie gewünscht, klar logisch, ISR ist dann nicht mehr.

schaltung ist nicht spannend, spannungsversorgung an den mcp, adress-pins (die stimmen), reset und interrupts an die im code beschriebenen pins.

gedanke ist (später) beliebigen port als input/output schalten, interrupts auf a und/oder b legen, dass ich nur einen abfragen muss.
pull-ups aktiviert bei input. hier im test hängt nix weiter dran, daher alle pins auf input und pull-up.

plattform: arduino uno r3
das ist mittlerweile der 4 mcp den ich teste, alle anderen gehen aber noch!

jemand ne idee?

danke & grüße

FlyingEaglE
02.03.2015, 20:17
Keiner ne Idee?

RoboHolIC
03.03.2015, 00:48
Vorweg: Ich kann C kaum lesen geschwiege denn fremden Source nachvollziehen. Die Kommunikation via ISR zu realisieren beinhaltet bereits einige Fehlermöglichkeiten.

Hast du schon getestet, ob es klappt, wenn alle Befehle mit ausreichend Pausenzeit dazwischen als sequentielle Befehlsfolge programmiert sind? Das vermeidet Fehlermöglichkeiten mit ISR und I2C-bezogenen Statusbits.

Weitere Fehlermöglichkeit: Der I2C-Bus ist nach einem Warmstart (denkbar auch nach Kaltstart = Power Up) möglicherweise blockiert. Wenn zu Beginn der Kommunikation die Datenleitung low ist, wird kein Busbetrieb möglich sein. Man kann dann z.B. so lange den Pegel der Clock-Leitung hin und her wechseln, bis die Datenleitung auf High gegangen ist. Erst dann kann der Master einen Busreset durchsetzen.

Ist das Protokoll peinlich genau eingehalten? (Ich hab schon mit einem voll I2C-konformen Baustein gearbeitet, der allerdings auf der Verwendung eines Repeated Start beharrte, wo formal auch ein Stop & Start funktionieren sollte.) Es sind m.W. verschiedene Wege möglich, um Daten an die Portpins zu schreiben.

Sind ausreichend niederohmige Pullups an den I2C-Leitungen (ggf. inkl. Interruptleitung - da bin ich mir nicht sicher) ? Die internen Pullups den Controllers können die Busleitungen sehr wahrscheinlich nicht genügend schnell Richtung High ziehen.

Ich hoffe doch, aus deinen Fehlern lernen zu können, denn ich habe in nächster Zeit genau diesen Baustein ebenfalls auf der Agenda stehen.

FlyingEaglE
03.03.2015, 07:37
Robo, danke für deine hinweise. aber das meiste kann ich bejaen bzw. hier in meinem 5cm testaufbau als erstmal irrelevant einstufen.
die kommunikation in der ISR ist nur das ergebniss von 1001 debug-versuchen, soll da eigentlich nicht drin sein.
sobald ich dahinter gekommen bin werde ich es hier schreiben.

Siro
06.03.2015, 08:47
Hallo, das klingt für mich wie ein Dauerinterrupt.
Der Prozessor hängt in einem Interrupt, verlässt ihn und landet gleich wieder dort.
In der Interrupt Funktion muss eventuell ein Interrupt Bit gelöscht werden, bevor sie verlassen wird.

PICture
06.03.2015, 09:01
@ FlyingEaglE


In der Interrupt Funktion muss eventuell ein Interrupt Bit gelöscht werden, bevor sie verlassen wird.

Genau, dafür habe ich das Bit in erstem Befehl am Anfang jedes Interrupts gelöscht (um es später nicht zu vergessen). :)

FlyingEaglE
06.03.2015, 09:03
@PICture, Siro: Das verstehe ich nicht.


#include <Wire.h>
#include <TimerOne.h>



#define Mcp_Reg_IODIRA 0x00 // IO direction (0 = output, 1 = input (Default))
#define Mcp_Reg_IODIRB 0x01
#define Mcp_Reg_IOPOLA 0x02 // IO polarity (0 = normal, 1 = inverse)
#define Mcp_Reg_IOPOLB 0x03
#define Mcp_Reg_GPINTENA 0x04 // Interrupt on change (0 = disable, 1 = enable)
#define Mcp_Reg_GPINTENB 0x05
#define Mcp_Reg_DEFVALA 0x06 // Default comparison for interrupt on change (interrupts on opposite)
#define Mcp_Reg_DEFVALB 0x07
#define Mcp_Reg_INTCONA 0x08 // Interrupt control (0 = interrupt on change from previous, 1 = interrupt on change from DEFVAL)
#define Mcp_Reg_INTCONB 0x09
#define Mcp_Reg_IOCON 0x0A // IO Configuration: bank/mirror/seqop/disslw/haen/odr/intpol/notimp
//#define Mcp_Reg_IOCON 0x0B // same as 0x0A
#define Mcp_Reg_GPPUA 0x0C // Pull-up resistor (0 = disabled, 1 = enabled)
#define Mcp_Reg_GPPUB 0x0D
#define Mcp_Reg_INFTFA 0x0E // Interrupt flag (read only) : (0 = no interrupt, 1 = pin caused interrupt)
#define Mcp_Reg_INFTFB 0x0F
#define Mcp_Reg_INTCAPA 0x10 // Interrupt capture (read only) : value of GPIO at time of last interrupt
#define Mcp_Reg_INTCAPB 0x11
#define Mcp_Reg_GPIOA 0x12 // Port value. Write to change, read to obtain value
#define Mcp_Reg_GPIOB 0x13
#define Mcp_Reg_OLLATA 0x14 // Output latch. Write to latch output.
#define Mcp_Reg_OLLATB 0x15

#define mcp 0x21

#define MCPResetPin 4 // hier hängt der MCP mit seinem Reset-Pin dran
#define MCPInterruptA 0 // hier hängt der MCP mit seinem Interrupt-Pin 19 dran
#define MCPInterruptB 1 // hier hängt der MCP mit seinem Interrupt-Pin 19 dran
#define LEDOnBoard 13 // pin 13, LED aufm Arduino-Board

byte WireTransmitResult = 0;
volatile boolean SwitchPressed = false;
volatile boolean PolledTimer = false;
volatile boolean isInInit = false;
byte inputStateA = 0;
byte inputStateB = 0;
byte inputLastStateA = 0;
byte inputLastStateB = 0;
int lastRead = 0;

byte OutStateA = 0;
byte OutStateB = 0;

void setup()
{
Serial.begin(9600);
Serial.println("Start");
Wire.begin();
initiic();
pinMode (LEDOnBoard, OUTPUT);
digitalWrite (LEDOnBoard, LOW);
// attachInterrupt(MCPInterruptA, ISRSwitchPressed, FALLING);
// attachInterrupt(MCPInterruptB, ISRSwitchPressed, FALLING);
Serial.println("Bereit");
Timer1.initialize(50000); // 10 Hz
// Timer1.initialize(50000); // 20 Hz
// Timer1.initialize(25000); // 40 Hz
Timer1.attachInterrupt( ISRTimer ); // attach the service routine here
}



void loop()
{
// if (SwitchPressed || (millis() - lastRead >= 4000))
if (SwitchPressed || PolledTimer)
{
digitalWrite (LEDOnBoard, HIGH);

// inputStateA = readiicbyte(mcp, Mcp_Reg_INTCAPA);
// inputStateB = readiicbyte(mcp, Mcp_Reg_INTCAPB);
inputStateA = readiicbyte(mcp, Mcp_Reg_GPIOA);
inputStateB = readiicbyte(mcp, Mcp_Reg_GPIOB);
// inputStateA = readiicbyte(mcp, Mcp_Reg_OLLATA);
// inputStateB = readiicbyte(mcp, Mcp_Reg_OLLATB);

if (inputStateA != inputLastStateA || inputStateB != inputLastStateB)
{
for (byte i = 0; i <= 7; i++)
{
if (inputStateA & (1 << i))
{
OutStateA ^= (1 << i);
}
if (inputStateB & (1 << i))
{
OutStateB ^= (1 << i);
}
}

Serial.print(OutStateA, BIN);
Serial.print(" ");
Serial.print(OutStateB, BIN);
Serial.println("\n");

inputLastStateA = inputStateA;
inputLastStateB = inputStateB;

digitalWrite (LEDOnBoard, LOW);

lastRead = millis();
SwitchPressed = false;
PolledTimer = false;
}
}
}



void ISRSwitchPressed()
{
if (!SwitchPressed && !isInInit)
{
SwitchPressed = true;
}
}



void ISRTimer()
{
if (!SwitchPressed && !isInInit && !PolledTimer)
{
PolledTimer = true;
}
}


void writeiic(uint8_t adr, uint8_t port, byte value)
{
Wire.beginTransmission( adr );
Wire.write( port );
Wire.write( value );
WireTransmitResult = Wire.endTransmission();

// String t = "writeiic: ";
// t += " Adr: " + String(adr) + " Port: " + String(port) + " Value: " + String(value);
// Serial.println(t);
}



byte readiicbyte(uint8_t adr, uint8_t port)
{
//Serial.println("IIC Lesen");
byte returnword = 0x00;

Wire.beginTransmission(adr);
Wire.write(port);
Wire.endTransmission();
Wire.requestFrom((int)adr, 1);

int c = 0;

if (Wire.available())
{
returnword = Wire.read();
}
return returnword;
}



void initiic()
{
Serial.println("Init Wire");
isInInit = true;
SwitchPressed = false;
PolledTimer = false;

pinMode(MCPResetPin, OUTPUT);
digitalWrite(MCPResetPin, LOW);
delay(5);
digitalWrite(MCPResetPin, HIGH);

writeiic(mcp, Mcp_Reg_IODIRA, 0x00); // Alles auf Output setzen
writeiic(mcp, Mcp_Reg_GPIOA, 0x00); // Alle Pins auf 0 setzen
writeiic(mcp, Mcp_Reg_IODIRB, 0x00); // Alles auf Output setzen
writeiic(mcp, Mcp_Reg_GPIOB, 0x00); // alle Pins auf 0 setzen

byte inputMaskA = 0xFF;
byte inputMaskB = 0xFF;
byte polA = 0xFF;
byte polB = 0xFF;

writeiic(mcp, Mcp_Reg_IODIRA, inputMaskA); // Richtung (Ein-/Ausgang) einstellen
writeiic(mcp, Mcp_Reg_IODIRB, inputMaskB); // Richtung (Ein-/Ausgang) einstellen

writeiic(mcp, Mcp_Reg_GPPUA, inputMaskA); // Pull-Up Widerstände einrichten
writeiic(mcp, Mcp_Reg_GPPUB, inputMaskB); // Pull-Up Widerstände einrichten

writeiic(mcp, Mcp_Reg_IOPOLA, polA); // Polarität einstellen (für Eingänge 0 oder 1)
writeiic(mcp, Mcp_Reg_IOPOLB, polB); // Polarität einstellen (für Eingänge 0 oder 1)

writeiic(mcp, Mcp_Reg_GPINTENA, inputMaskA); // Interrupt aktivieren
writeiic(mcp, Mcp_Reg_GPINTENB, inputMaskB); // Interrupt aktivieren

writeiic(mcp, Mcp_Reg_DEFVALA, inputMaskA); // Interrupt Default-Wert festlegen
writeiic(mcp, Mcp_Reg_DEFVALB, inputMaskB); // Interrupt Default-Wert festlegen

writeiic(mcp, Mcp_Reg_INTCONA, inputMaskA); // Interrupt Vergleich einstellen, 0 = Änderung zum Vorgänger, 1 = Änderung zum DEFVAL-Wert
writeiic(mcp, Mcp_Reg_INTCONB, inputMaskB); // Interrupt Vergleich einstellen, 0 = Änderung zum Vorgänger, 1 = Änderung zum DEFVAL-Wert

// readiicbyte(mcp, Mcp_Reg_INTCAPA); // Interrupts lesen und dadurch löschen
// readiicbyte(mcp, Mcp_Reg_INTCAPB); // Interrupts lesen und dadurch löschen
inputStateA = readiicbyte(mcp, Mcp_Reg_INTCAPA);
inputStateB = readiicbyte(mcp, Mcp_Reg_INTCAPB);
inputStateA = readiicbyte(mcp, Mcp_Reg_GPIOA);
inputStateB = readiicbyte(mcp, Mcp_Reg_GPIOB);
inputStateA = readiicbyte(mcp, Mcp_Reg_OLLATA);
inputStateB = readiicbyte(mcp, Mcp_Reg_OLLATB);

Serial.println("Init Fertig");
isInInit = false;
}

Das ist der aktuelle Stand, der Timer ist nur zum Pollen da, soll aber eigentlich so nicht sein.
Das interrupt problem besteht weiterhin.

WL
06.03.2015, 09:34
@PICture, Siro: Das verstehe ich nicht.

...........................

Das interrupt problem besteht weiterhin.


isInInit = false; >
Ich verstehe auch kein C, aber werden Flags nicht durch schreiben einer "1" gelöscht?