EthernetShield2 + CAN-BUS an SPI

Hallo,
ich habe vor einigen Tagen ein neues Projekt gestartet.
Ziel des Projekts ist, mit einem Arduino-Mega und dem Ethernet-Shield-2 einen kleinen Webserver aufzubauen.
Dieser soll CAN-Bus-Daten einlesen, die dann auf einer Internetseite lesbar sein sollen.
Beispiel: Temperaturen von verschiedenen Räumen
Um Daten vom CAN-BUS zu lesen wird ein kleines Modul mit dem Baustein MPC2515 verwendet.
Der Baustein wird wie das Ethernet-Shield-2 mit der SPI-Schnittstelle bedient.
Es ist auch geplant die Interrupt-Leitung des MPC2515 zu nutzen, um neu empfangenen CAN-Botschaften zu erkennen.
Der Hardwareaufbau sollte soweit in Ordnung sein.

Als Basis für meine Software habe ich das Projekt verwendet:

Ohne CAN-Schnittstelle läuft diese Projekt auf dem Arduino-Mega erfolgreich.

Danach habe ich eine neues Sketch erzeugt und die CAN-Bus-Schnittstelle erfolgreich getestet.
Bei diesem Test war das Ethernet-Shield-2 auf dem Mega gesteckt aber nicht über SW angesprochen.

Probleme habe ich nun bei der Integration beider Projekte (Web-Server und CAN-BUS).

Mein Ansatz für das Auslesen der CAN-Daten:
Bei einem Botschaftsempfang (CAN-Bus) soll der Interrupt-Ausgang des MPC2512 ein externen Interrupt am Arduino auslösen um die Daten abzuholen.

Leider funktioniert dieses nicht wie gewünscht. Oft werden die Daten vom CAN nicht gelesen und der Interrupt-Pegel bleibt auf GND.
Der interne PullUp des Mega ist über SW aktiv geschaltet.
Auf der CAN-Leitung wird aktuell nur eine Botschaft (ID 0x400h) im 200ms Raster gesendet und die Masken-Register sind richtig gesetzt.
Der Interrupt-Eingang des Mega wird somit nicht zu extrem belastet.

Ich vermute, dass die Problem(e) mit der SPI-Schnittstelle zusammenhängen.

Meine Fragen an euch / Was meint ihr dazu?:

  • Ist es überhaupt möglich in dem beschriebenen Projekt mit einem externen Interrupt zu arbeiten?
  • Wie kann dieser am besten in die SW- integriert werden?
  • An welcher Stelle des Programms sollte das Auslesen der Daten erfolgen?
  • Was geschieht, wenn bei SPI-Kommunikation zwischen Mega und Ethernet-Shield-2 ein externer Interrupt ausgelöst wird? Wird die SPI-Kommunikation sofort unterbrochen oder wird die gestartete Kommunikation noch „kontrolliert“ beendet?

Würde mich über Antworten sehr freuen.

Viele Grüße Klaus

MEGA_CAN_TEST_new.ino (11.7 KB)

Hallo,

also vorweg ich habe weder CAN- noch Ethernetshield, kenne aber CAN vom Teensy.

Was meint ihr dazu?

Also erstens würde ich schon erwarten, dass der MCP2515, wenn er so konfiguriert ist, bei jeder Message einen Interrupt liefert. Wenn dem nicht so ist, kann eigentlich nicht alles in Ordnung sein, so wie du ja schreibst.

Man wird wohl bei diesem Aufbau nicht um Interrupts herumkommen, da meines Wissens nach der MCP2515 nicht viele Botschaften speichern kann (2 ?).

Es könnte allerdings sein, dass es dem Ethernet Shield nicht gefällt, wenn eine laufende Kommunikation über SPI unterbrochen wird.

Arbeiten denn beide Libraries für die Shields mit den gleichen SPI-Einstellungen ? Nur wenige Libraries, die SPI verwenden, scheinen mit SPI.beginTransaction() & Co zu arbeiten, ggf. muss man das umbauen.

Du verwendest 3 SPI Dinger.
Also auch 3 CS Leitungen.

Ich würde es als notwendig erachten, dass als aller erstes alle 3 CS auf High gezogen werden.
Gerne auch per externem Pullup.

Hallo,
mit den CS-Leitungen bin ich mir relativ sicher, dass sie richtig bedient werden.

Meine Hauptfrage zielt in die Richtung, an welcher Stelle der SW bzw. mit welcher Methode hole ich die CAN-Daten ab?

Ja, den Interrupt benötige ich, um alle CAN-Daten lesen zu können.

Gruß

Keili:
mit welcher Methode hole ich die CAN-Daten ab?

Das hängt von deiner Library ab. Es gibt verschiedene Shields mit dem MCP2515. Da gibts meistens eine passende Library dazu. Wenn nur dieses IC auf dem Shield ist, sind die, abgesehen vom CS, aber wahrscheinlich austauschbar.

Du hast also einen Interrupt Handler für das Signal vom MCP und liest da die Daten aus.

Ich zeig einfach mal Code vom Teensy, so ähnlich wird es mit deiner Lib auch aussehen.

Entweder klassischer Arduino Style

  CAN_message_t inMsg;
  while (Can0.available()) 
  {
    Can0.read(inMsg);
    Serial.print("CAN bus 0: "); hexDump(8, inMsg.buf);
}

oder mit fertigem Interrupthandling aus der Library

class ExampleClass : public CANListener 
{
public:
   void printFrame(CAN_message_t &frame, int mailbox);
   void gotFrame(CAN_message_t &frame, int mailbox); //overrides the parent version so we can actually do something
};

// ... gekürzt ...

ExampleClass exampleClass;

// ...


Can0.attachObj(&exampleClass);
exampleClass.attachGeneralHandler();

Ich verwende dieses CAN-Modus:

Als Lib verwende ich diese:

Grund für diese Lib. : Sie kommt auch mit einem 8Mhz Quarz klar.

Soweit ich das durchblicke, scheint es da kein eingebautes Interrupt Handling zu geben. In dem Beispiel wo ich reingeschaut habe sehe ich das da

#define CAN0_INT 2 // Set INT to pin 2

// ...

if(!digitalRead(CAN0_INT))                         // If CAN0_INT pin is low, read receive buffer
{
   CAN0.readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)

Er setzt den Pin low, wenn er was hat. Muss man dann so oft lesen, wie der Pin gesetzt bleibt, oder woran sieht man wieviele Messages er hat ?

Komische Library, da bleibe ich lieber beim Teensy.

Scheint in der Tat so zu sein: Wenn der Pin low ist, muss man lesen. Wahrscheinlich wird dieses Verfahren bei einer bestimmten Anzahl von Messages pro Sekunde an seine Grenzen stossen, schliesslich geht das Lesen dann auch noch über SPI vom Shield.

Liest man nicht oft genug, gehen Messages verloren, das ist bei den Controllern mit integriertem CAN aber auch so.

Neben der Auslastung des SPI-Busses durch die CAN Daten, muss man dann noch schauen, wie man die Ethernet Anbindung gleichzeitig abwickelt, ohne den CAN Empfang zu unterbrechen ...

Hallo,
also ich verstehe das so.
Der MPC2515 löst einen Interrupt aus, setzt dabei den INT-Ausgang auf Masse (am MPC2515).

Diese Leitung verwende ich, um einen externen Interrupt am Mega auszulösen.
Geschieht dies, wird die Interrupt-Funktion auch aufgerufen und ausgeführt.

void MCP2515_ISR()
{
     Flag_Recv = 1;
     // Serial.println(F("Int-Fkt. active"));    /*  */

     // FRAGE-1: Hier Daten vom MCP2515 abholen ???

}

Die Frage ist aber, wo lese ich die CAN-Daten aus?
In der Int-Service-Routine?

Gruß

Ich bin mir nicht sicher.

In der ISR müsste auf jeden Fall eine while Schleife stehen, die ggf. mehrfach liest. Weil der MCP den Pin low lässt, wenn inzwischen eine weitere Message reingekommen ist.

Auch kann ich nicht sagen, ob der Arduino wieder einen neuen Interrupt auslöst, wenn vor Verlassen der ISR wieder eine Message eintrifft und der Pin während des Interrupts nach dem Lesen wieder low geht.
Das wissen die AVR Experten hier besser, falls keiner antwortet, frag noch mal separat nur zu dem Interrupt, ohne CAN zu erwähnen.

Hallo,
noch eine Anmerkung.
Der Interrupt wird alles 200ms beim Empfang der ID 0x400h.
Mehr Botschaften gibt es nicht auf dem Bus.

Ich denke, wenn sicher ist, dass man immer öfter als 200 ms durch die loop kommt, dann würde ich da direkt mit digitalRead arbeiten und den Interrupt weglassen.

Hallo,
mit der while-Schleife in der Interrupt-Routine werde ich versuchen.
Das ist nach meinen Verständnis ein sehr guter Ansatz.

Nochmals um sicher zu sein was du meinst.
Die while-Schleife solange durchlauf und Daten vom MPC2515 auslesen, bis die Interrupt-Leitung wieder High angenommen hat.

Vielen Dank für deine Unterstützung.

Gruß Klaus

Keili:
Nochmals um sicher zu sein was du meinst.
Die while-Schleife solange durchlauf und Daten vom MPC2515 auslesen, bis die Interrupt-Leitung wieder High angenommen hat.

Ja, effektiv entspricht das ja dem receive Beispiel aus der Lib

void loop()
{
  if(!digitalRead(CAN0_INT))                         // If CAN0_INT pin is low, read receive buffer
  {
    CAN0.readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)

Hallo,
habe mir gestern das Datenblatt des MPC2515 nochmals genau angeschaut.
Es gibt 2 RX-Buffer die beide den Interrupt bedienen.
Somit hast du (ihr) völlig recht, das Auslesen des MPC2515 muss mehrfach hintereinander erfolgen.
Wegen Zeitmangel konnte ich gestern am Di. keine Tests durchführen.

Hoffentlich komme ich heute dazu.

Gruß Klaus