Muss ich den SPI-Bus für die RFID-Karte selber steuern? (Modifiziert)

Ich betreibe einen Uno mit Ethernet-Card und integriertem SD-shield. Zusätzlich habe ich noch einen RFID-Leser der ebenfalls über SPI gesteuert wird.

Jetzt habe ich irgendwelche Probleme, die ich nicht in den Griff bekomme. Deshalb meine Frage: Muss ich, wenn ich Befehle für das Ethernet-shield absetze, die SS(Chip-Select) auf HIGH und anschließend wieder auf LOW setzen?

Wer kann mir die Frage beantworten?

Eberhard

Es ist eben genau andersherum.
Mit dem SlaveSelect auf LOW aktivierst du deinen SPI Partner also mit HIGH (5V) ignoriert dein Slave die Daten auf dem Bus. Wenn du den SlaveSelect auf LOW (0V) setzt ist dein Partner aktiv und “hört” auf die Daten auf dem SPI.
Wie immer ein hilfreicher Artikler auf Wiki zum SPI

Um Deine Frage zu beantworten: die Ethernet-Library setzt den SS (Slave Select) selbst über setSS() bzw. resetSS() (zu finden in utility/w5100.h). Wie volvodani richtig ausführte, ist SS LOW-active, d.h. der Chip wird aktiviert, wenn das Signal nach GND gezogen wird.

Häufig macht das Ethernet-Shield Probleme, wenn der SS (4) des SD-Slots nicht auf HIGH gesetzt wird. Füge mal

pinMode(4, OUTPUT);
digitalWrite(4, HIGH);

in Deine setup()-Routine ein, das hilft häufig.

Ansonsten: Zeige uns Deinen Code, vielleicht finden wir darin ein Problem.

Han’ mal den wichtigen Teil beigefügt. Die zwei Zeilen für das CS der SD-Karte habe ich eingefügt. Die Subs des dem RFID-shield mitgelieferten sketch habe ich weg gelassen.

Funktionsweise:

setup(): nix besonderes
loop(): Bereitstellen der RFID-Kartennummer und Übergabe an
playPlaylist(): aufrufen der Playliste im Logitech Media Center die aus der Kartennummer und Extension besteht.

#include <SPI.h>
#include <Ethernet.h>
#define	uchar	unsigned char
#define	uint	unsigned int

// Maximum length of an array
#define MAX_LEN 16

/////////////////////////////////////////////////////////////////////
//set the pin
/////////////////////////////////////////////////////////////////////
const int chipSelectPin = 9;
const int chipSelectEth = 10;
const int NRSTPD = 5;

// 4-byte card serial number, 5 byte checksum byte
uchar serNum[5];

uchar  writeData[16]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100};  //initialize the 100 yuan
uchar  moneyConsume = 18 ;  // consumption of 18 yuan
uchar  moneyAdd = 10 ;  // recharge 10 yuan
// Sector A password, 16 sectors, each sector password 6Byte
 uchar sectorKeyA[16][16] = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                             {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                             //{0x19, 0x84, 0x07, 0x15, 0x76, 0x14},
                             {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                            };
 uchar sectorNewKeyA[16][16] = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                                {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xff,0x07,0x80,0x69, 0x19,0x84,0x07,0x15,0x76,0x14},
                                 //you can set another ket , such as  " 0x19, 0x84, 0x07, 0x15, 0x76, 0x14 "
                                 //{0x19, 0x84, 0x07, 0x15, 0x76, 0x14, 0xff,0x07,0x80,0x69, 0x19,0x84,0x07,0x15,0x76,0x14},
                                 // but when loop, please set the  sectorKeyA, the same key, so that RFID module can read the card
                                {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xff,0x07,0x80,0x69, 0x19,0x33,0x07,0x15,0x34,0x14},
                               };
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
byte ip[]={192,168,2,177};
byte server[] = {192, 168, 2, 14 };
String card;
String cardNew;
EthernetClient client;


void setup() {                
   Serial.begin(9600);   // RFID reader SOUT pin connected to Serial RX pin at 2400bps 
   Ethernet.begin(mac, ip);
   SPI.begin();
   
  pinMode(chipSelectPin,OUTPUT);             // Set digital pin 10 as OUTPUT to connect it to the RFID /ENABLE pin 
  //pinMode(chipSelectEth,OUTPUT);
  digitalWrite(chipSelectPin, LOW);        // Activate the RFID reader
  //digitalWrite(chipSelectEth,HIGH);
  pinMode(NRSTPD,OUTPUT);                    // Set digital pin 10 , Not Reset and Power-down
  digitalWrite(NRSTPD, HIGH);
  pinMode(4, OUTPUT);
digitalWrite(4, HIGH);

  MFRC522_Init();  
}

void loop()
{
  	uchar i,tmp;
	uchar status;
        uchar str[MAX_LEN];
        uchar RC_size;
        uchar blockAddr;	// select the operating block address 0 to 63

        
  		// Look for the card, return the card type
		status = MFRC522_Request(PICC_REQIDL, str);	
		if (status == MI_OK)
		{}


		// Anti-collision, return the card serial number 4-byte
		status = MFRC522_Anticoll(str);
		memcpy(serNum, str, 16);
                card = " ";
		if (status == MI_OK)
		{
                  for (i=0;i<5;i++)
                  {
                    card += serNum[i];
                    if (i<4){card += "-";}
                  }
                
                if (cardNew!= card)
                {
                  Serial.println(card);
                  Serial.println(cardNew);
                  digitalWrite(chipSelectPin,HIGH);
                  playPlaylist(card);
                  digitalWrite(chipSelectPin,LOW);
                  Serial.println("Back again");
                }
                 cardNew = card;
                

		// Election card, return the card capacity
		RC_size = MFRC522_SelectTag(serNum);
		if (RC_size != 0)
		{}
                
                //Serial.println(" ");
		MFRC522_Halt();			// command card into hibernation            
          
}
}

/*
 * Function: playPlaylist
 * Description: The Playlist is sent to the Logitech Media center
 * Input parameters: Cardnumber of RFID-Card
 * Return value:
 */
void playPlaylist(String playlist)
{
  client.connect(server,9002);
  Serial.println("connecting..."); 
  if (client.connected()) {
    Serial.println("connected");
    Serial.println(client.connected() + playlist);
    //client.println("GET /status?p0=playlist&p1=play&p2=" + playlist + "&player=e3:f8:d4:d8:ae:ce HTTP/1.1");
    client.println("GET /status?p0=pause HTTP/1.1");
    client.println();
  } 
  else {
    Serial.println("connection failed");
  }

  while (client.available()) {
    char c = client.read();
    Serial.print(c);
  }
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();

  } 

}

Probleme wahrscheinlich in der Sub. teilweise bleibt der Uno auch nach der Rückkehr aus der sub stehen. “Back again” noch da, dann Ruhe im Busch.

Danke für die Hilfe.

Eberhard

teilweise bleibt der Uno auch nach der Rückkehr aus der sub stehen. "Back again" noch da, dann Ruhe im Busch.

Heisst "Ruhe im Busch", dass der Arduino einfriert? Oder startet er neu? Das könnte auf einen Speicher-Überlauf hindeuten.

uchar sectorKeyA[16][16];
uchar sectorNewKeyA[16][16];

Du bist Dir schon im Klaren, dass Du mit diesen zwei Deklarationen bereits einen Viertel des Speichers eines UNO belegt hast. Auch bei den print() bzw. println() Aufrufen kannst Du RAM sparen, wenn Du die alle konstanten Strings mit dem Macro F() kapselst:

Serial.println("Back again");

wird dann:

Serial.println(F("Back again"));

Damit werden die Strings nicht mehr in's RAM eingelesen, bevor sie verwendet werden, sondern werden direkt aus dem Programmspeicher (Flash) gelesen.

  digitalWrite(chipSelectPin, LOW);        // Activate the RFID reader

Du aktivierst den RFID-Reader, aber deaktivierst ihn nicht mehr. Das heisst, alles, was an den Ethernet-Chip geschickt wird, wird vom RFID-Reader auch verarbeitet und beantwortet. Somit ist ein Konflikt vorprogrammiert. Es sollte jeweils nur ein Chip-Select der SPI-Geräte aktiv (sprich: LOW) sein.

Hallo pylon,
habe mal ein wenig aufgeräumt. Das 2D-Array wird gar nicht benötigt also: Raus damit. Alle konstanten Serial.print in F() gekapselt. Das war für mich völlig neu. Na ja für einen Neuling nichts ungewähnliches.

Jetzt habe ich nach dem Kompilieren 14404 Bytes belegt. Ich habe keine Vorstellung, was mit dem Speicher passiert. Dazu später noch mal 'ne Frage.

Zum LOW-HIGH Problem:

Im setup() habe ich bewusst vor der CS-Deklaration erst Ethernet.begin() und dann CS für RFID auf LOW gesetzt. Das Ethernet-Shield wird erst wieder beim Aufruf von playPlaylist(card) angesprochen; deshalb wird der Aufruf auch eingebettet von:

                  digitalWrite(chipSelectPin,HIGH);                 // deaktivieren des RFID-Shields
                  playPlaylist(card);                                       // Aufruf void playPlaylist(String playlist)
                  digitalWrite(chipSelectPin,LOW);                 // aktivieren des RFID-Shields

Habe ich denn noch etwas übersehen?

Heisst "Ruhe im Busch", dass der Arduino einfriert? Oder startet er neu? Das könnte auf einen Speicher-Überlauf hindeuten.

Ich meine sowohl das Eine als auch das Andere mal bemerkt zu haben. Bin mir aber unsicher. Deutet Beides auf Speicer-Überlauf hin? Der Server (LMC) sendet ja bei jedem Aufruf etwas zurück. Bleibt das im Speicher oder wird das nur durchgeschoben? Wenn ich diesen Speicher nicht auslese, bekomme ich dann Probleme?

Deshalb gilt mein Hauptaugenmerk der Funktion void playPlaylist(String playlist). Wenn irgenwo was schief ist vermute ich es dort. Wie gesagt: vermute.

Gruß
Eberhard

Jetzt habe ich nach dem Kompilieren 14404 Bytes belegt. Ich habe keine Vorstellung, was mit dem Speicher passiert. Dazu später noch mal 'ne Frage.

Das ist die Grösse im Flash (Programmspeicher). Ein Arduino hat 3 verschiedene Speicherbereiche. Der Flash-Speicher (32kB beim UNO) wird für den Programmcode verwendet, ist nicht-flüchtig, kann nur direkt nach dem Booten geschrieben werden und ist danach read-only. Der Hauptspeicher (RAM) wird für Variablen und andere Daten während des Programm-Laufs verwendet. Er ist flüchtig, sprich, nach einem Wegfall der Stromversorgung ist der Inhalt unwiederbringlich weg. RAM (2kB beim UNO) kann immer geschrieben und gelesen werden. Als dritter Typ existiert noch EEPROM (1kB beim UNO), auch nicht-flüchtig, aber immer schreib- und lesbar. Allerdings sollten die Schreibzugriffe so selten wie möglich stattfinden, denn nach ca. 100'000 Schreibvorgängen ist eine Zelle hin und kann nicht wiederbelebt werden.

Habe ich denn noch etwas übersehen?

Nicht alle SPI-Geräte kommen damit klar, wenn der SS LOW ist, obwohl nicht getaktet wird (auf SCLK), also Daten verschoben werden. Das Datenblatt sollte dazu eigentlich Auskunft geben. Aber grundsätzlich könnte es so gehen, sorry, habe den Teil übersehen.

Wenn ich diesen Speicher nicht auslese, bekomme ich dann Probleme?

Zum einen scheinst Du das ja zu machen, zum anderen sollte das keine Probleme verursachen, wenn Du client.stop() aufrufst.

String card;
String cardNew;

Verwende die String-Klasse nicht! Sie geht zum einen verschwenderisch mit Speicher um, fragmentiert diesen (was auf einem PC mit OS und Memory Management Unit nicht so schlimm ist, weil die das wieder ausgleichen können, auf einem Microcontroller kann das Absturz bedeuten) und hat in der aktuellen Version zudem einen Fehler, der Memory-Leaks, also verlorengehenden Speicher verursacht. Verwende immer character Arrays, die Du kontrolliert deklarierst und dann am Context-Ende vom Compiler wieder freigegeben werden.

Hallo pylon.

Verwende immer character Arrays, die Du kontrolliert deklarierst und dann am Context-Ende vom Compiler wieder freigegeben werden.

Wenn die Seriennummer der RFID-Karte 5 Byte lang ist und zusätzlich 4 Trennstriche dazukommen würden m.E.

string card[9];
String cardNew[9]

jetzt habe ich das Problem, dass ich nicht mehr so komfortabel auf die Serien nummer zugreifen kann. Da muss ich noch mal nachdenken.

Gruß
Eberhard

string card[9];
String cardNew[9]

Eben gerade nicht! Sondern so:

char code[10];
char cardNew[10];

Allerdings kannst Du dir die Trennstriche sparen, wenn es sowieso 5 Bytes sind. Und wieso kannst Du nicht mehr darauf zugreifen? Wo liegt das Problem?

Bei mir sind die IDs länger als 5 Bytes. Zudem kommen die als Hex-Codes daher, Bytes jeweils durch ein Leerzeichen getrennt. Wenn Du das in Bytes kodierst, ist es kein ASCII mehr, sondern Binärdaten, dann würde ich die Trennstriche sowieso weglassen, das würde nur verwirren.

Hallo pylon,

Ziel des Ganzen ist es ein Zeichenkette in der Form:
"GET /status?p0=playlist&p1=play&p2=" + playlist + "&player=00:15:af:b8:ac:25 HTTP/1.1"
an einen Medienserver zu übergeben. Dabei entspricht die Variable playlist der Seriennummer der RFID-Card.

Wenn ich die Seriennimmer in einem Array speichere bekomme ich das wohl schon hin, würde das array an die Sub playPLaylist() übergeben.

Lasse ich dann noch die Trennstriche weg, kann ich gleich mit der Seriennummer uchar serNum[5] weiterarbeiten. Diese mit playplaylist(serNum) an die Sub zu übergeben und dort mit void playPLaylist(serNum) weiterzuverarbeiten führt zur Fehlermeldung: variable or field 'playPlaylist' declared void.

Und dann später die serNum in die Zeichenkette einzuarbeiten führt wegen der unpassenden Typen zu Fehlern. (und bei mir zu Eberhard overflow :))

Vielleicht wenn Du mir da noch mal einen Tipp gibst. Danke für Deine Mühe, mir hier aufs Pferd zu helfen.

Ich habe mal viel mit Basic gearbeitet und liebe deshalb den Typ string... das ist aber lange her......

Eberhard

Wichtig ist in erster Linie, die Speicherverwaltung nicht zu überfordern und somit möglichst selten neuen Speicher anzufordern.

Die Zeichenkette kann relativ einfach konstruiert werden:

char strbuf[85];

strnprintf(strbuf, 85, "GET /status?p0=playlist&p1=play&p2=%s&player=00:15:af:b8:ac:25 HTTP/1.1", playlist);

Die Variable playlist muss auch ein String sein (also 0-terminiert) und da ich von IDs der RFID-Karten ausgehe, die die volle Bandbreite an Byte-Werten (0-255) ausnützen, solltest Du sie in Hex kodieren, um sie an den Webserver zu senden.

Hast Du Beispiele, wie die IDs aussehen?

Ich habe hier Mifare-Karten S50. Die hat ein integriertes 81292 Bit EEprom. Der ist in 16 Sektoren mit jeweils 4 Blöcken a 16 Byte. Der Block "0" im Sektor "0" ist der Manufacturer Code. Da drin steht die Seriennummer. Sie besteht aus den Bytes 0-3. Im Byte 4 steht ein Check-Byte und der Rest bis Byte 15 ist zwar auslesbar aber nicht erklärt.

Beispiel: 46,34,173,209,112 oder 14,183,158,209,246 . Also mit dem Zahlenraum 0-255.

Da die Playlisten auf dem Server so heißen wie die Seriennummer der Karte, ist das mir der Umwandlung nach Hex nicht so sinnvoll. Oder ich muss die Playlisten umbenennen. Da ich im Entwicklungsstadium bin, habe ich bis jetzt nur 10 PL nach den SerNum umbenannt.

Mit welchen Karten arbeitest Du?

Ich werde ab morgen eine Woche abwesend sein. Vielleicht kann ich zwischendurch mal über das Projekt nachdenken.

Gruß
Eberhard

Deine Playlist für den ersten Fall heisst also '."¬Ñp' (kodiert in ISO-8859-1)? Das ist ein reichlich komischer Name :).

Ich denke, Du hast sie wahrscheinlich einfach mit der Dezimalschreibweise und irgendeinem Trennzeichen zu einem Dateinamen zusammengesetzt. All das kannst Du auf dem Server wieder machen, wenn Du sie als Hex übermittelt hast. Hex hat gegenüber der Dezimalschreibweise den Vorteil, dass ein Byte immer genau zwei Zeichen braucht und somit einfacher in der Übertragung ist.

Mit welchen Karten arbeitest Du?

Ich habe Mifare One-Karten, brauche sie aber zur Zeit nur mit den IDs, schreibe also momentan nicht drauf.

Deine Playlist für den ersten Fall heisst also '."¬Ñp' (kodiert in ISO-8859-1)? Das ist ein reichlich komischer Name

So sprechen wir hier in MG nun mal. Nein,fast richtig. :grin: Sie heißt: "46-34-173-209-112.m3u"

All das kannst Du auf dem Server wieder machen, wenn Du sie als Hex übermittelt hast.

Das kann ich nicht auf dem Server machen, weil dazu mir die Kenntnisse fehlen. Der Logitech-Media-Server läuft auf einer Synology 409+ unter Linux und das ist nix mehr für mich. Ich kann den String wenn er zum Server unterwegs ist nicht mehr nacharbeiten. Wenn da hex ankommt, der String also

"GET /status?p0=playlist&p1=play&p2=2E-22-AD-D1-70&player=00:15:af:b8:ac:25 HTTP/1.1"

lautet, könnte ich noch damit leben.

Ich werde also nach meiner Rückkehr mich mit den Speicherthemen beschäftigen. Da die zwei Sketche für sich tadellos laufen und die Probleme erst nach dem Mergen auftreten, wird es wohl am Speicher liegen (Hoffnungsvolles seufzen).

Wo finde ich eigentlich die Referenz zu strnprintf()?

Hat Deine Anwendung was mit Musik zu tun?

Gruß Eberhard

Der Code für Deine Anwendung könnte dann so lauten:

char strbuf[92];

strnprintf(strbuf, 92, "GET /status?p0=playlist&p1=play&p2=%d-%d-%d-%d-%d&player=00:15:af:b8:ac:25 HTTP/1.1", serNum[0], serNum[1], serNum[2], serNum[3], serNum[4]);

Wo finde ich eigentlich die Referenz zu strnprintf()?

Hmmmh, bei mir ist es ein "man strnprintf" auf der Kommandozeile :). Ich denke, Google findet viele Resultate, wenn Du danach suchst. Ist eigentlich eine Standard-C-Funktion, die AVR-Lib-C unterstützt einfach nicht ganz alle Optionen.

Hat Deine Anwendung was mit Musik zu tun?

Nein, überhaupt nicht, ich identifiziere Tiere damit.

@pylon
Du identifizierst Tier damit?
Was für einen Lesegerät verwendest Du? Nach meinen Informationen arbeiten die Tierchips mit 134.1kHz anstatt der 125kHz.
Habe schon mal nach einem Bausatz für die Tierchips gesucht und nix gefunden. Wie hast Du das gelöst?
Gruss MX738

Nicht so kompliziert, im Moment verwende ich 13.56MHz tags, die am Halsband angebracht sind, nur Versuchsbetrieb.

Ich habe irgendwo gelesen, dass mit den 125kHz-Empfängern auch die 134kHz-Chips ausgelesen werden können, aber bin noch nicht dazu gekommen, das mal auszuprobieren.

Ich habe zwar noch viele Fragen zur Qoute von pylon, bin aber der Meinung, dass wir uns von dem ursprünglichen Thema zu weit entfernt haben. Für Diejenigen, die sich wegen des SPI-Bus den Thread ansehen, hier eine Zusammenfassung:

Die Konfuguration: Uno, Ethernetshield und RFID-Shield mit Philips/NXP MFRC522 RFID Chip

In dem bereits angehängten Sketch wird:

  1. Der SPI-Bus des Ethernet-Shields über die Befehle der Library gesteuert.
  2. Der SPI-Bus des nicht benutzten SD-Slots auf HIGH gesetzt werden.
  3. Der SPI-Bus des RFID-Cardreaders durch Befehle im Sketch gesteuert.

Damit ist die ursprüngliche Frage zur Steuerung zwar beantwortet, die Probleme sind aber nicht beseitigt. Ich schließe mich der Meinung von pylon an und glaube auch inzwischen, dass es sich hier um ein Speicherproblem handelt.

ich würde diesen Thread deshalb gerne schließen und einen neuen mit dem Thema “Speicherprobleme bei Stringoperationen in Zusammenhang mit dem Ethernetshield” öffnen.

Dir, pylon, danke bis hierhin für die Geduld mit mir. …aber es geht weiter. :slight_smile:

Eberhard

Zum neuen Thread Speicherprobleme bei Stringoperationen in Zusammenhang mit dem Ethernetshield geht’s hier lang:
http://arduino.cc/forum/index.php/topic,119470.0.html