RAM Problem?

Hi,
in meinem derzeitigen Projekt verwende ich 2 Arduino Nano`s, die über eine Serielle verbindung miteinender Kommunizieren. Beim ersten Nano über die Hardwareserial, beim zweiten Nano über ein Softwareserial (Siehe Bild). Um trotzdem die Möglichkeit eines Interrupts zu haben, wird eine 3. Leitung vom 1. Nano (Pin A5) zum 2. Nano (Pin 3) geführt, die vor dem Übertragen auf LOW gezogen wird.

Der 2. Nano erhält seine Daten (in Form eines struct) über die Hardwareserial. Diese werden gemeinsam mit anderen Daten in ein Struct geschrieben, welches dann auf Anfrage des 1. Nano`s über das Softwareserial übertragen werden.

Die Anfrage des 1. Nano an den 2. Nano erfolgt über das Senden einer Zahl (0-5). Am 2. wird dann die Anfrage über eine switch statement abgearbeitet.

Mein Problem: Das ganze läuft nur 2x. Beim 3. Mal kann der empfangene char nicht mehr korrekt abgespeichert werden.

Kann es also sein, dass ich zuviel RAM benötige? Gibt es Verbesserungsvorschläge für den untenstehenden Code?

Code (switch statement gekürzt, steht überall das gleiche nur mit anderen structs):

enum dataNeeded {
  RTData,
  vescOptData,
  gpsRTData,
  btData,
  fsrData,
  batData
};

SoftwareSerial softSerial(4, 5);
void serialISR();
uint8_t recRequest;



void setup() {
  
  Serial.begin(9600);
  softSerial.begin(19200);

  //Interrupt on change@Pin D3
  attachInterrupt(digitalPinToInterrupt(3), serialISR, CHANGE);
  
}

// the loop function runs over and over again until power down or reset
void loop() {
  //softSerial.print(charToSend);
}

void serialISR() {
  Serial.println(F("in ISR"));
  
  if (softSerial.available() > 1) {
    recRequest = Serial.read();
  }
  requestHandler((char)recRequest);
} 

void requestHandler(char receivedNumber) {
  Serial.println(F("In requestHandler")); //Serial.println(receivedNumber);
  
  switch (receivedNumber) {             //Select which data is requested and copy the requested data into char Array and pass it to send function
  case RTData:
    char rtDat[sizeof(RtData) + 1];
    memcpy(&rtDat, &RtData, sizeof(DataRT));
    sendCharArray(rtDat);
    break;
  
default:
    Serial.println(F("reqHandler failure!"));
    break;
  }
}


void sendCharArray(char arrayToSend[]) {
  for (int i = 0; i < sizeof(arrayToSend); i++) {
    softSerial.print(arrayToSend[i]);
  }
  Serial.println("CharArray Sent");
  delete(arrayToSend);
}

In einer ISR sollte man nicht seriell benutzen

if (softSerial.available() > 1) {

Spricht erst beim zweiten Zeichen an

Korrekt:
if (softSerial.available()) {

Der einzige Grund für den Interrupt ist das Empfangen der Daten über die Serielle Schnittstelle zum anderen Arduino Nano.

Leider gibt es serialEvent() nur für die Hardware Serial...

Ich hab noch nie serialEvent gebraucht.

Mach das ganze ohne ISR, nur im loop.

Befürchte nur, dass das bei mir nicht Möglich ist, da da bereits andere Daten abgefragt werden (Hab an dem Nano noch ein GPS und einen ADC über I²C hängen). Sollte dann, während gerade andere Daten abgefragt werden, die Anfrage vom 1. Nano kommen, kann ich die nicht bearbeiten. Deshalb der Interrupt.

ElEspanol:
if (softSerial.available() > 1) {

Spricht erst beim zweiten Zeichen an

Korrekt:
if (softSerial.available()) {

Danke, hab ich ausgebessert :slight_smile:

noiasca:
wenn es wirklich am RAM liegen sollte

Serial.println("CharArray Sent");

ins Flash damit und alle anderen im unsichtbaren Code auch.

Öha, da hab ich wohl eines Übersehen. Sind alle bereits im Flash, das dürfte ich übersehen habe.

Ich vermute, dass es am RAM liegt. Es funktioniert ja 2x ohne Probleme. Beim dritten Mal scheitert es dann bereits am empfangen der Anfrage...

Wie lange braucht den deine loop?

Was sagt denn der Kompiler zu Flash/RAM?

Was du da alles in der ISR hast, ich weiß nicht .....

ElEspanol:
Wie lange braucht den deine loop?

Was sagt denn der Kompiler zu Flash/RAM?

Was du da alles in der ISR hast, ich weiß nicht .....

Steht noch nicht fest, die Programmteile werden gerade paralell dazu entwickelt.

//Compiling 'SoftSerialInterrupt' for 'Arduino Nano w/ ATmega328P (Old Bootloader)'
//Program size: 4,428 bytes (used 14% of a 30,720 byte maximum) (6.42 secs)
//Minimum Memory Usage: 446 bytes (22% of a 2048 byte maximum)

Also bei 78% freies RAM glaube ich, dass das Problem woanders sitzt.

Wie lange braucht deine aktuelle loop, die mit den Problemen?

Es funktioniert ja 2x ohne Probleme. Beim dritten Mal scheitert es dann

Daas liegt nicht am RAM, sondern an deiner Vorstellung von ISR.

Interrupts dienen nicht zum Parallel Ausführen verschiedener Tasks, sondern um sehr hardwarenah mit wenigen Maschinenbefehlen auf Ereignisse zu reagieren. Als kleine Software-Erweiterung zu Timern und anderen Hardware-Komponenten.

Serial.print in einer ISR "funktioniert" für 64 Buchstaben. Es funktioniert also nicht!

Deine Beschreibung ist sehr lückenhaft Da Du nur einen Teilaspekt Deines Projekts beleuchtest. Der Fehler kann überall liegen.

  1. soweit ich mich erinnere kann die software serial nicht >9600

Um trotzdem die Möglichkeit eines Interrupts zu haben, wird eine 3. Leitung vom 1. Nano (Pin A5) zum 2. Nano (Pin 3) geführt, die vor dem Übertragen auf LOW gezogen wird.

  1. A4 wird von der I2C benutzt
  2. Serial in der Interruptroutine ght nicht

Gib uns mehr Infos zB alles Sketchs.

Grüße Uwe

Die serielle Schnittstelle ist sehr langsam. Bei deinen Baudraten im Bereich von hunderten 100µs bis 1ms. Ein Zeichen braucht 1 / Baudrate * 10 Sekunden. Da braucht man keine Interrupts wenn loop() vernünftig programmiert ist und nicht blockiert. Außerdem haben die Serial Klassen intern einen Puffer den man nur schnell genug leeren muss.

Serenifly:
Da braucht man keine Interrupts wenn loop() vernünftig programmiert ist und nicht blockiert.

Meine Rede

Da braucht man keine Interrupts wenn loop() vernünftig programmiert ist und nicht blockiert

Schlecht formuliert, Serenifly ;):
Wenn "loop() unvernünftig programmiert ist und blockiert", hift auch keine Interrupt-Routine dagegen

Hi

Da im gezeigten Sketch loop() aber leer ist, wird's wohl nicht daran liegen ... oder eben im magischem, aber unbekanntem Code.

MfG

postmaster-ino:
Da im gezeigten Sketch loop() aber leer ist, wird's wohl nicht daran liegen

Es geht darum das loop() schnell ist und man keine seriellen Sachen in einer ISR macht

Danke an alle für eure Hilfe :slight_smile:

Leider funktioniert das mit empfangen der Anfrage nicht (auch nicht mit einem if(Serial.available()) in der main loop). Habe es gelöst indem der Nano 2 einfach in 500ms Abständen selbstständig schickt und der Nano 1 diese in der serialEvent() Funktion bearbeitet (sprich in ein char[] aufnimmt und dann mit memcpy() in das struct schreibt).

Wird sicher nicht das letzte Problem an diesem Projekt sein, werdet ziemlich sicher noch ein paar Themen von mir in diesem Forum sehen :wink:

Dann schau Dir mal union an. Da kann das char[] und das Struct den gleichen Speicher gemeinsam nutzen und Du musst nichts umkopieren und kannst direkt zugreifen.

Gruß Tommy

Tommy56:
Dann schau Dir mal union an. Da kann das char[] und das Struct den gleichen Speicher gemeinsam nutzen und Du musst nichts umkopieren und kannst direkt zugreifen.

Gruß Tommy

Mal schauen. Da ich die Daten als struct bekomme (library), müsste ich die dann nur einmal umkopieren. Schau ich mir morgen mal genauer an! :wink:

Tommy56:
Dann schau Dir mal union an. Da kann das char[] und das Struct den gleichen Speicher gemeinsam nutzen und Du musst nichts umkopieren und kannst direkt zugreifen.

Gruß Tommy

Hab mir das mal angesehen. Möglich ist das schon. Erlaubt ist es allerdings weder in C noch in C++, daher für mich leider nicht geeignet.

Aber danke trotzdem für den Hinweis! :slight_smile: