Input unverzerrt zum Output

Habe die Ehre,

Ich versuche neben unseren alten Magnetkartenleser (Magtek ttl) einen NFC-Reader zu installieren. Da ich nicht alle alten Karten austauschen kann müssen die zwei Dinger parallel funktionieren. Der Kartenleser dient als Input für eine Anlagensteuerung = Black-Box.

Meine Idee war es, wenn am MagTek ein Signal anliegt, dann gebe ich das 1 zu 1 weiter. Wenn ein NFC-Transponder anliegt, dann simuliere ich das TTL-Signal des Magtek. Das Signal des Magnetkartenlesers konnte ich mit dem Arduino auslesen und die Bits entsprechen dem was auf der Karte steht.

ABER:
Die Anlagensteuerung akzeptiert weder das künstliche-NFC-TTL noch das Signal, das ich "einfach" weiterleite. Es glaubt mir, dass eine Karte im Slot ist, aber nichts weiter.
Einfacher scheint mir das Weiterleiten, also versuch ich das mal zu fixen: Hat einer von Euch eine Idee wo da das Problem liegen könnte? Lt. Beschreibung gibt der MagTek max. 3750 bit/s her (wenn man die Karte ziemlich flott durchzieht). Das wären min. 250µs pro bit. Das sollte sich doch locker ausgehen, oder doch ein Performance-Problem?

int signal[2] = {1,0};
int strobe[2] = {1,0};
int backend[2] = {1,0};

// The loop function is called in an endless loop
void loop() {
        signal[0] = digitalRead(CR_SIGNAL);
        strobe[0] = digitalRead(CR_STROBE);
        backend[0]= digitalRead(CR_BACKE);
/*        Serial.print(signal);
        Serial.print("\t");
        Serial.print(strobe);
        Serial.print("\t");
        Serial.print(backend);
        Serial.println(""); */
        if(signal[0] != signal[1]) {
          digitalWrite(OUT_SIGNAL, signal[0]);
          Serial.print(".");
        }
        if(strobe[0] != strobe[1]) {
          digitalWrite(OUT_STROBE, strobe[0]);
          Serial.print(".");
        }
        if(backend[0] != backend[1]) {
  	  digitalWrite(OUT_BACKE, backend[0]);
          Serial.print(".");
        }
        
        signal[1] = signal[0];
        strobe[1] = strobe[0];
        backend[1] = backend[0];
}

Bester Gruß
Edi

Wenn Du das mit digitalRead/Write machst, dann hast Du ein Performance Problem. Die Antwort lautet direkte Portmanipulation + ausschalten der Interrupts während des Lesevorgangs.

Und falls Du dabei noch Serial.Write verwendest (wie in Deinem Code), dann bist Du völlig chancenlos. Sobald der Ausgabepuffer voll ist geht die Performance senkrecht durch die Bodenplatte bis unterhalb des Kellers nach unten.

herzlichen Dank!

Wenn ich den Code auf Performance trimme sollte das aber machbar sein, oder bin ich da mit der Arduino grundsätzlich zu langsam aufgestellt?

wird mir das Seeed NFC2.0 shield noch einen Strich durch die Rechnung machen?

Wenn das richtig programmiert ist, dann ist das sehr locker drin. Ein Arduino ist zwar kein DSP, aber für sowas sollte das mehr als locker reichen.

Bin gespannt ...
Noch Verbesserungsideen?

// Do not remove the include below

#include "PN532.h"
#include "SPI.h"
#include <digitalWriteFast.h>


/*
 * arduino block
 * containing pin definitions
 */


#define CR_STROBE 7
#define CR_SIGNAL 5
#define CR_CARDP  6
#define CR_BACKE  4

#define OUT_STROBE 11
#define OUT_SIGNAL 9
#define OUT_BACKE  8

#define OUT_LED 13

void setup() {
        pinMode(CR_SIGNAL, INPUT);    
        pinMode(CR_CARDP, INPUT);    
        pinMode(CR_BACKE, INPUT);
        pinMode(CR_STROBE, INPUT);    
        
        pinMode(OUT_SIGNAL, OUTPUT);
        pinMode(OUT_STROBE, OUTPUT);
        pinMode(OUT_BACKE, OUTPUT);
        pinMode(OUT_LED, OUTPUT);

        digitalWrite(OUT_SIGNAL, HIGH);
        digitalWrite(OUT_STROBE, HIGH);
        digitalWrite(OUT_BACKE, HIGH);
        
         digitalWrite(OUT_LED, HIGH);  //just to see that its on (the green light on the Arduino is covered by the shield
}


int signal[2] = {1,0};
int strobe[2] = {1,0};
int backend[2] = {1,0};

// The loop function is called in an endless loop
void loop() {
  while(1) {
        signal[0] = digitalReadFast(CR_SIGNAL);
        strobe[0] = digitalReadFast(CR_STROBE);
        backend[0]= digitalReadFast(CR_BACKE);

        if(signal[0] != signal[1]) {
          digitalWriteFast(OUT_SIGNAL, signal[0]);
        }
        if(strobe[0] != strobe[1]) {
          digitalWriteFast(OUT_STROBE, strobe[0]);
        }
        if(backend[0] != backend[1]) {
  	  digitalWriteFast(OUT_BACKE, backend[0]);
        }
        
        signal[1] = signal[0];
        strobe[1] = strobe[0];
        backend[1] = backend[0];
  } 
}

eris:
Bin gespannt ...
Noch Verbesserungsideen?

Was für ein Signal über "BACKE" übertragen wird, ist mir unklar.

Aber soweit es es "Signal" und "Strobe" betrifft sieht es ganz klar nach einer falschen Programmlogik aus.

Aus dem Datenblatt http://www.magtek.com/docs/99875042.pdf
(keine Ahnung ob das Dein Reader ist, aber wenigstens dürfte es da ähnlich sein):
The Strobe signal indicates when Data is valid. It is recommended that Data be loaded by the
user with the leading edge (negative) of the Strobe.

Das heißt, in Bezug auf Signal und Strobe kommt es ganz besonders darauf an, auf das Strobe nur dann zu setzen, wenn das Data-Signal gültig ist. Und das Data-Signal ist immer dann gültig, wenn das Strobe-Signal wechselt (leading edge (negative)).

Eventuell reicht es aus, in Deinem Code nur die zwei Zeilen zu vertauschen, in denen Strobe und Signal gelesen werden:
strobe[0] = digitalReadFast(CR_STROBE);
signal[0] = digitalReadFast(CR_SIGNAL);

Also erst Strobe und danach Signal lesen und beim Setzen (so wie es ist) erst Signal setzen und dann Strobe. So dass auf jeden Fall ein gültiges Signal weitergeleitet wird.

Eventuell auch gleich nach dieser Logik pollen und Signale setzen:

  • In der Polling Loop die Strobe-Leitung auslesen
  • Nur wenn sich der Zustand der Strobe-Leitung seit dem letzten Loop-Durchlauf geändert hat ("state change" auf Strobe):
  • ankommende Daten-Leitung auslesen
  • abgehende Daten-Leitung setzen
  • abgehende Strobe-Leitung setzen

Üblicherweise würdest Du auf den Pegelwechsel der Strobe-Leitung wohl auch besser in einer Interrupt-Behandlungsroutine reagieren als den Leitungsstatus nur zu pollen.

Für das langsame Present-Signal müßte es so funktionieren, wie Du es jetzt auch machst.
Zum Backe-Signal kann ich gar nichts sagen, da wäre es vielleicht hilfreich zu wissen, was das ist und nach welcher Logik es gesetzt wird.

Klar geht das noch besser. Wozu das Signal dazwischen auswerten wenn man es auch einfach durchkopieren kann?

while(1) {
    digitalWriteFast(OUT_SIGNAL, digitalReadFast(CR_SIGNAL));
    digitalWriteFast(OUT_STROBE,digitalReadFast(CR_STROBE));
    digitalWriteFast(OUT_BACKE, digitalReadFast(CR_BACKE));
}

Davon abgesehen würde ich die #defines durch const Deklarationen ersetzen. Das ist sauberer. Und um den Jitter zu reduzieren würde ich mit cli() alle Interrupts sperren.