CAN FD mit MCP2518, Arduino zu langsam?

Hi zusammen,

Ich brauche Mal euren Rat.
Ich bin dabei einen kleinen CANFD Logger zu bauen. Dazu nutze ich einen MCP2518fd CAN Controller welcher per SPI am Arduino hängt.

Im Moment nutze ich diese Longan Lib mit entsprechendem Programm. Womit die Kommunikation auch wunderbar klappt. LonganLIB

Nun habe ich aber das Problem das einige Frames von meinem Arduino nicht gefangen werden.
Im Bild kann man gut erkennen das frames mit einem extrem kurzen Abstand ( <1ms ) es nicht in die logdatei schaffen.

Zeilenumbrüche in Logdatei zur Übersicht manuell eingefügt.

Das bsp. aus der Lib nutzt eine einfache wiederholende abfrage des CAN Controllers und holt sich dann die daten daraus. Eine andere Variante per Interrupt gibt es auch, jeodoch hängt sich dann ab einem bestimmten Punkt alles auf. Eventuell weil mehr Interrupts kommen als verarbeite werden können?

Somit fehlen mir in bestimmten Situationen also frames.

Ich bin mir sicher das der CAN Controller die Daten hat nur ich es aber nicht schaffe sie schnell genug abzurufen.

Habt ihr eventuell Vorschläge wie ich das ganze lösen kann? Muss ich irgendwie den Speicher besser nutzen und die Daten nicht im Interrupt verarbeiten? Oder ist hier ein Arduino UNO einfach unterdimensioniert?

Wenn ich richtig recherchiert habe, beträgt der kleinste Abstand zwischen den Frames 15 Bit-Zeiten. Was bei einem 500kbit/s Bus etwa 30 Mikrosekunden entspricht.

Anbei mein Code:

/*  MCP2517/8 receive a CAN-FD frame with interrupt
    can-fd baud rate:
    CAN_125K_500K
    CAN_250K_500K
    CAN_250K_750K
    CAN_250K_1M
    CAN_250K_1M5
    CAN_250K_2M
    CAN_250K_3M
    CAN_250K_4M
    CAN_500K_1M
    CAN_500K_2M
    CAN_500K_3M
    CAN_500K_4M
    CAN_1000K_4M


    v2 - einbau SD karte über die selbe SPI schnitstelle
    v3 - nutzung Software SPI mit SDfat lib
    v4 - import RTC modul & Datumsformatierte Dateinbenamung
    v5 - zu schriebende daten aus dem buffer auch ohne Close schrieben "flush()" 
        + 5sec timer zum wegschreiben
        + einbau delta t der einzelnen frames zueinander
    v6 - ausgabe anpassung für großtest
        + wiederholte flush mit SaveDataTimerStatus jetzt vehindert
    V7 - anpassung ausgab, beim flush()
        + RTC steup bei Compilevorgang, schaltbar!
    v8 - performancetests bzgl. frames <1ms
    v9 - performanstests flush nur nach 90ms ohne frame- so sollte der FIFO des MCP frei sein
    v9_1 - cleaned for forum
    v10 - umbau auf ISR
        +auswertung des RX FIFO
        +nutzung von tab formatierung
        
         
*/

#include <Arduino.h>
#include <SPI.h>
#include "mcp2518fd_can.h"

#include <ThreeWire.h>  
#include <RtcDS1302.h>
ThreeWire myWire(7,5,8); // IO, SCLK, CE
RtcDS1302<ThreeWire> Rtc(myWire);

#include <SdFat.h>
#if SPI_DRIVER_SELECT == 2
#define SD_FAT_TYPE 1

#define MAX_DATA_SIZE 64

// pin for CAN-FD Shield
const int SPI_CS_PIN = 9;
const int CAN_INT_PIN = 2;

//anpassung für SD Karte
int count = 0 ;
bool SaveDataTimerStatus = true;
static unsigned long  Zeitscheibe_0 = 0;
unsigned long vorher_ms = 0;
// Chip select may be constant or RAM variable. (Software SPI aus SDfat LIB)
const uint8_t SD_CS_PIN = 10;
const uint8_t SOFT_MISO_PIN = 6;
const uint8_t SOFT_MOSI_PIN = 3;
const uint8_t SOFT_SCK_PIN = 4;
#if SD_FAT_TYPE == 0
SdFat sd;
File file;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
#else  // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif  // SD_FAT_TYPE

// SdFat software SPI template
SoftSpiDriver<SOFT_MISO_PIN, SOFT_MOSI_PIN, SOFT_SCK_PIN> softSpi;
// Speed argument is ignored for software SPI.
#if ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(25), &softSpi)
#else  // ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(0), &softSpi)
#endif  // ENABLE_DEDICATED_SPI


mcp2518fd CAN(SPI_CS_PIN); // Set CS pin

unsigned char flagRecv = 0;
unsigned char len = 0;
unsigned char buf[MAX_DATA_SIZE];



void setup() {

    delay(4000);            //kurze wartezeit um nach dem hochladen das Terminal verbinden zu können

    Serial.begin(115200);
    while (!Serial);


//+++++++++++++++++++++++++++  RTC  ++++++++++++++++++++++++++++++++++++++++++++++++++++
    Rtc.Begin();
    //setzen der RTC über compiler (einmal auf true gesetzt hochladen)
    if(false){
        Serial.print("compiled: ");
        Serial.print(__DATE__);
        Serial.println(__TIME__);
        RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
        //printDateTime(compiled);
        Serial.println();
        Serial.println("setze neue Zeit aus Compilevorgang");
        Rtc.SetDateTime(compiled);
    }

    RtcDateTime now = Rtc.GetDateTime();
    if (!now.IsValid()){
        // Common Causes:
        //    1) the battery on the device is low or even missing and the power line was disconnected
        Serial.println("RTC lost confidence in the DateTime!");
    }else{
        Serial.println("RTC init ok!  -  ");
    }

//+++++++++++++++++++++++++++  SD  ++++++++++++++++++++++++++++++++++++++++++++++++++++
    //timestamp als Dateiname erstellen
    String timestamp = (String(now.Hour())+"_"+String(now.Minute())+"_"+String(now.Second())+".txt");
    vorher_ms = millis();
    char newFilename[20];
    timestamp.toCharArray(newFilename, 20);

    // SD Karte initialisierung
    if (!sd.begin(SD_CONFIG)) {
        sd.initErrorHalt();
    }
    Serial.println("SD  init ok!");

    //SD Dateivorbereitung
    if (!file.open(newFilename, O_RDWR | O_CREAT)) {
        sd.errorHalt(F("open failed!!"));
    }

    Serial.print("Create logifle: ");
    Serial.print(newFilename);
    Serial.print(" ... ");
    file.println(F("Logged by rudikx6"));
    Serial.println("done.");



//+++++++++++++++++++++++++++  CAN  ++++++++++++++++++++++++++++++++++++++++++++++++++++
    //attachInterrupt(digitalPinToInterrupt(CAN_INT_PIN), CAN_ISR, FALLING); // start interrupt
    CAN.setMode(CAN_NORMAL_MODE);
    //CAN.setMode(CAN_LISTEN_ONLY_MODE);
    // init can bus : arbitration bitrate = 500k, data bitrate = 2M
    while (0 != CAN.begin(CAN_500K_2M)) {
        Serial.println("CAN init fail, retry...");
        delay(100);
    }
    Serial.println("CAN init ok!");
}



void loop() {
if (CAN_MSGAVAIL == CAN.checkReceive()) {

 //       unsigned long dauer = millis();

        CAN.readMsgBuf(&len, buf);            // You should call readMsgBuff before getCanId
        unsigned long id = CAN.getCanId();
        
        unsigned long now_ms = millis();        //ermittle zeitabstand der frames
        unsigned long dt_Frame = now_ms - vorher_ms;
        vorher_ms = now_ms;

        Serial.print(CAN.readRxTxStatus());            //Rx FIFO status
        /*  CAN_RX_FIFO_NO_EVENT = 0,
            CAN_RX_FIFO_ALL_EVENTS = 0x0F,
            CAN_RX_FIFO_NOT_EMPTY_EVENT = 0x01,
            CAN_RX_FIFO_HALF_FULL_EVENT = 0x02,
            CAN_RX_FIFO_FULL_EVENT = 0x04,
            CAN_RX_FIFO_OVERFLOW_EVENT = 0x08       */
        
//        Serial.print(dt_Frame);
        file.print(dt_Frame);
//        Serial.print("ms - id: ");
//        file.print("ms - id: ");
        file.print("\t");
//        Serial.print(id, HEX);
        file.print(id, HEX);
//        Serial.print("x - Data: ");
//      file.print("x - Data: ");
        file.print("\t");
//        file.write(buf, HEX);
        for (int i = 0; i < len; i++) {
//            Serial.print(buf[i], HEX); 
//            Serial.print(" ");
            file.print(buf[i], HEX);
            file.print(" ");
//            data [i] = (buf[i], HEX);
//            data.append(" ");
        }
//        Serial.println();
        file.println();
        Zeitscheibe_0  = millis();
        SaveDataTimerStatus = true;     //weil ein neuer Frame reinkam, aktieviere wieder den SaveDataTimerStatus
}
    if (millis() - Zeitscheibe_0 > 90 & SaveDataTimerStatus) {        // Zeitscheibe_0 zur Datensicheurng wenn seit 90ms kein daten mehr gekommen sind
        Zeitscheibe_0  = millis();
        file.flush();
        Serial.println("flush");      //("flush SaveDataTimerStatus");
        SaveDataTimerStatus = false;    //deaktiviere den SaveDataTimerStatus damit nicht unnötig flush() ausgeführt wird
    }
}


#else  // SPI_DRIVER_SELECT
#error SPI_DRIVER_SELECT must be two in SdFat/SdFatConfig.h
#endif  // SPI_DRIVER_SELECT


// END FILE

Hier auch der Teil der Ausgabe bis es schief geht :

RTC init ok! -
SD init ok!
Create logifle: 23_53_33.txt ... done.
CAN init ok!
flush
00000flush
00flush
00000flush
00flush
000000000flush
00000flush
0000000000000000flush
0000000flush
0000flush
0000000000110flush
0000000flush
0000000flush
00000flush
00000000flush
001110flush
0flush
01115111111111111111111111199999998flush
9998flush
8flush
811151111111511111111111111111199999998flush
811151111111111111111111111111199999998flush
8flush
9111511111111111111111111111111111199999998flush
915111111111111111111111111111111119999999888flush
811111115111111111111111111111111999999988flush
811151511111111111511111111111111111111999999998888flush
88888flush
888888898888988888888888flush
889999999999999988888999998998888899998888899988889999888flush
888888888flush
99999999999999999999899988888888889899988888998889989989999999988898999988889999998flush
888888898888988898888888888899888988988898898888999998898888flush
8899988998flush

und die entsprechende Logdatei die dabei erstellt wurde.
(habe die ersten fehlenden Stellen gekennzeichnet)
23_53_33.txt (91.9 KB)

Vielleicht hat jemand hier ja schon Erfahrung damit gemacht :slight_smile:

Wo?

Gruß Tommy

hatte versehentlich STG + ENTER gedrückt und den Post losgeschickt obwohl nicht fertig :sweat_smile:

habe mir mittlerweile auch den RX FIFO Status ausgeben lassen und man sieht das nach einer bestimmten zeit es wohl Overflows gibt...

Ich sehe immer noch keinen vollständigen Code.
Übrigens eine Textausgabe als Bild einzubinden ist der denkbar schlechteste Weg.
Setze Code (vollständig und kompilierbar) und Ausgaben als Text in Codetags hier ein.
Wie das geht, steht hier.

Gruß Tommy

o.k. Danke für den Hinweis,
habe den ersten Post jetzt um alles ergänzt.

Ich hoffe, dass dir klar ist, dass die SD Karte durchaus mal 100 oder 200ms mit inneren Aktivitäten beschäftigt ist.
Das blockiert dein Vorhaben.

Vielleicht solltest du doch den Interruptbetrieb reparieren....

Hmmm.... das hatte ich auch schon im Hinterkofp, aber das ganze mit dem schrieben und dem flush() noch nicht ganz durchdrungen.

Ich schau mal wie sich der RX_FIFO des CAN Controllers Verhält wenn ich die Daten nicht parallel auf die SD schreibe.

Danke schonmal für diesen Tipp :slight_smile:

Wenn Du persistent speichern willst, wäre in FRAM evtl. eine schnellere Lösung.

Gruß Tommy

Wie viele Daten werden es denn?
Dieser FRAM-Chip hat 512 kB

Noch eine Variante wäre evtl. PulseView

https://sigrok.org/wiki/Downloads

Hi zusammen,

ich brauche die Daten auf einer SD gesichert. Der FRAM würde dann also als zwischen Speicher infrage kommen. Müsste dann am ende der Messung die Daten aus dem FRAM auf die SD schreiben. Es können bis zu 5mb anfallen.

Aber nochmal zum grundlegenden Problem...
Ich habe eben das schreibend er Daten auf die SD deaktiviert um zu sehen wie der RX FIFO Status sich dann verhält.

Überraschende weise habe ich weiterhin Overflows :face_with_raised_eyebrow:

Habe es dann auch mal wider mit der Interruptvariante versucht. Aber leider scheint der Interrupt nach einiger Zeit nicht mehr ausgeführt zu werden...

Ich glaube da hängt noch etwas anderes :confused:

Schaue mir gerade mal eine andere LIB an, dort ist auch eine sehr ausführliche Dokumentation verfügbar.

LIB

Hmmm,,,,,,
Vielleicht solltest du doch den Interruptbetrieb reparieren....
Leider kann ich nicht testen, keine passende Hardware.
Sehe bei dir auch keine Interrupts, also auch nicht was da falsch läuft.

Den Code mit aktivem ISR hatte ich bisslang noch nicht gepostet.

void CAN_ISR(){...

Aktiviert wird er mittels folgendem Befehl im CAN Setup.

attachInterrupt(digitalPinToInterrupt(CAN_INT_PIN), CAN_ISR, FALLING);

Hier ist er:

/*  MCP2517/8 receive a CAN-FD frame with interrupt
    can-fd baud rate:
    CAN_125K_500K
    CAN_250K_500K
    CAN_250K_750K
    CAN_250K_1M
    CAN_250K_1M5
    CAN_250K_2M
    CAN_250K_3M
    CAN_250K_4M
    CAN_500K_1M
    CAN_500K_2M
    CAN_500K_3M
    CAN_500K_4M
    CAN_1000K_4M


    v2 - einbau SD karte über die selbe SPI schnitstelle
    v3 - nutzung Software SPI mit SDfat lib
    v4 - import RTC modul & Datumsformatierte Dateinbenamung
    v5 - zu schriebende daten aus dem buffer auch ohne Close schrieben "flush()" 
        + 5sec timer zum wegschreiben
        + einbau delta t der einzelnen frames zueinander
    v6 - ausgabe anpassung für großtest
        + wiederholte flush mit SaveDataTimerStatus jetzt vehindert
    V7 - anpassung ausgab, beim flush()
        + RTC steup bei Compilevorgang, schaltbar!
    v8 - performancetests bzgl. frames <1ms
    v9 - performanstests flush nur nach 90ms ohne frame- so sollte der FIFO des MCP frei sein
    v9_1 - cleaned for forum
    v10 - umbau auf ISR
        +auswertung des RX FIFO
        +nutzung von tab formatierung
    v11 - performance versuch ohne SD schreiben
    v11_1 - als ISR 
        
         
*/

#include <Arduino.h>
#include <SPI.h>
#include "mcp2518fd_can.h"

#include <ThreeWire.h>  
#include <RtcDS1302.h>
ThreeWire myWire(7,5,8); // IO, SCLK, CE
RtcDS1302<ThreeWire> Rtc(myWire);

#include <SdFat.h>
#if SPI_DRIVER_SELECT == 2
#define SD_FAT_TYPE 1

#define MAX_DATA_SIZE 64

// pin for CAN-FD Shield
const int SPI_CS_PIN = 9;
const int CAN_INT_PIN = 2;

//anpassung für SD Karte
int count = 0 ;
bool SaveDataTimerStatus = true;
static unsigned long  Zeitscheibe_0 = 0;
unsigned long vorher_ms = 0;
// Chip select may be constant or RAM variable. (Software SPI aus SDfat LIB)
const uint8_t SD_CS_PIN = 10;
const uint8_t SOFT_MISO_PIN = 6;
const uint8_t SOFT_MOSI_PIN = 3;
const uint8_t SOFT_SCK_PIN = 4;
#if SD_FAT_TYPE == 0
SdFat sd;
File file;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
#else  // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif  // SD_FAT_TYPE

// SdFat software SPI template
SoftSpiDriver<SOFT_MISO_PIN, SOFT_MOSI_PIN, SOFT_SCK_PIN> softSpi;
// Speed argument is ignored for software SPI.
#if ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(25), &softSpi)
#else  // ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(0), &softSpi)
#endif  // ENABLE_DEDICATED_SPI


mcp2518fd CAN(SPI_CS_PIN); // Set CS pin

unsigned char flagRecv = 0;
unsigned char len = 0;
unsigned char buf[MAX_DATA_SIZE];


void CAN_ISR(){             //Interrupt

 //       unsigned long dauer = millis();

        CAN.readMsgBuf(&len, buf);            // You should call readMsgBuff before getCanId
        unsigned long id = CAN.getCanId();
        
        unsigned long now_ms = millis();        //ermittle zeitabstand der frames
    //    unsigned long dt_Frame = now_ms - vorher_ms;
        vorher_ms = now_ms;

        Serial.print(CAN.readRxTxStatus());            //Rx FIFO status
        /*  CAN_RX_FIFO_NO_EVENT = 0,
            CAN_RX_FIFO_ALL_EVENTS = 0x0F,
            CAN_RX_FIFO_NOT_EMPTY_EVENT = 0x01,
            CAN_RX_FIFO_HALF_FULL_EVENT = 0x02,
            CAN_RX_FIFO_FULL_EVENT = 0x04,
            CAN_RX_FIFO_OVERFLOW_EVENT = 0x08       */
        
//        Serial.print(dt_Frame);
    //    file.print(dt_Frame);
//        Serial.print("ms - id: ");
//        file.print("ms - id: ");
     //   file.print("\t");
//        Serial.print(id, HEX);
     //   file.print(id, HEX);
//        Serial.print("x - Data: ");
//      file.print("x - Data: ");
     //   file.print("\t");
//        file.write(buf, HEX);
    //    for (int i = 0; i < len; i++) {
//            Serial.print(buf[i], HEX); 
//            Serial.print(" ");
     //       file.print(buf[i], HEX);
     //       file.print(" ");
//            data [i] = (buf[i], HEX);
//            data.append(" ");
     //   }
//        Serial.println();
     //   file.println();
        Zeitscheibe_0  = millis();
        SaveDataTimerStatus = true;     //weil ein neuer Frame reinkam, aktieviere wieder den SaveDataTimerStatus
}


void setup() {

    delay(4000);            //kurze wartezeit um nach dem hochladen das Terminal verbinden zu können

    Serial.begin(115200);
    while (!Serial);


//+++++++++++++++++++++++++++  RTC  ++++++++++++++++++++++++++++++++++++++++++++++++++++
    Rtc.Begin();
    //setzen der RTC über compiler (einmal auf true gesetzt hochladen)
    if(false){
        Serial.print("compiled: ");
        Serial.print(__DATE__);
        Serial.println(__TIME__);
        RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
        //printDateTime(compiled);
        Serial.println();
        Serial.println("setze neue Zeit aus Compilevorgang");
        Rtc.SetDateTime(compiled);
    }

    RtcDateTime now = Rtc.GetDateTime();
    if (!now.IsValid()){
        // Common Causes:
        //    1) the battery on the device is low or even missing and the power line was disconnected
        Serial.println("RTC lost confidence in the DateTime!");
    }else{
        Serial.println("RTC init ok!  -  ");
    }

//+++++++++++++++++++++++++++  SD  ++++++++++++++++++++++++++++++++++++++++++++++++++++
    //timestamp als Dateiname erstellen
    String timestamp = (String(now.Hour())+"_"+String(now.Minute())+"_"+String(now.Second())+".txt");
    vorher_ms = millis();
    char newFilename[20];
    timestamp.toCharArray(newFilename, 20);

    // SD Karte initialisierung
    if (!sd.begin(SD_CONFIG)) {
        sd.initErrorHalt();
    }
    Serial.println("SD  init ok!");

    //SD Dateivorbereitung
    if (!file.open(newFilename, O_RDWR | O_CREAT)) {
        sd.errorHalt(F("open failed!!"));
    }

    Serial.print("Create logifle: ");
    Serial.print(newFilename);
    Serial.print(" ... ");
    file.println(F("Logged by rudikx6"));
    Serial.println("done.");



//+++++++++++++++++++++++++++  CAN  ++++++++++++++++++++++++++++++++++++++++++++++++++++
    attachInterrupt(digitalPinToInterrupt(CAN_INT_PIN), CAN_ISR, FALLING); // start interrupt
    CAN.setMode(CAN_NORMAL_MODE);
    //CAN.setMode(CAN_LISTEN_ONLY_MODE);
    // init can bus : arbitration bitrate = 500k, data bitrate = 2M
    while (0 != CAN.begin(CAN_500K_2M)) {
        Serial.println("CAN init fail, retry...");
        delay(100);
    }
    Serial.println("CAN init ok!");
}



void loop() {
//if (CAN_MSGAVAIL == CAN.checkReceive()) {
        //einfacher loop beriech
//}
    if (millis() - Zeitscheibe_0 > 90 & SaveDataTimerStatus) {        // Zeitscheibe_0 zur Datensicheurng wenn seit 90ms kein daten mehr gekommen sind
        Zeitscheibe_0  = millis();
     //   file.flush();
        Serial.println("flush");      //("flush SaveDataTimerStatus");
        SaveDataTimerStatus = false;    //deaktiviere den SaveDataTimerStatus damit nicht unnötig flush() ausgeführt wird
    }
}


#else  // SPI_DRIVER_SELECT
#error SPI_DRIVER_SELECT must be two in SdFat/SdFatConfig.h
#endif  // SPI_DRIVER_SELECT


// END FILE

Welcher?

Wenn AVR, dann: (für andere µC gilt meist ähnliches)
Serial in ISR ist ein NoGo
Mehrbyte Values müssen ATOMIC gelesen werden.
Für lesen von Daten, welche von der ISR geschrieben werden bedarf es einer "Memory Barrier"
Dann solltest du wohl einen RingBuffer anlegen, damit es dir nicht die Daten überschreibt, bevor du sie verarbeitet hast.

scheint eine HIGH-speed-Aufgabenstellung zu sein. Da würde ich ernsthaft überlegen auf einen schnelleren Prozessor mit viel Speicher umzusteigen.
Der Teensy 4.1 hat den microSD-slot schon auf der Platine
und die Möglichkeit QSPI-chips aufzulöten
https://www.pjrc.com/store/teensy41.html

https://www.pjrc.com/store/psram.html

Wenn der besondere Spaß im ausreizen eines Arduino
(Welcher Arduino is es denn? ein Uno?)
besteht dann nur zu.

Ansonsten .....

Ich halte den Arduino Uno + SD für eine schlechte Kombination.

Die Blockgröße von SD ist 512 Bytes, das sind 1/4 des RAMs des Unos. Da ist dann nicht viel mit Caching.

D.h. ein Schreibzugriff dürfte eine Vielzahl an Zugriffen auf die SD zur Folge haben:

  • Freien Block finden und allokieren
  • Daten schreiben
  • Verzeichniseintrag aktualisieren

Daher sollte man einzelne File.print() vermeiden und die formatierten Daten in einem Buffer sammeln, den man dann in einem Stück zur SD schicken kann.

Während die SD schreibt kommen per CAN weiter Daten an, die nicht verloren gehen sollen. Also brauchts noch einen Buffer.

Ohne Task-scheduler stellt sich dann noch die Frage: Wie empfange ich die CAN-Frames wenn die SD beschäftigt ist?

Am Ende eine sehr interessante Optimierungsaufgabe...

Eventuell gehts mit einem ESP32:

  • Task 1: CAN-Frames empfangen und in einen Buffer schreiben
  • Task 2: Daten aus Buffer lesen, formatieren und auf SD schreiben

Danke euch für eure Kommentare und Gedanken.
Das bringt mich immer näher zum Ziel :slight_smile:

Aktuell versuche ich es mit dem Arduino UNO. Die Serielle Ausgabe im ISR werde ich auch entfernen.
Wie schon in meinem Titel und euren Hinweisen sehe ich den UNO hier gerade auch als limitiert.

Hatte ehrlichgesagt nicht vor etwas zu schaffen was von der Leistung her eigentlich zu schwach wäre.

Gerade das Thema Blockgröße hat mich da "Erleuchtet", gelesen hatte ich dazu bereits etwas, aber nicht ganz verstanden. Beim Kompilieren bekommt man ja immer einen Einblick zur Nutzung der Speicher.... da ist der RAM schon recht voll.

RAM: [======== ] 82.0% (used 1680 bytes from 2048 bytes)
Flash: [======= ] 73.1% (used 23584 bytes from 32256 bytes)

ATOMIC lesen, eine Memory Barrier und RingBuffer klingen für mich nach mehr als Hobbyprogrammiererkenntnissen. :sweat_smile:
Teilweise kann ich mir darunter etwas vorstellen aber wie man das in einem Arduino umsetzt werde ich mir mal anschauen.

Eine Lösung über mehrere Tasks scheint mir angebracht, da kommt der Arduino aber nicht mehr infrage würde ich sagen.

Einen Teensy hatte ich sogar zu beginn des Projekts im Blick, weil es aber später mehrere Geräte werden sollen, habe ich auf den Preis geschaut.

Der ESP32 scheint mir mit seinen Separaten SD Bus und den damit noch freibleibendem SPI interessant.

Meint ihr es müsste mit einem ESP32 weiterhin in C Programmiert werden oder wäre µPython auch ein Option?

Ich hab grad mal auf den Code geschaut.
Warum:

????

Der UNO hat einen Hardware SPI - der dürfte eindeutig besser geeignet sein.
Die ISR zu bereinigen ist ein guter Ansatz.

Was mich interessiert, gibt es irgendwann eine Pause während des Streams?
Sprich: Hast Du mal mit einem Kurzcode versucht heraus zu bekommen, wieviel Zeit zwischen den einzelnen Datenpaketen vergeht?

Einige ESP32 varianten haben einen eingebauten CAN Controller. Da brauchst du nur den passenden Transceiver.

Ich habe die gemeinsame Nutzung des SPI für SD und CAN Controller nicht hinbekommen gehabt. Wenn ich richtig verstanden habe, nutzen die Geräte unterschiedliche SPI Mode. Müsste also immer umschalten im Code.

Die eintreffenden frames haben auch Pausen drin. Ich habe professionelles CAN Equipment von Vector. Damit spiele ich aufgezeichnete Traces ab und kann somit auch die Frameabstände einsehen. Es gibt Abstände von mehreren Sekunden als auch von <1ms

Denkst du die längeren Pausen könnten Probleme machen?

Der im ESP integrierte can Controller ist nicht CAN FD fähig. nur üblicher can 2.0.

Ich brauche CANFD, müsste also extern den mcp2518fd über SPI anbinden.